@@ -202,6 +202,151 @@ void main() {
202
202
check (store.allEmojiCandidates ()).identicalTo (candidates);
203
203
});
204
204
});
205
+
206
+ group ('EmojiAutocompleteQuery.matches' , () {
207
+ EmojiCandidate unicode (List <String > names, {String ? emojiCode}) {
208
+ emojiCode ?? = '10ffff' ;
209
+ return EmojiCandidate (emojiType: ReactionType .unicodeEmoji,
210
+ emojiCode: emojiCode,
211
+ emojiName: names.first, aliases: names.sublist (1 ),
212
+ emojiDisplay: UnicodeEmojiDisplay (
213
+ emojiName: names.first,
214
+ emojiUnicode: tryParseEmojiCodeToUnicode (emojiCode)! ));
215
+ }
216
+
217
+ bool matchesName (String query, String emojiName) {
218
+ return EmojiAutocompleteQuery (query).matches (unicode ([emojiName]));
219
+ }
220
+
221
+ test ('one-word query matches anywhere in name' , () {
222
+ check (matchesName ('' , 'smile' )).isTrue ();
223
+ check (matchesName ('s' , 'smile' )).isTrue ();
224
+ check (matchesName ('sm' , 'smile' )).isTrue ();
225
+ check (matchesName ('smile' , 'smile' )).isTrue ();
226
+ check (matchesName ('m' , 'smile' )).isTrue ();
227
+ check (matchesName ('mile' , 'smile' )).isTrue ();
228
+ check (matchesName ('e' , 'smile' )).isTrue ();
229
+
230
+ check (matchesName ('smiley' , 'smile' )).isFalse ();
231
+ check (matchesName ('a' , 'smile' )).isFalse ();
232
+
233
+ check (matchesName ('o' , 'open_book' )).isTrue ();
234
+ check (matchesName ('open' , 'open_book' )).isTrue ();
235
+ check (matchesName ('pe' , 'open_book' )).isTrue ();
236
+ check (matchesName ('boo' , 'open_book' )).isTrue ();
237
+ check (matchesName ('ok' , 'open_book' )).isTrue ();
238
+ });
239
+
240
+ test ('multi-word query matches from start of a word' , () {
241
+ check (matchesName ('open_' , 'open_book' )).isTrue ();
242
+ check (matchesName ('open_b' , 'open_book' )).isTrue ();
243
+ check (matchesName ('open_book' , 'open_book' )).isTrue ();
244
+
245
+ check (matchesName ('pen_' , 'open_book' )).isFalse ();
246
+ check (matchesName ('n_b' , 'open_book' )).isFalse ();
247
+
248
+ check (matchesName ('blue_dia' , 'large_blue_diamond' )).isTrue ();
249
+ });
250
+
251
+ test ('spaces in query behave as underscores' , () {
252
+ check (matchesName ('open ' , 'open_book' )).isTrue ();
253
+ check (matchesName ('open b' , 'open_book' )).isTrue ();
254
+ check (matchesName ('open book' , 'open_book' )).isTrue ();
255
+
256
+ check (matchesName ('pen ' , 'open_book' )).isFalse ();
257
+ check (matchesName ('n b' , 'open_book' )).isFalse ();
258
+
259
+ check (matchesName ('blue dia' , 'large_blue_diamond' )).isTrue ();
260
+ });
261
+
262
+ test ('query is lower-cased' , () {
263
+ check (matchesName ('Smi' , 'smile' )).isTrue ();
264
+ });
265
+
266
+ test ('query matches aliases same way as primary name' , () {
267
+ bool matchesNames (String query, List <String > names) {
268
+ return EmojiAutocompleteQuery (query).matches (unicode (names));
269
+ }
270
+
271
+ check (matchesNames ('a' , ['a' , 'b' ])).isTrue ();
272
+ check (matchesNames ('b' , ['a' , 'b' ])).isTrue ();
273
+ check (matchesNames ('c' , ['a' , 'b' ])).isFalse ();
274
+
275
+ check (matchesNames ('pe' , ['x' , 'open_book' ])).isTrue ();
276
+ check (matchesNames ('ok' , ['x' , 'open_book' ])).isTrue ();
277
+
278
+ check (matchesNames ('open_' , ['x' , 'open_book' ])).isTrue ();
279
+ check (matchesNames ('open b' , ['x' , 'open_book' ])).isTrue ();
280
+ check (matchesNames ('pen_' , ['x' , 'open_book' ])).isFalse ();
281
+
282
+ check (matchesNames ('Smi' , ['x' , 'smile' ])).isTrue ();
283
+ });
284
+
285
+ test ('query matches literal Unicode value' , () {
286
+ bool matchesLiteral (String query, String emojiCode, {required String aka}) {
287
+ assert (aka == query);
288
+ return EmojiAutocompleteQuery (query)
289
+ .matches (unicode (['asdf' ], emojiCode: emojiCode));
290
+ }
291
+
292
+ // Matching the code, in hex, doesn't count.
293
+ check (matchesLiteral ('1f642' , aka: '1f642' , '1f642' )).isFalse ();
294
+
295
+ // Matching the Unicode value the code describes does count…
296
+ check (matchesLiteral ('🙂' , aka: '\u {1f642}' , '1f642' )).isTrue ();
297
+ // … and failing to match it doesn't make a match.
298
+ check (matchesLiteral ('🙁' , aka: '\u {1f641}' , '1f642' )).isFalse ();
299
+
300
+ // Multi-code-point emoji work fine.
301
+ check (matchesLiteral ('🏳🌈' , aka: '\u {1f3f3}\u {200d}\u {1f308}' ,
302
+ '1f3f3-200d-1f308' )).isTrue ();
303
+ // Only exact matches count; no partial matches.
304
+ check (matchesLiteral ('🏳' , aka: '\u {1f3f3}' ,
305
+ '1f3f3-200d-1f308' )).isFalse ();
306
+ check (matchesLiteral ('🌈' , aka: '\u {200d}\u {1f308}' ,
307
+ '1f3f3-200d-1f308' )).isFalse ();
308
+ check (matchesLiteral ('🏳🌈' , aka: '\u {1f3f3}\u {200d}\u {1f308}' ,
309
+ '1f3f3' )).isFalse ();
310
+ });
311
+
312
+ test ('can match realm emoji' , () {
313
+ EmojiCandidate realmCandidate (String emojiName) {
314
+ return EmojiCandidate (
315
+ emojiType: ReactionType .realmEmoji,
316
+ emojiCode: '1' , emojiName: emojiName, aliases: null ,
317
+ emojiDisplay: ImageEmojiDisplay (
318
+ emojiName: emojiName,
319
+ resolvedUrl: eg.realmUrl.resolve ('/emoji/1.png' ),
320
+ resolvedStillUrl: eg.realmUrl.resolve ('/emoji/1-still.png' )));
321
+ }
322
+
323
+ check (EmojiAutocompleteQuery ('eqeq' )
324
+ .matches (realmCandidate ('eqeq' ))).isTrue ();
325
+ check (EmojiAutocompleteQuery ('open_' )
326
+ .matches (realmCandidate ('open_book' ))).isTrue ();
327
+ check (EmojiAutocompleteQuery ('n_b' )
328
+ .matches (realmCandidate ('open_book' ))).isFalse ();
329
+ check (EmojiAutocompleteQuery ('blue dia' )
330
+ .matches (realmCandidate ('large_blue_diamond' ))).isTrue ();
331
+ check (EmojiAutocompleteQuery ('Smi' )
332
+ .matches (realmCandidate ('smile' ))).isTrue ();
333
+ });
334
+
335
+ test ('can match Zulip extra emoji' , () {
336
+ final store = eg.store ();
337
+ final zulipCandidate = EmojiCandidate (
338
+ emojiType: ReactionType .zulipExtraEmoji,
339
+ emojiCode: 'zulip' , emojiName: 'zulip' , aliases: null ,
340
+ emojiDisplay: store.emojiDisplayFor (
341
+ emojiType: ReactionType .zulipExtraEmoji,
342
+ emojiCode: 'zulip' , emojiName: 'zulip' ));
343
+
344
+ check (EmojiAutocompleteQuery ('z' ).matches (zulipCandidate)).isTrue ();
345
+ check (EmojiAutocompleteQuery ('Zulip' ).matches (zulipCandidate)).isTrue ();
346
+ check (EmojiAutocompleteQuery ('p' ).matches (zulipCandidate)).isTrue ();
347
+ check (EmojiAutocompleteQuery ('x' ).matches (zulipCandidate)).isFalse ();
348
+ });
349
+ });
205
350
}
206
351
207
352
extension EmojiDisplayChecks on Subject <EmojiDisplay > {
0 commit comments