Skip to content

Commit 66efd39

Browse files
committed
internal_link: Recognize channel operator in narrow links
Fixes: #632
1 parent 316cc1a commit 66efd39

File tree

3 files changed

+95
-17
lines changed

3 files changed

+95
-17
lines changed

lib/model/internal_link.dart

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,7 @@ Narrow? _interpretNarrowSegments(List<String> segments, PerAccountStore store) {
159159
final operand = segments[i + 1];
160160
switch (operator) {
161161
case _NarrowOperator.stream:
162+
case _NarrowOperator.channel:
162163
if (streamElement != null) return null;
163164
final streamId = _parseStreamOperand(operand, store);
164165
if (streamId == null) return null;
@@ -207,6 +208,7 @@ enum _NarrowOperator {
207208
near,
208209
pmWith,
209210
stream,
211+
channel,
210212
subject,
211213
topic,
212214
unknown;

lib/model/internal_link.g.dart

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

test/model/internal_link_test.dart

Lines changed: 92 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -131,13 +131,16 @@ void main() {
131131
final bool expected = testCase.$1;
132132
final String description = testCase.$2;
133133
final String urlString = testCase.$3;
134+
final String urlWithChannelSyntax = urlString.replaceFirst('#narrow/stream/', '#narrow/channel/');
134135
final Uri realmUrl = testCase.$4;
135-
test('${expected ? 'accepts': 'rejects'} $description: $urlString', () {
136-
final store = setupStore(realmUrl: realmUrl, streams: streams);
137-
final url = store.tryResolveUrl(urlString)!;
138-
final result = parseInternalLink(url, store);
139-
check(result != null).equals(expected);
140-
});
136+
for (var urlString in [urlString, urlWithChannelSyntax]) {
137+
test('${expected ? 'accepts': 'rejects'} $description: $urlString', () {
138+
final store = setupStore(realmUrl: realmUrl, streams: streams);
139+
final url = store.tryResolveUrl(urlString)!;
140+
final result = parseInternalLink(url, store);
141+
check(result != null).equals(expected);
142+
});
143+
}
141144
}
142145
});
143146

@@ -158,6 +161,15 @@ void main() {
158161
testExpectedNarrows(testCases, streams: streams);
159162
});
160163

164+
group('"/#narrow/channel/<...>" returns expected StreamNarrow', () {
165+
const testCases = [
166+
('/#narrow/channel/check', StreamNarrow(1)),
167+
('/#narrow/channel/stream/', StreamNarrow(5)),
168+
('/#narrow/channel/topic/', StreamNarrow(123)),
169+
];
170+
testExpectedNarrows(testCases, streams: streams);
171+
});
172+
161173
group('"/#narrow/stream/<...>/topic/<...>" returns expected TopicNarrow', () {
162174
const testCases = [
163175
('/#narrow/stream/check/topic/test', TopicNarrow(1, 'test')),
@@ -170,6 +182,18 @@ void main() {
170182
testExpectedNarrows(testCases, streams: streams);
171183
});
172184

185+
group('"/#narrow/channel/<...>/topic/<...>" returns expected TopicNarrow', () {
186+
const testCases = [
187+
('/#narrow/channel/check/topic/test', TopicNarrow(1, 'test')),
188+
('/#narrow/channel/mobile/subject/topic/near/378333', TopicNarrow(3, 'topic')),
189+
('/#narrow/channel/mobile/topic/topic/', TopicNarrow(3, 'topic')),
190+
('/#narrow/channel/stream/topic/topic/near/1', TopicNarrow(5, 'topic')),
191+
('/#narrow/channel/stream/subject/topic/near/1', TopicNarrow(5, 'topic')),
192+
('/#narrow/channel/stream/subject/topic', TopicNarrow(5, 'topic')),
193+
];
194+
testExpectedNarrows(testCases, streams: streams);
195+
});
196+
173197
group('"/#narrow/dm/<...>" returns expected DmNarrow', () {
174198
final expectedNarrow = DmNarrow.withUsers([1, 2],
175199
selfUserId: eg.selfUser.userId);
@@ -196,6 +220,8 @@ void main() {
196220
final testCases = [
197221
('/#narrow/stream/name/topic/', null), // missing operand
198222
('/#narrow/stream/name/unknown/operand/', null), // unknown operator
223+
('/#narrow/channel/name/topic/', null), // missing operand
224+
('/#narrow/channel/name/unknown/operand/', null), // unknown operator
199225
];
200226
testExpectedNarrows(testCases, streams: streams);
201227
});
@@ -247,6 +273,23 @@ void main() {
247273
];
248274
testExpectedNarrows(testCases, streams: streams);
249275
});
276+
277+
group('parses correctly in channel and topic operands', () {
278+
final streams = [
279+
eg.stream(streamId: 1, name: 'some_stream'),
280+
eg.stream(streamId: 2, name: 'some stream'),
281+
eg.stream(streamId: 3, name: 'some.stream'),
282+
];
283+
const testCases = [
284+
('/#narrow/channel/some_stream', StreamNarrow(1)),
285+
('/#narrow/channel/some.20stream', StreamNarrow(2)),
286+
('/#narrow/channel/some.2Estream', StreamNarrow(3)),
287+
('/#narrow/channel/some_stream/topic/some_topic', TopicNarrow(1, 'some_topic')),
288+
('/#narrow/channel/some_stream/topic/some.20topic', TopicNarrow(1, 'some topic')),
289+
('/#narrow/channel/some_stream/topic/some.2Etopic', TopicNarrow(1, 'some.topic')),
290+
];
291+
testExpectedNarrows(testCases, streams: streams);
292+
});
250293
});
251294

252295
group('parseInternalLink edge cases', () {
@@ -259,21 +302,28 @@ void main() {
259302

260303
group('basic', () {
261304
testExpectedStreamNarrow('#narrow/stream/1-general', 1);
305+
testExpectedStreamNarrow('#narrow/channel/1-general', 1);
262306
});
263307

264308
group('if stream not found, use stream ID anyway', () {
265309
testExpectedStreamNarrow('#narrow/stream/123-topic', 123);
310+
testExpectedStreamNarrow('#narrow/channel/123-topic', 123);
266311
});
267312

268313
group('on stream link with wrong name, ID wins', () {
269314
testExpectedStreamNarrow('#narrow/stream/1-nonsense', 1);
270315
testExpectedStreamNarrow('#narrow/stream/1-', 1);
316+
testExpectedStreamNarrow('#narrow/channel/1-nonsense', 1);
317+
testExpectedStreamNarrow('#narrow/channel/1-', 1);
271318
});
272319

273320
group('on malformed stream link: reject', () {
274321
testExpectedStreamNarrow('#narrow/stream/-1', null);
275322
testExpectedStreamNarrow('#narrow/stream/1nonsense-general', null);
276323
testExpectedStreamNarrow('#narrow/stream/-general', null);
324+
testExpectedStreamNarrow('#narrow/channel/-1', null);
325+
testExpectedStreamNarrow('#narrow/channel/1nonsense-general', null);
326+
testExpectedStreamNarrow('#narrow/channel/-general', null);
277327
});
278328
});
279329

@@ -292,6 +342,11 @@ void main() {
292342
('#narrow/stream/311-/', StreamNarrow(3)),
293343
('#narrow/stream/311-help/', StreamNarrow(4)),
294344
('#narrow/stream/--help/', StreamNarrow(5)),
345+
('#narrow/channel/test-team/', StreamNarrow(1)),
346+
('#narrow/channel/311/', StreamNarrow(2)),
347+
('#narrow/channel/311-/', StreamNarrow(3)),
348+
('#narrow/channel/311-help/', StreamNarrow(4)),
349+
('#narrow/channel/--help/', StreamNarrow(5)),
295350
];
296351
testExpectedNarrows(testCases, streams: streams);
297352
});
@@ -307,6 +362,9 @@ void main() {
307362
('#narrow/stream/311/', StreamNarrow(311)),
308363
('#narrow/stream/311-/', StreamNarrow(311)),
309364
('#narrow/stream/311-help/', StreamNarrow(311)),
365+
('#narrow/channel/311/', StreamNarrow(311)),
366+
('#narrow/channel/311-/', StreamNarrow(311)),
367+
('#narrow/channel/311-help/', StreamNarrow(311)),
310368
];
311369
testExpectedNarrows(testCases, streams: streams);
312370
});
@@ -327,6 +385,14 @@ void main() {
327385
('#narrow/stream/topic/', StreamNarrow(5)),
328386

329387
('#narrow/stream/check.API/', null),
388+
389+
('#narrow/channel/check/', StreamNarrow(1)),
390+
('#narrow/channel/bot.20testing/', StreamNarrow(2)),
391+
('#narrow/channel/check.2EAPI/', StreamNarrow(3)),
392+
('#narrow/channel/stream/', StreamNarrow(4)),
393+
('#narrow/channel/topic/', StreamNarrow(5)),
394+
395+
('#narrow/channel/check.API/', null),
330396
];
331397
testExpectedNarrows(testCases, streams: streams);
332398
});
@@ -337,27 +403,36 @@ void main() {
337403
final stream = eg.stream(name: "general");
338404

339405
group('basic', () {
340-
String mkUrlString(operand) {
341-
return '#narrow/stream/${stream.streamId}-${stream.name}/topic/$operand';
406+
String mkUrlString(operand, String streamSyntax) {
407+
return '#narrow/$streamSyntax/${stream.streamId}-${stream.name}/topic/$operand';
342408
}
343409
final testCases = [
344-
(mkUrlString('(no.20topic)'), TopicNarrow(stream.streamId, '(no topic)')),
345-
(mkUrlString('lunch'), TopicNarrow(stream.streamId, 'lunch')),
410+
(mkUrlString('(no.20topic)', 'stream'), TopicNarrow(stream.streamId, '(no topic)')),
411+
(mkUrlString('lunch', 'stream'), TopicNarrow(stream.streamId, 'lunch')),
412+
(mkUrlString('(no.20topic)', 'channel'), TopicNarrow(stream.streamId, '(no topic)')),
413+
(mkUrlString('lunch', 'channel'), TopicNarrow(stream.streamId, 'lunch')),
346414
];
347415
testExpectedNarrows(testCases, streams: [stream]);
348416
});
349417

350418
group('on old topic link, with dot-encoding', () {
351-
String mkUrlString(operand) {
419+
String mkUrlString(operand, String streamSyntax) {
352420
return '#narrow/stream/${stream.name}/topic/$operand';
353421
}
354422
final testCases = [
355-
(mkUrlString('(no.20topic)'), TopicNarrow(stream.streamId, '(no topic)')),
356-
(mkUrlString('google.2Ecom'), TopicNarrow(stream.streamId, 'google.com')),
357-
(mkUrlString('google.com'), null),
358-
(mkUrlString('topic.20name'), TopicNarrow(stream.streamId, 'topic name')),
359-
(mkUrlString('stream'), TopicNarrow(stream.streamId, 'stream')),
360-
(mkUrlString('topic'), TopicNarrow(stream.streamId, 'topic')),
423+
(mkUrlString('(no.20topic)', 'stream'), TopicNarrow(stream.streamId, '(no topic)')),
424+
(mkUrlString('google.2Ecom', 'stream'), TopicNarrow(stream.streamId, 'google.com')),
425+
(mkUrlString('google.com', 'stream'), null),
426+
(mkUrlString('topic.20name', 'stream'), TopicNarrow(stream.streamId, 'topic name')),
427+
(mkUrlString('stream', 'stream'), TopicNarrow(stream.streamId, 'stream')),
428+
(mkUrlString('topic', 'stream'), TopicNarrow(stream.streamId, 'topic')),
429+
430+
(mkUrlString('(no.20topic)', 'channel'), TopicNarrow(stream.streamId, '(no topic)')),
431+
(mkUrlString('google.2Ecom', 'channel'), TopicNarrow(stream.streamId, 'google.com')),
432+
(mkUrlString('google.com', 'channel'), null),
433+
(mkUrlString('topic.20name', 'channel'), TopicNarrow(stream.streamId, 'topic name')),
434+
(mkUrlString('stream', 'channel'), TopicNarrow(stream.streamId, 'stream')),
435+
(mkUrlString('topic', 'channel'), TopicNarrow(stream.streamId, 'topic')),
361436
];
362437
testExpectedNarrows(testCases, streams: [stream]);
363438
});

0 commit comments

Comments
 (0)