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

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

Issue 132403010: big update to observe, template_binding, polymer (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 6 years, 10 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
« no previous file with comments | « pkg/observe/test/observe_test_utils.dart ('k') | pkg/pkg.status » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 'observe_test_utils.dart'; 8 import 'observe_test_utils.dart';
8 9
9 // This file contains code ported from: 10 // This file contains code ported from:
10 // https://github.com/rafaelw/ChangeSummary/blob/master/tests/test.js 11 // https://github.com/rafaelw/ChangeSummary/blob/master/tests/test.js
11 12
12 main() { 13 main() => dirtyCheckZone().run(() {
13 group('PathObserver', observePathTests); 14 group('PathObserver', observePathTests);
14 } 15
15 16 group('PropertyPath', () {
16 observePath(obj, path) => new PathObserver(obj, path); 17 test('toString length', () {
18 expectPath(p, str, len) {
19 var path = new PropertyPath(p);
20 expect(path.toString(), str);
21 expect(path.length, len, reason: 'expected path length $len for $path');
22 }
23
24 expectPath('/foo', '<invalid path>', 0);
25 expectPath('abc', 'abc', 1);
26 expectPath('a.b.c', 'a.b.c', 3);
27 expectPath('a.b.c ', 'a.b.c', 3);
28 expectPath(' a.b.c', 'a.b.c', 3);
29 expectPath(' a.b.c ', 'a.b.c', 3);
30 expectPath('1.abc', '1.abc', 2);
31 expectPath([#qux], 'qux', 1);
32 expectPath([1, #foo, #bar], '1.foo.bar', 3);
33 });
34
35 test('caching and ==', () {
36 var start = new PropertyPath('abc.0');
37 for (int i = 1; i <= 100; i++) {
38 expect(identical(new PropertyPath('abc.0'), start), true,
39 reason: 'should return identical path');
40
41 var p = new PropertyPath('abc.$i');
42 expect(identical(p, start), false,
43 reason: 'different paths should not be merged');
44 }
45 var end = new PropertyPath('abc.0');
46 expect(identical(end, start), false,
47 reason: 'first entry expired');
48 expect(end, start, reason: 'different instances are equal');
49 });
50
51 test('hashCode equal', () {
52 var a = new PropertyPath([#foo, 2, #bar]);
53 var b = new PropertyPath('foo.2.bar');
54 expect(identical(a, b), false, reason: 'only strings cached');
55 expect(a, b, reason: 'same paths are equal');
56 expect(a.hashCode, b.hashCode, reason: 'equal hashCodes');
57 });
58
59 test('hashCode not equal', () {
60 expect(2.hashCode, isNot(3.hashCode),
61 reason: 'test depends on 2 and 3 having different hashcodes');
62
63 var a = new PropertyPath([2]);
64 var b = new PropertyPath([3]);
65 expect(a, isNot(b), reason: 'different paths');
66 expect(a.hashCode, isNot(b.hashCode), reason: 'different hashCodes');
67 });
68 });
69 });
70
17 71
18 observePathTests() { 72 observePathTests() {
19 observeTest('Degenerate Values', () { 73 test('Degenerate Values', () {
20 expect(observePath(null, '').value, null); 74 expect(new PathObserver(null, '').value, null);
21 expect(observePath(123, '').value, 123); 75 expect(new PathObserver(123, '').value, 123);
22 expect(observePath(123, 'foo.bar.baz').value, null); 76 expect(new PathObserver(123, 'foo.bar.baz').value, null);
23 77
24 // shouldn't throw: 78 // shouldn't throw:
25 observePath(123, '').changes.listen((_) {}).cancel(); 79 new PathObserver(123, '')..open((_) {})..close();
26 observePath(null, '').value = null; 80 new PropertyPath('').setValueFrom(null, null);
27 observePath(123, '').value = 42; 81 new PropertyPath('').setValueFrom(123, 42);
28 observePath(123, 'foo.bar.baz').value = 42; 82 new PropertyPath('foo.bar.baz').setValueFrom(123, 42);
29 83
30 var foo = {}; 84 var foo = {};
31 expect(observePath(foo, '').value, foo); 85 expect(new PathObserver(foo, '').value, foo);
32 86
33 foo = new Object(); 87 foo = new Object();
34 expect(observePath(foo, '').value, foo); 88 expect(new PathObserver(foo, '').value, foo);
35 89
36 expect(observePath(foo, 'a/3!').value, null); 90 expect(new PathObserver(foo, 'a/3!').value, null);
37 }); 91 });
38 92
39 observeTest('get value at path ObservableBox', () { 93 test('get value at path ObservableBox', () {
40 var obj = new ObservableBox(new ObservableBox(new ObservableBox(1))); 94 var obj = new ObservableBox(new ObservableBox(new ObservableBox(1)));
41 95
42 expect(observePath(obj, '').value, obj); 96 expect(new PathObserver(obj, '').value, obj);
43 expect(observePath(obj, 'value').value, obj.value); 97 expect(new PathObserver(obj, 'value').value, obj.value);
44 expect(observePath(obj, 'value.value').value, obj.value.value); 98 expect(new PathObserver(obj, 'value.value').value, obj.value.value);
45 expect(observePath(obj, 'value.value.value').value, 1); 99 expect(new PathObserver(obj, 'value.value.value').value, 1);
46 100
47 obj.value.value.value = 2; 101 obj.value.value.value = 2;
48 expect(observePath(obj, 'value.value.value').value, 2); 102 expect(new PathObserver(obj, 'value.value.value').value, 2);
49 103
50 obj.value.value = new ObservableBox(3); 104 obj.value.value = new ObservableBox(3);
51 expect(observePath(obj, 'value.value.value').value, 3); 105 expect(new PathObserver(obj, 'value.value.value').value, 3);
52 106
53 obj.value = new ObservableBox(4); 107 obj.value = new ObservableBox(4);
54 expect(observePath(obj, 'value.value.value').value, null); 108 expect(new PathObserver(obj, 'value.value.value').value, null);
55 expect(observePath(obj, 'value.value').value, 4); 109 expect(new PathObserver(obj, 'value.value').value, 4);
56 }); 110 });
57 111
58 112
59 observeTest('get value at path ObservableMap', () { 113 test('get value at path ObservableMap', () {
60 var obj = toObservable({'a': {'b': {'c': 1}}}); 114 var obj = toObservable({'a': {'b': {'c': 1}}});
61 115
62 expect(observePath(obj, '').value, obj); 116 expect(new PathObserver(obj, '').value, obj);
63 expect(observePath(obj, 'a').value, obj['a']); 117 expect(new PathObserver(obj, 'a').value, obj['a']);
64 expect(observePath(obj, 'a.b').value, obj['a']['b']); 118 expect(new PathObserver(obj, 'a.b').value, obj['a']['b']);
65 expect(observePath(obj, 'a.b.c').value, 1); 119 expect(new PathObserver(obj, 'a.b.c').value, 1);
66 120
67 obj['a']['b']['c'] = 2; 121 obj['a']['b']['c'] = 2;
68 expect(observePath(obj, 'a.b.c').value, 2); 122 expect(new PathObserver(obj, 'a.b.c').value, 2);
69 123
70 obj['a']['b'] = toObservable({'c': 3}); 124 obj['a']['b'] = toObservable({'c': 3});
71 expect(observePath(obj, 'a.b.c').value, 3); 125 expect(new PathObserver(obj, 'a.b.c').value, 3);
72 126
73 obj['a'] = toObservable({'b': 4}); 127 obj['a'] = toObservable({'b': 4});
74 expect(observePath(obj, 'a.b.c').value, null); 128 expect(new PathObserver(obj, 'a.b.c').value, null);
75 expect(observePath(obj, 'a.b').value, 4); 129 expect(new PathObserver(obj, 'a.b').value, 4);
76 }); 130 });
77 131
78 observeTest('set value at path', () { 132 test('set value at path', () {
79 var obj = toObservable({}); 133 var obj = toObservable({});
80 observePath(obj, 'foo').value = 3; 134 new PropertyPath('foo').setValueFrom(obj, 3);
81 expect(obj['foo'], 3); 135 expect(obj['foo'], 3);
82 136
83 var bar = toObservable({ 'baz': 3 }); 137 var bar = toObservable({ 'baz': 3 });
84 observePath(obj, 'bar').value = bar; 138 new PropertyPath('bar').setValueFrom(obj, bar);
85 expect(obj['bar'], bar); 139 expect(obj['bar'], bar);
86 140
87 observePath(obj, 'bar.baz.bat').value = 'not here'; 141 new PropertyPath('bar.baz.bat').setValueFrom(obj, 'not here');
88 expect(observePath(obj, 'bar.baz.bat').value, null); 142 expect(new PathObserver(obj, 'bar.baz.bat').value, null);
89 }); 143 });
90 144
91 observeTest('set value back to same', () { 145 test('set value back to same', () {
92 var obj = toObservable({}); 146 var obj = toObservable({});
93 var path = observePath(obj, 'foo'); 147 var path = new PathObserver(obj, 'foo');
94 var values = []; 148 var values = [];
95 path.changes.listen((_) { values.add(path.value); }); 149 path.open((x) {
150 expect(x, path.value, reason: 'callback should get current value');
151 values.add(x);
152 });
96 153
97 path.value = 3; 154 path.value = 3;
98 expect(obj['foo'], 3); 155 expect(obj['foo'], 3);
99 expect(path.value, 3); 156 expect(path.value, 3);
100 157
101 observePath(obj, 'foo').value = 2; 158 new PropertyPath('foo').setValueFrom(obj, 2);
102 performMicrotaskCheckpoint(); 159 return new Future(() {
103 expect(path.value, 2); 160 expect(path.value, 2);
104 expect(observePath(obj, 'foo').value, 2); 161 expect(new PathObserver(obj, 'foo').value, 2);
105 162
106 observePath(obj, 'foo').value = 3; 163 new PropertyPath('foo').setValueFrom(obj, 3);
107 performMicrotaskCheckpoint(); 164 }).then(newMicrotask).then((_) {
108 expect(path.value, 3); 165 expect(path.value, 3);
109 166
110 performMicrotaskCheckpoint(); 167 }).then(newMicrotask).then((_) {
111 expect(values, [2, 3]); 168 expect(values, [2, 3]);
112 }); 169 });
113 170 });
114 observeTest('Observe and Unobserve - Paths', () { 171
172 test('Observe and Unobserve - Paths', () {
115 var arr = toObservable({}); 173 var arr = toObservable({});
116 174
117 arr['foo'] = 'bar'; 175 arr['foo'] = 'bar';
118 var fooValues = []; 176 var fooValues = [];
119 var fooPath = observePath(arr, 'foo'); 177 var fooPath = new PathObserver(arr, 'foo');
120 var fooSub = fooPath.changes.listen((_) { 178 fooPath.open(fooValues.add);
121 fooValues.add(fooPath.value);
122 });
123 arr['foo'] = 'baz'; 179 arr['foo'] = 'baz';
124 arr['bat'] = 'bag'; 180 arr['bat'] = 'bag';
125 var batValues = []; 181 var batValues = [];
126 var batPath = observePath(arr, 'bat'); 182 var batPath = new PathObserver(arr, 'bat');
127 var batSub = batPath.changes.listen((_) { 183 batPath.open(batValues.add);
128 batValues.add(batPath.value); 184
129 }); 185 return new Future(() {
130 186 expect(fooValues, ['baz']);
131 performMicrotaskCheckpoint(); 187 expect(batValues, []);
132 expect(fooValues, ['baz']); 188
133 expect(batValues, []); 189 arr['foo'] = 'bar';
134 190 fooPath.close();
135 arr['foo'] = 'bar'; 191 arr['bat'] = 'boo';
136 fooSub.cancel(); 192 batPath.close();
137 arr['bat'] = 'boo'; 193 arr['bat'] = 'boot';
138 batSub.cancel(); 194
139 arr['bat'] = 'boot'; 195 }).then(newMicrotask).then((_) {
140 196 expect(fooValues, ['baz']);
141 performMicrotaskCheckpoint(); 197 expect(batValues, []);
142 expect(fooValues, ['baz']); 198 });
143 expect(batValues, []); 199 });
144 }); 200
145 201 test('Path Value With Indices', () {
146 observeTest('Path Value With Indices', () {
147 var model = toObservable([]); 202 var model = toObservable([]);
148 var path = observePath(model, '0'); 203 var path = new PathObserver(model, '0');
149 path.changes.listen(expectAsync1((_) { 204 path.open(expectAsync1((x) {
150 expect(path.value, 123); 205 expect(path.value, 123);
206 expect(x, 123);
151 })); 207 }));
152 model.add(123); 208 model.add(123);
153 }); 209 });
154 210
155 group('ObservableList', () { 211 group('ObservableList', () {
156 observeTest('isNotEmpty', () { 212 test('isNotEmpty', () {
157 var model = new ObservableList(); 213 var model = new ObservableList();
158 var path = observePath(model, 'isNotEmpty'); 214 var path = new PathObserver(model, 'isNotEmpty');
159 expect(path.value, false); 215 expect(path.value, false);
160 216
161 var future = path.changes.first.then((_) { 217 path.open(expectAsync1((_) {
162 expect(path.value, true); 218 expect(path.value, true);
163 }); 219 }));
164 model.add(123); 220 model.add(123);
165 221 });
166 return future; 222
167 }); 223 test('isEmpty', () {
168
169 observeTest('isEmpty', () {
170 var model = new ObservableList(); 224 var model = new ObservableList();
171 var path = observePath(model, 'isEmpty'); 225 var path = new PathObserver(model, 'isEmpty');
172 expect(path.value, true); 226 expect(path.value, true);
173 227
174 var future = path.changes.first.then((_) { 228 path.open(expectAsync1((_) {
175 expect(path.value, false); 229 expect(path.value, false);
176 }); 230 }));
177 model.add(123); 231 model.add(123);
178
179 return future;
180 }); 232 });
181 }); 233 });
182 234
183 for (var createModel in [() => new TestModel(), () => new WatcherModel()]) { 235 for (var createModel in [() => new TestModel(), () => new WatcherModel()]) {
184 observeTest('Path Observation - ${createModel().runtimeType}', () { 236 test('Path Observation - ${createModel().runtimeType}', () {
185 var model = createModel()..a = 237 var model = createModel()..a =
186 (createModel()..b = (createModel()..c = 'hello, world')); 238 (createModel()..b = (createModel()..c = 'hello, world'));
187 239
188 var path = observePath(model, 'a.b.c'); 240 var path = new PathObserver(model, 'a.b.c');
189 var lastValue = null; 241 var lastValue = null;
190 var sub = path.changes.listen((_) { lastValue = path.value; }); 242 path.open((x) { lastValue = x; });
191 243
192 model.a.b.c = 'hello, mom'; 244 model.a.b.c = 'hello, mom';
193 245
194 expect(lastValue, null); 246 expect(lastValue, null);
195 performMicrotaskCheckpoint(); 247 return new Future(() {
196 expect(lastValue, 'hello, mom'); 248 expect(lastValue, 'hello, mom');
197 249
198 model.a.b = createModel()..c = 'hello, dad'; 250 model.a.b = createModel()..c = 'hello, dad';
199 performMicrotaskCheckpoint(); 251 }).then(newMicrotask).then((_) {
200 expect(lastValue, 'hello, dad'); 252 expect(lastValue, 'hello, dad');
201 253
202 model.a = createModel()..b = 254 model.a = createModel()..b =
203 (createModel()..c = 'hello, you'); 255 (createModel()..c = 'hello, you');
204 performMicrotaskCheckpoint(); 256 }).then(newMicrotask).then((_) {
205 expect(lastValue, 'hello, you'); 257 expect(lastValue, 'hello, you');
206 258
207 model.a.b = 1; 259 model.a.b = 1;
208 performMicrotaskCheckpoint(); 260 }).then(newMicrotask).then((_) {
209 expect(lastValue, null); 261 expect(lastValue, null);
210 262
211 // Stop observing 263 // Stop observing
212 sub.cancel(); 264 path.close();
213 265
214 model.a.b = createModel()..c = 'hello, back again -- but not observing'; 266 model.a.b = createModel()..c = 'hello, back again -- but not observing';
215 performMicrotaskCheckpoint(); 267 }).then(newMicrotask).then((_) {
216 expect(lastValue, null); 268 expect(lastValue, null);
217 269
218 // Resume observing 270 // Resume observing
219 sub = path.changes.listen((_) { lastValue = path.value; }); 271 new PathObserver(model, 'a.b.c').open((x) { lastValue = x; });
220 272
221 model.a.b.c = 'hello. Back for reals'; 273 model.a.b.c = 'hello. Back for reals';
222 performMicrotaskCheckpoint(); 274 }).then(newMicrotask).then((_) {
223 expect(lastValue, 'hello. Back for reals'); 275 expect(lastValue, 'hello. Back for reals');
276 });
224 }); 277 });
225 } 278 }
226 279
227 observeTest('observe map', () { 280 test('observe map', () {
228 var model = toObservable({'a': 1}); 281 var model = toObservable({'a': 1});
229 var path = observePath(model, 'a'); 282 var path = new PathObserver(model, 'a');
230 283
231 var values = [path.value]; 284 var values = [path.value];
232 var sub = path.changes.listen((_) { values.add(path.value); }); 285 path.open(values.add);
233 expect(values, [1]); 286 expect(values, [1]);
234 287
235 model['a'] = 2; 288 model['a'] = 2;
236 performMicrotaskCheckpoint(); 289 return new Future(() {
237 expect(values, [1, 2]); 290 expect(values, [1, 2]);
238 291
239 sub.cancel(); 292 path.close();
240 model['a'] = 3; 293 model['a'] = 3;
241 performMicrotaskCheckpoint(); 294 }).then(newMicrotask).then((_) {
242 expect(values, [1, 2]); 295 expect(values, [1, 2]);
243 }); 296 });
244 297 });
245 observeTest('errors thrown from getter/setter', () { 298
299 test('errors thrown from getter/setter', () {
246 var model = new ObjectWithErrors(); 300 var model = new ObjectWithErrors();
247 var observer = new PathObserver(model, 'foo'); 301 var observer = new PathObserver(model, 'foo');
248 302
249 expect(() => observer.value, throws); 303 expect(() => observer.value, throws);
250 expect(model.getFooCalled, 1); 304 expect(model.getFooCalled, 1);
251 305
252 expect(() { observer.value = 123; }, throws); 306 expect(() { observer.value = 123; }, throws);
253 expect(model.setFooCalled, [123]); 307 expect(model.setFooCalled, [123]);
254 }); 308 });
255 309
256 observeTest('object with noSuchMethod', () { 310 test('object with noSuchMethod', () {
257 var model = new NoSuchMethodModel(); 311 var model = new NoSuchMethodModel();
258 var observer = new PathObserver(model, 'foo'); 312 var observer = new PathObserver(model, 'foo');
259 313
260 expect(observer.value, 42); 314 expect(observer.value, 42);
261 observer.value = 'hi'; 315 observer.value = 'hi';
262 expect(model._foo, 'hi'); 316 expect(model._foo, 'hi');
263 expect(observer.value, 'hi'); 317 expect(observer.value, 'hi');
264 318
265 expect(model.log, [#foo, const Symbol('foo='), #foo]); 319 expect(model.log, [#foo, const Symbol('foo='), #foo]);
266 320
267 // These shouldn't throw 321 // These shouldn't throw
268 observer = new PathObserver(model, 'bar'); 322 observer = new PathObserver(model, 'bar');
269 expect(observer.value, null, reason: 'path not found'); 323 expect(observer.value, null, reason: 'path not found');
270 observer.value = 42; 324 observer.value = 42;
271 expect(observer.value, null, reason: 'path not found'); 325 expect(observer.value, null, reason: 'path not found');
272 }); 326 });
273 327
274 observeTest('object with indexer', () { 328 test('object with indexer', () {
275 var model = new IndexerModel(); 329 var model = new IndexerModel();
276 var observer = new PathObserver(model, 'foo'); 330 var observer = new PathObserver(model, 'foo');
277 331
278 expect(observer.value, 42); 332 expect(observer.value, 42);
279 expect(model.log, ['[] foo']); 333 expect(model.log, ['[] foo']);
280 model.log.clear(); 334 model.log.clear();
281 335
282 observer.value = 'hi'; 336 observer.value = 'hi';
283 expect(model.log, ['[]= foo hi']); 337 expect(model.log, ['[]= foo hi']);
284 expect(model._foo, 'hi'); 338 expect(model._foo, 'hi');
(...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after
371 425
372 class WatcherModel extends Observable { 426 class WatcherModel extends Observable {
373 // TODO(jmesserly): dart2js does not let these be on the same line: 427 // TODO(jmesserly): dart2js does not let these be on the same line:
374 // @observable var a, b, c; 428 // @observable var a, b, c;
375 @observable var a; 429 @observable var a;
376 @observable var b; 430 @observable var b;
377 @observable var c; 431 @observable var c;
378 432
379 WatcherModel(); 433 WatcherModel();
380 } 434 }
OLDNEW
« no previous file with comments | « pkg/observe/test/observe_test_utils.dart ('k') | pkg/pkg.status » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698