OLD | NEW |
| (Empty) |
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | |
2 // for details. All rights reserved. Use of this source code is governed by a | |
3 // BSD-style license that can be found in the LICENSE file. | |
4 | |
5 import 'dart:async'; | |
6 import 'package:observe/observe.dart'; | |
7 import 'package:unittest/unittest.dart'; | |
8 import 'observe_test_utils.dart'; | |
9 | |
10 main() => dirtyCheckZone().run(_runTests); | |
11 | |
12 _runTests() { | |
13 // TODO(jmesserly): need all standard Map API tests. | |
14 | |
15 StreamSubscription sub; | |
16 | |
17 sharedTearDown() { | |
18 if (sub != null) { | |
19 sub.cancel(); | |
20 sub = null; | |
21 } | |
22 } | |
23 | |
24 group('observe length', () { | |
25 ObservableMap map; | |
26 List<ChangeRecord> changes; | |
27 | |
28 setUp(() { | |
29 map = toObservable({'a': 1, 'b': 2, 'c': 3}); | |
30 changes = null; | |
31 sub = map.changes.listen((records) { | |
32 changes = getPropertyChangeRecords(records, #length); | |
33 }); | |
34 }); | |
35 | |
36 tearDown(sharedTearDown); | |
37 | |
38 test('add item changes length', () { | |
39 map['d'] = 4; | |
40 expect(map, {'a': 1, 'b': 2, 'c': 3, 'd': 4}); | |
41 return new Future(() { | |
42 expectChanges(changes, [_lengthChange(map, 3, 4)]); | |
43 }); | |
44 }); | |
45 | |
46 test('putIfAbsent changes length', () { | |
47 map.putIfAbsent('d', () => 4); | |
48 expect(map, {'a': 1, 'b': 2, 'c': 3, 'd': 4}); | |
49 return new Future(() { | |
50 expectChanges(changes, [_lengthChange(map, 3, 4)]); | |
51 }); | |
52 }); | |
53 | |
54 test('remove changes length', () { | |
55 map.remove('c'); | |
56 map.remove('a'); | |
57 expect(map, {'b': 2}); | |
58 return new Future(() { | |
59 expectChanges(changes, [ | |
60 _lengthChange(map, 3, 2), | |
61 _lengthChange(map, 2, 1) | |
62 ]); | |
63 }); | |
64 }); | |
65 | |
66 test('remove non-existent item does not change length', () { | |
67 map.remove('d'); | |
68 expect(map, {'a': 1, 'b': 2, 'c': 3}); | |
69 return new Future(() { | |
70 expectChanges(changes, null); | |
71 }); | |
72 }); | |
73 | |
74 test('set existing item does not change length', () { | |
75 map['c'] = 9000; | |
76 expect(map, {'a': 1, 'b': 2, 'c': 9000}); | |
77 return new Future(() { | |
78 expectChanges(changes, []); | |
79 }); | |
80 }); | |
81 | |
82 test('clear changes length', () { | |
83 map.clear(); | |
84 expect(map, {}); | |
85 return new Future(() { | |
86 expectChanges(changes, [_lengthChange(map, 3, 0)]); | |
87 }); | |
88 }); | |
89 }); | |
90 | |
91 group('observe item', () { | |
92 | |
93 ObservableMap map; | |
94 List<ChangeRecord> changes; | |
95 | |
96 setUp(() { | |
97 map = toObservable({'a': 1, 'b': 2, 'c': 3}); | |
98 changes = null; | |
99 sub = map.changes.listen((records) { | |
100 changes = records.where((r) => r is MapChangeRecord && r.key == 'b') | |
101 .toList(); | |
102 }); | |
103 }); | |
104 | |
105 tearDown(sharedTearDown); | |
106 | |
107 test('putIfAbsent new item does not change existing item', () { | |
108 map.putIfAbsent('d', () => 4); | |
109 expect(map, {'a': 1, 'b': 2, 'c': 3, 'd': 4}); | |
110 return new Future(() { | |
111 expectChanges(changes, []); | |
112 }); | |
113 }); | |
114 | |
115 test('set item to null', () { | |
116 map['b'] = null; | |
117 expect(map, {'a': 1, 'b': null, 'c': 3}); | |
118 return new Future(() { | |
119 expectChanges(changes, [_changeKey('b', 2, null)]); | |
120 }); | |
121 }); | |
122 | |
123 test('set item to value', () { | |
124 map['b'] = 777; | |
125 expect(map, {'a': 1, 'b': 777, 'c': 3}); | |
126 return new Future(() { | |
127 expectChanges(changes, [_changeKey('b', 2, 777)]); | |
128 }); | |
129 }); | |
130 | |
131 test('putIfAbsent does not change if already there', () { | |
132 map.putIfAbsent('b', () => 1234); | |
133 expect(map, {'a': 1, 'b': 2, 'c': 3}); | |
134 return new Future(() { | |
135 expectChanges(changes, null); | |
136 }); | |
137 }); | |
138 | |
139 test('change a different item', () { | |
140 map['c'] = 9000; | |
141 expect(map, {'a': 1, 'b': 2, 'c': 9000}); | |
142 return new Future(() { | |
143 expectChanges(changes, []); | |
144 }); | |
145 }); | |
146 | |
147 test('change the item', () { | |
148 map['b'] = 9001; | |
149 map['b'] = 42; | |
150 expect(map, {'a': 1, 'b': 42, 'c': 3}); | |
151 return new Future(() { | |
152 expectChanges(changes, [ | |
153 _changeKey('b', 2, 9001), | |
154 _changeKey('b', 9001, 42) | |
155 ]); | |
156 }); | |
157 }); | |
158 | |
159 test('remove other items', () { | |
160 map.remove('a'); | |
161 expect(map, {'b': 2, 'c': 3}); | |
162 return new Future(() { | |
163 expectChanges(changes, []); | |
164 }); | |
165 }); | |
166 | |
167 test('remove the item', () { | |
168 map.remove('b'); | |
169 expect(map, {'a': 1, 'c': 3}); | |
170 return new Future(() { | |
171 expectChanges(changes, [_removeKey('b', 2)]); | |
172 }); | |
173 }); | |
174 | |
175 test('remove and add back', () { | |
176 map.remove('b'); | |
177 map['b'] = 2; | |
178 expect(map, {'a': 1, 'b': 2, 'c': 3}); | |
179 return new Future(() { | |
180 expectChanges(changes, | |
181 [_removeKey('b', 2), _insertKey('b', 2)]); | |
182 }); | |
183 }); | |
184 }); | |
185 | |
186 test('toString', () { | |
187 var map = toObservable({'a': 1, 'b': 2}); | |
188 expect(map.toString(), '{a: 1, b: 2}'); | |
189 }); | |
190 | |
191 group('observe keys/values', () { | |
192 ObservableMap map; | |
193 int keysChanged; | |
194 int valuesChanged; | |
195 | |
196 setUp(() { | |
197 map = toObservable({'a': 1, 'b': 2, 'c': 3}); | |
198 keysChanged = 0; | |
199 valuesChanged = 0; | |
200 sub = map.changes.listen((records) { | |
201 keysChanged += getPropertyChangeRecords(records, #keys).length; | |
202 valuesChanged += getPropertyChangeRecords(records, #values).length; | |
203 }); | |
204 }); | |
205 | |
206 tearDown(sharedTearDown); | |
207 | |
208 test('add item changes keys/values', () { | |
209 map['d'] = 4; | |
210 expect(map, {'a': 1, 'b': 2, 'c': 3, 'd': 4}); | |
211 return new Future(() { | |
212 expect(keysChanged, 1); | |
213 expect(valuesChanged, 1); | |
214 }); | |
215 }); | |
216 | |
217 test('putIfAbsent changes keys/values', () { | |
218 map.putIfAbsent('d', () => 4); | |
219 expect(map, {'a': 1, 'b': 2, 'c': 3, 'd': 4}); | |
220 return new Future(() { | |
221 expect(keysChanged, 1); | |
222 expect(valuesChanged, 1); | |
223 }); | |
224 }); | |
225 | |
226 test('remove changes keys/values', () { | |
227 map.remove('c'); | |
228 map.remove('a'); | |
229 expect(map, {'b': 2}); | |
230 return new Future(() { | |
231 expect(keysChanged, 2); | |
232 expect(valuesChanged, 2); | |
233 }); | |
234 }); | |
235 | |
236 test('remove non-existent item does not change keys/values', () { | |
237 map.remove('d'); | |
238 expect(map, {'a': 1, 'b': 2, 'c': 3}); | |
239 return new Future(() { | |
240 expect(keysChanged, 0); | |
241 expect(valuesChanged, 0); | |
242 }); | |
243 }); | |
244 | |
245 test('set existing item does not change keys', () { | |
246 map['c'] = 9000; | |
247 expect(map, {'a': 1, 'b': 2, 'c': 9000}); | |
248 return new Future(() { | |
249 expect(keysChanged, 0); | |
250 expect(valuesChanged, 1); | |
251 }); | |
252 }); | |
253 | |
254 test('clear changes keys/values', () { | |
255 map.clear(); | |
256 expect(map, {}); | |
257 return new Future(() { | |
258 expect(keysChanged, 1); | |
259 expect(valuesChanged, 1); | |
260 }); | |
261 }); | |
262 }); | |
263 | |
264 | |
265 group('change records', () { | |
266 List<ChangeRecord> records; | |
267 ObservableMap map; | |
268 | |
269 setUp(() { | |
270 map = toObservable({'a': 1, 'b': 2}); | |
271 records = null; | |
272 map.changes.first.then((r) { records = r; }); | |
273 }); | |
274 | |
275 tearDown(sharedTearDown); | |
276 | |
277 test('read operations', () { | |
278 expect(map.length, 2); | |
279 expect(map.isEmpty, false); | |
280 expect(map['a'], 1); | |
281 expect(map.containsKey(2), false); | |
282 expect(map.containsValue(2), true); | |
283 expect(map.containsKey('b'), true); | |
284 expect(map.keys.toList(), ['a', 'b']); | |
285 expect(map.values.toList(), [1, 2]); | |
286 var copy = {}; | |
287 map.forEach((k, v) { copy[k] = v; }); | |
288 expect(copy, {'a': 1, 'b': 2}); | |
289 return new Future(() { | |
290 // no change from read-only operators | |
291 expect(records, null); | |
292 | |
293 // Make a change so the subscription gets unregistered. | |
294 map.clear(); | |
295 }); | |
296 }); | |
297 | |
298 test('putIfAbsent', () { | |
299 map.putIfAbsent('a', () => 42); | |
300 expect(map, {'a': 1, 'b': 2}); | |
301 | |
302 map.putIfAbsent('c', () => 3); | |
303 expect(map, {'a': 1, 'b': 2, 'c': 3}); | |
304 | |
305 return new Future(() { | |
306 expectChanges(records, [ | |
307 _lengthChange(map, 2, 3), | |
308 _insertKey('c', 3), | |
309 _propChange(map, #keys), | |
310 _propChange(map, #values), | |
311 ]); | |
312 }); | |
313 }); | |
314 | |
315 test('[]=', () { | |
316 map['a'] = 42; | |
317 expect(map, {'a': 42, 'b': 2}); | |
318 | |
319 map['c'] = 3; | |
320 expect(map, {'a': 42, 'b': 2, 'c': 3}); | |
321 | |
322 return new Future(() { | |
323 expectChanges(records, [ | |
324 _changeKey('a', 1, 42), | |
325 _propChange(map, #values), | |
326 _lengthChange(map, 2, 3), | |
327 _insertKey('c', 3), | |
328 _propChange(map, #keys), | |
329 _propChange(map, #values), | |
330 ]); | |
331 }); | |
332 }); | |
333 | |
334 test('remove', () { | |
335 map.remove('b'); | |
336 expect(map, {'a': 1}); | |
337 | |
338 return new Future(() { | |
339 expectChanges(records, [ | |
340 _removeKey('b', 2), | |
341 _lengthChange(map, 2, 1), | |
342 _propChange(map, #keys), | |
343 _propChange(map, #values), | |
344 ]); | |
345 }); | |
346 }); | |
347 | |
348 test('clear', () { | |
349 map.clear(); | |
350 expect(map, {}); | |
351 | |
352 return new Future(() { | |
353 expectChanges(records, [ | |
354 _removeKey('a', 1), | |
355 _removeKey('b', 2), | |
356 _lengthChange(map, 2, 0), | |
357 _propChange(map, #keys), | |
358 _propChange(map, #values), | |
359 ]); | |
360 }); | |
361 }); | |
362 }); | |
363 } | |
364 | |
365 _lengthChange(map, int oldValue, int newValue) => | |
366 new PropertyChangeRecord(map, #length, oldValue, newValue); | |
367 | |
368 _changeKey(key, old, newValue) => new MapChangeRecord(key, old, newValue); | |
369 | |
370 _insertKey(key, newValue) => new MapChangeRecord.insert(key, newValue); | |
371 | |
372 _removeKey(key, oldValue) => new MapChangeRecord.remove(key, oldValue); | |
373 | |
374 _propChange(map, prop) => new PropertyChangeRecord(map, prop, null, null); | |
OLD | NEW |