11import 'package:checks/checks.dart' ;
22import 'package:test/scaffolding.dart' ;
3+ import 'package:zulip/api/model/events.dart' ;
34import 'package:zulip/api/model/model.dart' ;
5+ import 'package:zulip/api/route/realm.dart' ;
46import 'package:zulip/model/emoji.dart' ;
7+ import 'package:zulip/model/store.dart' ;
58
69import '../example_data.dart' as eg;
710
@@ -73,6 +76,132 @@ void main() {
7376 ..resolvedStillUrl.isNull ();
7477 });
7578 });
79+
80+ Condition <Object ?> isUnicodeCandidate (String ? emojiCode, List <String >? names) {
81+ return (it_) {
82+ final it = it_.isA <EmojiCandidate >();
83+ it.emojiType.equals (ReactionType .unicodeEmoji);
84+ if (emojiCode != null ) it.emojiCode.equals (emojiCode);
85+ if (names != null ) {
86+ it.emojiName.equals (names.first);
87+ it.aliases.deepEquals (names.sublist (1 ));
88+ }
89+ };
90+ }
91+
92+ Condition <Object ?> isRealmCandidate ({String ? emojiCode, String ? emojiName}) {
93+ return (it_) {
94+ final it = it_.isA <EmojiCandidate >();
95+ it.emojiType.equals (ReactionType .realmEmoji);
96+ if (emojiCode != null ) it.emojiCode.equals (emojiCode);
97+ if (emojiName != null ) it.emojiName.equals (emojiName);
98+ it.aliases.isEmpty ();
99+ };
100+ }
101+
102+ Condition <Object ?> isZulipCandidate () {
103+ return (it) => it.isA <EmojiCandidate >()
104+ ..emojiType.equals (ReactionType .zulipExtraEmoji)
105+ ..emojiCode.equals ('zulip' )
106+ ..emojiName.equals ('zulip' )
107+ ..aliases.isEmpty ();
108+ }
109+
110+ group ('allEmojiCandidates' , () {
111+ // TODO test emojiDisplay of candidates matches emojiDisplayFor
112+
113+ PerAccountStore prepare ({
114+ Map <String , RealmEmojiItem > realmEmoji = const {},
115+ Map <String , List <String >>? unicodeEmoji,
116+ }) {
117+ final store = eg.store (
118+ initialSnapshot: eg.initialSnapshot (realmEmoji: realmEmoji));
119+ if (unicodeEmoji != null ) {
120+ store.setServerEmojiData (ServerEmojiData (codeToNames: unicodeEmoji));
121+ }
122+ return store;
123+ }
124+
125+ test ('realm emoji overrides Unicode emoji' , () {
126+ final store = prepare (realmEmoji: {
127+ '1' : eg.realmEmojiItem (emojiCode: '1' , emojiName: 'smiley' ),
128+ }, unicodeEmoji: {
129+ '1f642' : ['smile' ],
130+ '1f603' : ['smiley' ],
131+ });
132+ check (store.allEmojiCandidates ()).deepEquals ([
133+ isUnicodeCandidate ('1f642' , ['smile' ]),
134+ isRealmCandidate (emojiCode: '1' , emojiName: 'smiley' ),
135+ isZulipCandidate (),
136+ ]);
137+ });
138+
139+ test ('Unicode emoji with overridden aliases survives with remaining names' , () {
140+ final store = prepare (realmEmoji: {
141+ '1' : eg.realmEmojiItem (emojiCode: '1' , emojiName: 'tangerine' ),
142+ }, unicodeEmoji: {
143+ '1f34a' : ['orange' , 'tangerine' , 'mandarin' ],
144+ });
145+ check (store.allEmojiCandidates ()).deepEquals ([
146+ isUnicodeCandidate ('1f34a' , ['orange' , 'mandarin' ]),
147+ isRealmCandidate (emojiCode: '1' , emojiName: 'tangerine' ),
148+ isZulipCandidate (),
149+ ]);
150+ });
151+
152+ test ('Unicode emoji with overridden primary name survives with remaining names' , () {
153+ final store = prepare (realmEmoji: {
154+ '1' : eg.realmEmojiItem (emojiCode: '1' , emojiName: 'orange' ),
155+ }, unicodeEmoji: {
156+ '1f34a' : ['orange' , 'tangerine' , 'mandarin' ],
157+ });
158+ check (store.allEmojiCandidates ()).deepEquals ([
159+ isUnicodeCandidate ('1f34a' , ['tangerine' , 'mandarin' ]),
160+ isRealmCandidate (emojiCode: '1' , emojiName: 'orange' ),
161+ isZulipCandidate (),
162+ ]);
163+ });
164+
165+ test ('updates on setServerEmojiData' , () {
166+ final store = prepare ();
167+ check (store.allEmojiCandidates ()).deepEquals ([
168+ isZulipCandidate (),
169+ ]);
170+
171+ store.setServerEmojiData (ServerEmojiData (codeToNames: {
172+ '1f642' : ['smile' ],
173+ }));
174+ check (store.allEmojiCandidates ()).deepEquals ([
175+ isUnicodeCandidate ('1f642' , ['smile' ]),
176+ isZulipCandidate (),
177+ ]);
178+ });
179+
180+ test ('updates on RealmEmojiUpdateEvent' , () {
181+ final store = prepare ();
182+ check (store.allEmojiCandidates ()).deepEquals ([
183+ isZulipCandidate (),
184+ ]);
185+
186+ store.handleEvent (RealmEmojiUpdateEvent (id: 1 , realmEmoji: {
187+ '1' : eg.realmEmojiItem (emojiCode: '1' , emojiName: 'happy' ),
188+ }));
189+ check (store.allEmojiCandidates ()).deepEquals ([
190+ isRealmCandidate (emojiCode: '1' , emojiName: 'happy' ),
191+ isZulipCandidate (),
192+ ]);
193+ });
194+
195+ test ('memoizes result' , () {
196+ final store = prepare (realmEmoji: {
197+ '1' : eg.realmEmojiItem (emojiCode: '1' , emojiName: 'happy' ),
198+ }, unicodeEmoji: {
199+ '1f642' : ['smile' ],
200+ });
201+ final candidates = store.allEmojiCandidates ();
202+ check (store.allEmojiCandidates ()).identicalTo (candidates);
203+ });
204+ });
76205}
77206
78207extension EmojiDisplayChecks on Subject <EmojiDisplay > {
@@ -87,3 +216,11 @@ extension ImageEmojiDisplayChecks on Subject<ImageEmojiDisplay> {
87216 Subject <Uri > get resolvedUrl => has ((x) => x.resolvedUrl, 'resolvedUrl' );
88217 Subject <Uri ?> get resolvedStillUrl => has ((x) => x.resolvedStillUrl, 'resolvedStillUrl' );
89218}
219+
220+ extension EmojiCandidateChecks on Subject <EmojiCandidate > {
221+ Subject <ReactionType > get emojiType => has ((x) => x.emojiType, 'emojiType' );
222+ Subject <String > get emojiCode => has ((x) => x.emojiCode, 'emojiCode' );
223+ Subject <String > get emojiName => has ((x) => x.emojiName, 'emojiName' );
224+ Subject <Iterable <String >> get aliases => has ((x) => x.aliases, 'aliases' );
225+ Subject <EmojiDisplay > get emojiDisplay => has ((x) => x.emojiDisplay, 'emojiDisplay' );
226+ }
0 commit comments