Skip to content

Commit a55dedc

Browse files
committed
internal_link: Recognize channel operator in narrow links
Fixes: #632
1 parent 53853ab commit a55dedc

File tree

3 files changed

+52
-6
lines changed

3 files changed

+52
-6
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: 49 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -36,12 +36,19 @@ void main() {
3636
assert(streams != null || users != null);
3737
for (final testCase in testCases) {
3838
final String urlString = testCase.$1;
39-
final Narrow? expected = testCase.$2;
40-
test(urlString, () async {
41-
final store = await setupStore(realmUrl: realmUrl, streams: streams, users: users);
42-
final url = store.tryResolveUrl(urlString)!;
43-
check(parseInternalLink(url, store)).equals(expected);
44-
});
39+
// This is here to avoid duplicating each test case that contains `#narrow/stream` or `#narrow/channel`
40+
final urlWithChannelSyntax = urlString.replaceFirst('#narrow/stream', '#narrow/channel');
41+
final urlWithStreamSyntax = urlString.replaceFirst('#narrow/channel', '#narrow/stream');
42+
// Using Set instead of List in `{urlWithStreamSyntax, urlWithChannelSyntax}` to avoid any duplicated
43+
// test urls. Specifically, when url is targeting `pm-with/..` or `dm/..`
44+
for (final urlString in {urlWithStreamSyntax, urlWithChannelSyntax}) {
45+
final Narrow? expected = testCase.$2;
46+
test(urlString, () async {
47+
final store = await setupStore(realmUrl: realmUrl, streams: streams, users: users);
48+
final url = store.tryResolveUrl(urlString)!;
49+
check(parseInternalLink(url, store)).equals(expected);
50+
});
51+
}
4552
}
4653
}
4754

@@ -52,13 +59,21 @@ void main() {
5259
final testCases = [
5360
(true, 'legacy: stream name, no ID',
5461
'#narrow/stream/check', realmUrl),
62+
(true, 'legacy: channel name, no ID',
63+
'#narrow/channel/check', realmUrl),
5564
(true, 'legacy: stream name, no ID, topic',
5665
'#narrow/stream/check/topic/topic1', realmUrl),
66+
(true, 'legacy: channel name, no ID, topic',
67+
'#narrow/channel/check/topic/topic1', realmUrl),
5768

5869
(true, 'with numeric stream ID',
5970
'#narrow/stream/123-check', realmUrl),
71+
(true, 'with numeric channel ID',
72+
'#narrow/channel/123-check', realmUrl),
6073
(true, 'with numeric stream ID and topic',
6174
'#narrow/stream/123-a/topic/topic1', realmUrl),
75+
(true, 'with numeric channel ID and topic',
76+
'#narrow/channel/123-a/topic/topic1', realmUrl),
6277

6378
(true, 'with numeric pm user IDs (new operator)',
6479
'#narrow/dm/123-mark', realmUrl),
@@ -69,20 +84,33 @@ void main() {
6984
'#nope', realmUrl),
7085
(false, 'wrong path',
7186
'user_uploads/#narrow/stream/check', realmUrl),
87+
(false, 'wrong path with channel syntax',
88+
'user_uploads/#narrow/channel/check', realmUrl),
7289
(false, 'wrong domain',
7390
'https://another.com/#narrow/stream/check', realmUrl),
91+
(false, 'wrong domain with channel syntax',
92+
'https://another.com/#narrow/channel/check', realmUrl),
7493

7594
(false, '#narrowly',
7695
'#narrowly/stream/check', realmUrl),
96+
(false, '#narrowly with channel syntax',
97+
'#narrowly/channel/check', realmUrl),
7798

7899
(false, 'double slash',
79100
'https://example.com//#narrow/stream/check', realmUrl),
101+
(false, 'double slash with channel syntax',
102+
'https://example.com//#narrow/channel/check', realmUrl),
80103
(false, 'triple slash',
81104
'https://example.com///#narrow/stream/check', realmUrl),
105+
(false, 'triple slash with channel syntax',
106+
'https://example.com///#narrow/channel/check', realmUrl),
82107

83108
(true, 'with port',
84109
'https://example.com:444/#narrow/stream/check',
85110
Uri.parse('https://example.com:444/')),
111+
(true, 'with port with channel syntax',
112+
'https://example.com:444/#narrow/channel/check',
113+
Uri.parse('https://example.com:444/')),
86114

87115
// Dart's [Uri] currently lacks IDNA or Punycode support:
88116
// https://github.com/dart-lang/sdk/issues/26284
@@ -95,6 +123,9 @@ void main() {
95123
(true, 'punycodable host',
96124
'https://example.भारत/#narrow/stream/check',
97125
Uri.parse('https://example.भारत/')),
126+
(true, 'punycodable host with channel syntax',
127+
'https://example.भारत/#narrow/channel/check',
128+
Uri.parse('https://example.भारत/')),
98129

99130
// (true, 'same domain, IDNA-mappable',
100131
// 'https://ℯⅩªm🄿ₗℰ.ℭᴼⓂ/#narrow/stream/check',
@@ -103,6 +134,9 @@ void main() {
103134
(true, 'ipv4 address',
104135
'http://192.168.0.1/#narrow/stream/check',
105136
Uri.parse('http://192.168.0.1/')),
137+
(true, 'ipv4 address with channel syntax',
138+
'http://192.168.0.1/#narrow/channel/check',
139+
Uri.parse('http://192.168.0.1/')),
106140

107141
// (true, 'same IPv4 address, IDNA-mappable',
108142
// 'http://1𝟗𝟚。①⁶🯸.₀。𝟭/#narrow/stream/check',
@@ -119,12 +153,21 @@ void main() {
119153
(false, 'wrong domain, realm-like path, narrow-like fragment',
120154
'https://web.archive.org/web/*/${realmUrl.resolve('#narrow/stream/check')}',
121155
realmUrl),
156+
(false, 'wrong domain, realm-like path, narrow-like fragment with channel syntax',
157+
'https://web.archive.org/web/*/${realmUrl.resolve('#narrow/channel/check')}',
158+
realmUrl),
122159
(false, 'odd scheme, wrong domain, realm-like path, narrow-like fragment',
123160
'ftp://web.archive.org/web/*/${realmUrl.resolve('#narrow/stream/check')}',
124161
realmUrl),
162+
(false, 'odd scheme, wrong domain, realm-like path, narrow-like fragment with channel syntax',
163+
'ftp://web.archive.org/web/*/${realmUrl.resolve('#narrow/channel/check')}',
164+
realmUrl),
125165
(false, 'same domain, realm-like path, narrow-like fragment',
126166
'web/*/${realmUrl.resolve('#narrow/stream/check')}',
127167
realmUrl),
168+
(false, 'same domain, realm-like path, narrow-like fragment with channel syntax',
169+
'web/*/${realmUrl.resolve('#narrow/channel/check')}',
170+
realmUrl),
128171
];
129172
for (final testCase in testCases) {
130173
final bool expected = testCase.$1;

0 commit comments

Comments
 (0)