1
1
import 'package:checks/checks.dart' ;
2
2
import 'package:test/scaffolding.dart' ;
3
+ import 'package:zulip/api/model/events.dart' ;
3
4
import 'package:zulip/api/model/model.dart' ;
5
+ import 'package:zulip/api/route/realm.dart' ;
4
6
import 'package:zulip/model/emoji.dart' ;
7
+ import 'package:zulip/model/store.dart' ;
5
8
6
9
import '../example_data.dart' as eg;
7
10
@@ -73,6 +76,132 @@ void main() {
73
76
..resolvedStillUrl.isNull ();
74
77
});
75
78
});
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
+ });
76
205
}
77
206
78
207
extension EmojiDisplayChecks on Subject <EmojiDisplay > {
@@ -87,3 +216,11 @@ extension ImageEmojiDisplayChecks on Subject<ImageEmojiDisplay> {
87
216
Subject <Uri > get resolvedUrl => has ((x) => x.resolvedUrl, 'resolvedUrl' );
88
217
Subject <Uri ?> get resolvedStillUrl => has ((x) => x.resolvedStillUrl, 'resolvedStillUrl' );
89
218
}
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