Skip to content

Commit ca17ee3

Browse files
chrisbobbegnprice
authored andcommitted
recent_senders: Treat topics case-insensitively
1 parent c1b3734 commit ca17ee3

File tree

2 files changed

+38
-5
lines changed

2 files changed

+38
-5
lines changed

lib/model/recent_senders.dart

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import 'package:flutter/foundation.dart';
44
import '../api/model/events.dart';
55
import '../api/model/model.dart';
66
import 'algorithms.dart';
7+
import 'channel.dart';
78

89
/// Tracks the latest messages sent by each user, in each stream and topic.
910
///
@@ -16,7 +17,7 @@ class RecentSenders {
1617

1718
// topicSenders[streamId][topic][senderId] = MessageIdTracker
1819
@visibleForTesting
19-
final Map<int, Map<TopicName, Map<int, MessageIdTracker>>> topicSenders = {};
20+
final Map<int, TopicKeyedMap<Map<int, MessageIdTracker>>> topicSenders = {};
2021

2122
/// The latest message the given user sent to the given stream,
2223
/// or null if no such message is known.
@@ -27,6 +28,8 @@ class RecentSenders {
2728

2829
/// The latest message the given user sent to the given topic,
2930
/// or null if no such message is known.
31+
///
32+
/// Topics are treated case-insensitively; see [TopicName.isSameAs].
3033
int? latestMessageIdOfSenderInTopic({
3134
required int streamId,
3235
required TopicName topic,
@@ -53,7 +56,7 @@ class RecentSenders {
5356
}
5457
for (final entry in messagesByUserInTopic.entries) {
5558
final (streamId, topic, senderId) = entry.key;
56-
(((topicSenders[streamId] ??= {})[topic] ??= {})
59+
(((topicSenders[streamId] ??= makeTopicKeyedMap())[topic] ??= {})
5760
[senderId] ??= MessageIdTracker()).addAll(entry.value);
5861
}
5962
}
@@ -64,7 +67,7 @@ class RecentSenders {
6467
final StreamMessage(:streamId, :topic, :senderId, id: int messageId) = message;
6568
((streamSenders[streamId] ??= {})
6669
[senderId] ??= MessageIdTracker()).add(messageId);
67-
(((topicSenders[streamId] ??= {})[topic] ??= {})
70+
(((topicSenders[streamId] ??= makeTopicKeyedMap())[topic] ??= {})
6871
[senderId] ??= MessageIdTracker()).add(messageId);
6972
}
7073

test/model/recent_senders_test.dart

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,16 @@
11
import 'package:checks/checks.dart';
2+
import 'package:collection/collection.dart';
23
import 'package:flutter_test/flutter_test.dart';
4+
import 'package:zulip/api/model/events.dart';
35
import 'package:zulip/api/model/model.dart';
6+
import 'package:zulip/model/channel.dart';
47
import 'package:zulip/model/recent_senders.dart';
58
import '../example_data.dart' as eg;
69

710
/// [messages] should be sorted by [id] ascending.
811
void checkMatchesMessages(RecentSenders model, List<Message> messages) {
912
final Map<int, Map<int, Set<int>>> messagesByUserInStream = {};
10-
final Map<int, Map<TopicName, Map<int, Set<int>>>> messagesByUserInTopic = {};
13+
final Map<int, TopicKeyedMap<Map<int, Set<int>>>> messagesByUserInTopic = {};
1114
for (final message in messages) {
1215
if (message is! StreamMessage) {
1316
throw UnsupportedError('Message of type ${message.runtimeType} is not expected.');
@@ -17,7 +20,7 @@ void checkMatchesMessages(RecentSenders model, List<Message> messages) {
1720

1821
((messagesByUserInStream[streamId] ??= {})
1922
[senderId] ??= {}).add(messageId);
20-
(((messagesByUserInTopic[streamId] ??= {})[topic] ??= {})
23+
(((messagesByUserInTopic[streamId] ??= makeTopicKeyedMap())[topic] ??= {})
2124
[senderId] ??= {}).add(messageId);
2225
}
2326

@@ -125,6 +128,16 @@ void main() {
125128
[eg.streamMessage(stream: streamA, topic: 'other', sender: userX)]);
126129
});
127130

131+
test('case-insensitive topics', () {
132+
checkHandleMessages(
133+
[eg.streamMessage(stream: streamA, topic: 'thing', sender: userX)],
134+
[eg.streamMessage(stream: streamA, topic: 'ThInG', sender: userX)]);
135+
check(model.topicSenders).values.single.deepEquals(
136+
{eg.t('thing'):
137+
{userX.userId: (Subject<Object?> it) =>
138+
it.isA<MessageIdTracker>().ids.length.equals(2)}});
139+
});
140+
128141
test('add new stream', () {
129142
checkHandleMessages(
130143
[eg.streamMessage(stream: streamA, topic: 'thing', sender: userX)],
@@ -161,6 +174,16 @@ void main() {
161174
Map.fromEntries(messages.map((msg) => MapEntry(msg.id, msg))));
162175

163176
checkMatchesMessages(model, [messages[1]]);
177+
178+
// check case-insensitivity
179+
model.handleDeleteMessageEvent(DeleteMessageEvent(
180+
id: 0,
181+
messageIds: [messages[1].id],
182+
messageType: MessageType.stream,
183+
streamId: stream.streamId,
184+
topic: eg.t('oThEr'),
185+
), {messages[1].id: messages[1]});
186+
checkMatchesMessages(model, []);
164187
});
165188

166189
test('RecentSenders.latestMessageIdOfSenderInStream', () {
@@ -200,6 +223,9 @@ void main() {
200223

201224
check(model.latestMessageIdOfSenderInTopic(streamId: 1,
202225
topic: eg.t('a'), senderId: 10)).equals(300);
226+
// case-insensitivity
227+
check(model.latestMessageIdOfSenderInTopic(streamId: 1,
228+
topic: eg.t('A'), senderId: 10)).equals(300);
203229
// No message of user 20 in topic "a".
204230
check(model.latestMessageIdOfSenderInTopic(streamId: 1,
205231
topic: eg.t('a'), senderId: 20)).equals(null);
@@ -211,3 +237,7 @@ void main() {
211237
topic: eg.t('a'), senderId: 10)).equals(null);
212238
});
213239
}
240+
241+
extension MessageIdTrackerChecks on Subject<MessageIdTracker> {
242+
Subject<QueueList<int>> get ids => has((x) => x.ids, 'ids');
243+
}

0 commit comments

Comments
 (0)