Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(879)

Side by Side Diff: pkg/observe/test/observable_map_test.dart

Issue 19771010: implement dirty checking for @observable objects (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: fix example code in the library comment Created 7 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file 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 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. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 import 'dart:async';
5 import 'package:observe/observe.dart'; 6 import 'package:observe/observe.dart';
6 import 'package:unittest/unittest.dart'; 7 import 'package:unittest/unittest.dart';
7 import 'utils.dart'; 8 import 'observe_test_utils.dart';
8 9
9 main() { 10 main() {
10 // TODO(jmesserly): need all standard Map API tests. 11 // TODO(jmesserly): need all standard Map API tests.
11 12
13 StreamSubscription sub;
14
15 sharedTearDown() {
16 if (sub != null) {
17 sub.cancel();
18 sub = null;
19 }
20 }
21
12 group('observe length', () { 22 group('observe length', () {
13 ObservableMap map; 23 ObservableMap map;
14 List<ChangeRecord> changes; 24 List<ChangeRecord> changes;
15 25
16 setUp(() { 26 setUp(() {
17 map = toObservable({'a': 1, 'b': 2, 'c': 3}); 27 map = toObservable({'a': 1, 'b': 2, 'c': 3});
18 changes = null; 28 changes = null;
19 map.changes.listen((records) { 29 sub = map.changes.listen((records) {
20 changes = records.where((r) => r.changes(_LENGTH)).toList(); 30 changes = records.where((r) => r.changes(_LENGTH)).toList();
21 }); 31 });
22 }); 32 });
23 33
24 test('add item changes length', () { 34 tearDown(sharedTearDown);
35
36 observeTest('add item changes length', () {
25 map['d'] = 4; 37 map['d'] = 4;
26 expect(map, {'a': 1, 'b': 2, 'c': 3, 'd': 4}); 38 expect(map, {'a': 1, 'b': 2, 'c': 3, 'd': 4});
27 deliverChangeRecords(); 39 performMicrotaskCheckpoint();
28 expectChanges(changes, [_lengthChange]); 40 expectChanges(changes, [_lengthChange]);
29 }); 41 });
30 42
31 test('putIfAbsent changes length', () { 43 observeTest('putIfAbsent changes length', () {
32 map.putIfAbsent('d', () => 4); 44 map.putIfAbsent('d', () => 4);
33 expect(map, {'a': 1, 'b': 2, 'c': 3, 'd': 4}); 45 expect(map, {'a': 1, 'b': 2, 'c': 3, 'd': 4});
34 deliverChangeRecords(); 46 performMicrotaskCheckpoint();
35 expectChanges(changes, [_lengthChange]); 47 expectChanges(changes, [_lengthChange]);
36 }); 48 });
37 49
38 test('remove changes length', () { 50 observeTest('remove changes length', () {
39 map.remove('c'); 51 map.remove('c');
40 map.remove('a'); 52 map.remove('a');
41 expect(map, {'b': 2}); 53 expect(map, {'b': 2});
42 deliverChangeRecords(); 54 performMicrotaskCheckpoint();
43 expectChanges(changes, [_lengthChange, _lengthChange]); 55 expectChanges(changes, [_lengthChange, _lengthChange]);
44 }); 56 });
45 57
46 test('remove non-existent item does not change length', () { 58 observeTest('remove non-existent item does not change length', () {
47 map.remove('d'); 59 map.remove('d');
48 expect(map, {'a': 1, 'b': 2, 'c': 3}); 60 expect(map, {'a': 1, 'b': 2, 'c': 3});
49 deliverChangeRecords(); 61 performMicrotaskCheckpoint();
50 expectChanges(changes, null); 62 expectChanges(changes, null);
51 }); 63 });
52 64
53 test('set existing item does not change length', () { 65 observeTest('set existing item does not change length', () {
54 map['c'] = 9000; 66 map['c'] = 9000;
55 expect(map, {'a': 1, 'b': 2, 'c': 9000}); 67 expect(map, {'a': 1, 'b': 2, 'c': 9000});
56 deliverChangeRecords(); 68 performMicrotaskCheckpoint();
57 expectChanges(changes, []); 69 expectChanges(changes, []);
58 }); 70 });
59 71
60 test('clear changes length', () { 72 observeTest('clear changes length', () {
61 map.clear(); 73 map.clear();
62 expect(map, {}); 74 expect(map, {});
63 deliverChangeRecords(); 75 performMicrotaskCheckpoint();
64 expectChanges(changes, [_lengthChange]); 76 expectChanges(changes, [_lengthChange]);
65 }); 77 });
66 }); 78 });
67 79
68 group('observe item', () { 80 group('observe item', () {
69 81
70 ObservableMap map; 82 ObservableMap map;
71 List<ChangeRecord> changes; 83 List<ChangeRecord> changes;
72 84
73 setUp(() { 85 setUp(() {
74 map = toObservable({'a': 1, 'b': 2, 'c': 3}); 86 map = toObservable({'a': 1, 'b': 2, 'c': 3});
75 changes = null; 87 changes = null;
76 map.changes.listen((records) { 88 sub = map.changes.listen((records) {
77 changes = records.where((r) => r.changes('b')).toList(); 89 changes = records.where((r) => r.changes('b')).toList();
78 }); 90 });
79 }); 91 });
80 92
81 test('putIfAbsent new item does not change existing item', () { 93 tearDown(sharedTearDown);
94
95 observeTest('putIfAbsent new item does not change existing item', () {
82 map.putIfAbsent('d', () => 4); 96 map.putIfAbsent('d', () => 4);
83 expect(map, {'a': 1, 'b': 2, 'c': 3, 'd': 4}); 97 expect(map, {'a': 1, 'b': 2, 'c': 3, 'd': 4});
84 deliverChangeRecords(); 98 performMicrotaskCheckpoint();
85 expectChanges(changes, []); 99 expectChanges(changes, []);
86 }); 100 });
87 101
88 test('set item to null', () { 102 observeTest('set item to null', () {
89 map['b'] = null; 103 map['b'] = null;
90 expect(map, {'a': 1, 'b': null, 'c': 3}); 104 expect(map, {'a': 1, 'b': null, 'c': 3});
91 deliverChangeRecords(); 105 performMicrotaskCheckpoint();
92 expectChanges(changes, [_change('b')]); 106 expectChanges(changes, [_change('b')]);
93 }); 107 });
94 108
95 test('set item to value', () { 109 observeTest('set item to value', () {
96 map['b'] = 777; 110 map['b'] = 777;
97 expect(map, {'a': 1, 'b': 777, 'c': 3}); 111 expect(map, {'a': 1, 'b': 777, 'c': 3});
98 deliverChangeRecords(); 112 performMicrotaskCheckpoint();
99 expectChanges(changes, [_change('b')]); 113 expectChanges(changes, [_change('b')]);
100 }); 114 });
101 115
102 test('putIfAbsent does not change if already there', () { 116 observeTest('putIfAbsent does not change if already there', () {
103 map.putIfAbsent('b', () => 1234); 117 map.putIfAbsent('b', () => 1234);
104 expect(map, {'a': 1, 'b': 2, 'c': 3}); 118 expect(map, {'a': 1, 'b': 2, 'c': 3});
105 deliverChangeRecords(); 119 performMicrotaskCheckpoint();
106 expectChanges(changes, null); 120 expectChanges(changes, null);
107 }); 121 });
108 122
109 test('change a different item', () { 123 observeTest('change a different item', () {
110 map['c'] = 9000; 124 map['c'] = 9000;
111 expect(map, {'a': 1, 'b': 2, 'c': 9000}); 125 expect(map, {'a': 1, 'b': 2, 'c': 9000});
112 deliverChangeRecords(); 126 performMicrotaskCheckpoint();
113 expectChanges(changes, []); 127 expectChanges(changes, []);
114 }); 128 });
115 129
116 test('change the item', () { 130 observeTest('change the item', () {
117 map['b'] = 9001; 131 map['b'] = 9001;
118 map['b'] = 42; 132 map['b'] = 42;
119 expect(map, {'a': 1, 'b': 42, 'c': 3}); 133 expect(map, {'a': 1, 'b': 42, 'c': 3});
120 deliverChangeRecords(); 134 performMicrotaskCheckpoint();
121 expectChanges(changes, [_change('b'), _change('b')]); 135 expectChanges(changes, [_change('b'), _change('b')]);
122 }); 136 });
123 137
124 test('remove other items', () { 138 observeTest('remove other items', () {
125 map.remove('a'); 139 map.remove('a');
126 expect(map, {'b': 2, 'c': 3}); 140 expect(map, {'b': 2, 'c': 3});
127 deliverChangeRecords(); 141 performMicrotaskCheckpoint();
128 expectChanges(changes, []); 142 expectChanges(changes, []);
129 }); 143 });
130 144
131 test('remove the item', () { 145 observeTest('remove the item', () {
132 map.remove('b'); 146 map.remove('b');
133 expect(map, {'a': 1, 'c': 3}); 147 expect(map, {'a': 1, 'c': 3});
134 deliverChangeRecords(); 148 performMicrotaskCheckpoint();
135 expectChanges(changes, [_change('b', isRemove: true)]); 149 expectChanges(changes, [_change('b', isRemove: true)]);
136 }); 150 });
137 151
138 test('remove and add back', () { 152 observeTest('remove and add back', () {
139 map.remove('b'); 153 map.remove('b');
140 map['b'] = 2; 154 map['b'] = 2;
141 expect(map, {'a': 1, 'b': 2, 'c': 3}); 155 expect(map, {'a': 1, 'b': 2, 'c': 3});
142 deliverChangeRecords(); 156 performMicrotaskCheckpoint();
143 expectChanges(changes, 157 expectChanges(changes,
144 [_change('b', isRemove: true), _change('b', isInsert: true)]); 158 [_change('b', isRemove: true), _change('b', isInsert: true)]);
145 }); 159 });
146 }); 160 });
147 161
148 test('toString', () { 162 observeTest('toString', () {
149 var map = toObservable({'a': 1, 'b': 2}); 163 var map = toObservable({'a': 1, 'b': 2});
150 expect(map.toString(), '{a: 1, b: 2}'); 164 expect(map.toString(), '{a: 1, b: 2}');
151 }); 165 });
152 166
153 group('change records', () { 167 group('change records', () {
154 List<ChangeRecord> records; 168 List<ChangeRecord> records;
155 ObservableMap map; 169 ObservableMap map;
156 170
157 setUp(() { 171 setUp(() {
158 map = toObservable({'a': 1, 'b': 2}); 172 map = toObservable({'a': 1, 'b': 2});
159 records = null; 173 records = null;
160 map.changes.first.then((r) { records = r; }); 174 map.changes.first.then((r) { records = r; });
161 }); 175 });
162 176
163 test('read operations', () { 177 tearDown(sharedTearDown);
178
179 observeTest('read operations', () {
164 expect(map.length, 2); 180 expect(map.length, 2);
165 expect(map.isEmpty, false); 181 expect(map.isEmpty, false);
166 expect(map['a'], 1); 182 expect(map['a'], 1);
167 expect(map.containsKey(2), false); 183 expect(map.containsKey(2), false);
168 expect(map.containsValue(2), true); 184 expect(map.containsValue(2), true);
169 expect(map.containsKey('b'), true); 185 expect(map.containsKey('b'), true);
170 expect(map.keys.toList(), ['a', 'b']); 186 expect(map.keys.toList(), ['a', 'b']);
171 expect(map.values.toList(), [1, 2]); 187 expect(map.values.toList(), [1, 2]);
172 var copy = {}; 188 var copy = {};
173 map.forEach((k, v) { copy[k] = v; }); 189 map.forEach((k, v) { copy[k] = v; });
174 expect(copy, {'a': 1, 'b': 2}); 190 expect(copy, {'a': 1, 'b': 2});
175 deliverChangeRecords(); 191 performMicrotaskCheckpoint();
176 192
177 // no change from read-only operators 193 // no change from read-only operators
178 expect(records, null); 194 expect(records, null);
195
196 // Make a change so the subscription gets unregistered.
197 map.clear();
179 }); 198 });
180 199
181 test('putIfAbsent', () { 200 observeTest('putIfAbsent', () {
182 map.putIfAbsent('a', () => 42); 201 map.putIfAbsent('a', () => 42);
183 expect(map, {'a': 1, 'b': 2}); 202 expect(map, {'a': 1, 'b': 2});
184 203
185 map.putIfAbsent('c', () => 3); 204 map.putIfAbsent('c', () => 3);
186 expect(map, {'a': 1, 'b': 2, 'c': 3}); 205 expect(map, {'a': 1, 'b': 2, 'c': 3});
187 206
188 deliverChangeRecords(); 207 performMicrotaskCheckpoint();
189 expectChanges(records, [ 208 expectChanges(records, [
190 _lengthChange, 209 _lengthChange,
191 _change('c', isInsert: true), 210 _change('c', isInsert: true),
192 ]); 211 ]);
193 }); 212 });
194 213
195 test('[]=', () { 214 observeTest('[]=', () {
196 map['a'] = 42; 215 map['a'] = 42;
197 expect(map, {'a': 42, 'b': 2}); 216 expect(map, {'a': 42, 'b': 2});
198 217
199 map['c'] = 3; 218 map['c'] = 3;
200 expect(map, {'a': 42, 'b': 2, 'c': 3}); 219 expect(map, {'a': 42, 'b': 2, 'c': 3});
201 220
202 deliverChangeRecords(); 221 performMicrotaskCheckpoint();
203 expectChanges(records, [ 222 expectChanges(records, [
204 _change('a'), 223 _change('a'),
205 _lengthChange, 224 _lengthChange,
206 _change('c', isInsert: true) 225 _change('c', isInsert: true)
207 ]); 226 ]);
208 }); 227 });
209 228
210 test('remove', () { 229 observeTest('remove', () {
211 map.remove('b'); 230 map.remove('b');
212 expect(map, {'a': 1}); 231 expect(map, {'a': 1});
213 232
214 deliverChangeRecords(); 233 performMicrotaskCheckpoint();
215 expectChanges(records, [ 234 expectChanges(records, [
216 _change('b', isRemove: true), 235 _change('b', isRemove: true),
217 _lengthChange, 236 _lengthChange,
218 ]); 237 ]);
219 }); 238 });
220 239
221 test('clear', () { 240 observeTest('clear', () {
222 map.clear(); 241 map.clear();
223 expect(map, {}); 242 expect(map, {});
224 243
225 deliverChangeRecords(); 244 performMicrotaskCheckpoint();
226 expectChanges(records, [ 245 expectChanges(records, [
227 _change('a', isRemove: true), 246 _change('a', isRemove: true),
228 _change('b', isRemove: true), 247 _change('b', isRemove: true),
229 _lengthChange, 248 _lengthChange,
230 ]); 249 ]);
231 }); 250 });
232 }); 251 });
233 } 252 }
234 253
235 254
236 const _LENGTH = const Symbol('length'); 255 const _LENGTH = const Symbol('length');
237 256
238 final _lengthChange = new PropertyChangeRecord(_LENGTH); 257 final _lengthChange = new PropertyChangeRecord(_LENGTH);
239 258
240 _change(key, {isInsert: false, isRemove: false}) => 259 _change(key, {isInsert: false, isRemove: false}) =>
241 new MapChangeRecord(key, isInsert: isInsert, isRemove: isRemove); 260 new MapChangeRecord(key, isInsert: isInsert, isRemove: isRemove);
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698