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

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

Issue 210823005: Revert "Change path-observer to lookup properties aggressively and report errors" (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 6 years, 9 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/lib/src/path_observer.dart ('k') | pkg/polymer_expressions/lib/eval.dart » ('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 'dart:async';
6 import 'package:observe/observe.dart'; 6 import 'package:observe/observe.dart';
7 import 'package:unittest/unittest.dart'; 7 import 'package:unittest/unittest.dart';
8 import 'observe_test_utils.dart'; 8 import 'observe_test_utils.dart';
9 9
10 // This file contains code ported from: 10 // This file contains code ported from:
11 // https://github.com/rafaelw/ChangeSummary/blob/master/tests/test.js 11 // https://github.com/rafaelw/ChangeSummary/blob/master/tests/test.js
12 // Dart note: getting invalid properties is an error, unlike in JS where it 12
13 // returns undefined. This difference comes up where we check for _throwsNSM in
14 // the tests below.
15 main() => dirtyCheckZone().run(() { 13 main() => dirtyCheckZone().run(() {
16 group('PathObserver', observePathTests); 14 group('PathObserver', observePathTests);
17 15
18 group('PropertyPath', () { 16 group('PropertyPath', () {
19 test('toString length', () { 17 test('toString length', () {
20 expectPath(p, str, len) { 18 expectPath(p, str, len) {
21 var path = new PropertyPath(p); 19 var path = new PropertyPath(p);
22 expect(path.toString(), str); 20 expect(path.toString(), str);
23 expect(path.length, len, reason: 'expected path length $len for $path'); 21 expect(path.length, len, reason: 'expected path length $len for $path');
24 } 22 }
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
63 reason: 'test depends on 2 and 3 having different hashcodes'); 61 reason: 'test depends on 2 and 3 having different hashcodes');
64 62
65 var a = new PropertyPath([2]); 63 var a = new PropertyPath([2]);
66 var b = new PropertyPath([3]); 64 var b = new PropertyPath([3]);
67 expect(a, isNot(b), reason: 'different paths'); 65 expect(a, isNot(b), reason: 'different paths');
68 expect(a.hashCode, isNot(b.hashCode), reason: 'different hashCodes'); 66 expect(a.hashCode, isNot(b.hashCode), reason: 'different hashCodes');
69 }); 67 });
70 }); 68 });
71 }); 69 });
72 70
71
73 observePathTests() { 72 observePathTests() {
74 test('Degenerate Values', () { 73 test('Degenerate Values', () {
75 expect(new PathObserver(null, '').value, null); 74 expect(new PathObserver(null, '').value, null);
76 expect(new PathObserver(123, '').value, 123); 75 expect(new PathObserver(123, '').value, 123);
77 expect(() => new PathObserver(123, 'foo.bar.baz').value, _throwsNSM('foo')); 76 expect(new PathObserver(123, 'foo.bar.baz').value, null);
78 77
79 // shouldn't throw: 78 // shouldn't throw:
80 new PathObserver(123, '')..open((_) {})..close(); 79 new PathObserver(123, '')..open((_) {})..close();
81 new PropertyPath('').setValueFrom(null, null); 80 new PropertyPath('').setValueFrom(null, null);
82 new PropertyPath('').setValueFrom(123, 42); 81 new PropertyPath('').setValueFrom(123, 42);
83 expect(() => new PropertyPath('foo.bar.baz').setValueFrom(123, 42), 82 new PropertyPath('foo.bar.baz').setValueFrom(123, 42);
84 _throwsNSM('foo')); 83
85 var foo = {}; 84 var foo = {};
86 expect(new PathObserver(foo, '').value, foo); 85 expect(new PathObserver(foo, '').value, foo);
87 86
88 foo = new Object(); 87 foo = new Object();
89 expect(new PathObserver(foo, '').value, foo); 88 expect(new PathObserver(foo, '').value, foo);
90 89
91 expect(new PathObserver(foo, 'a/3!').value, null); 90 expect(new PathObserver(foo, 'a/3!').value, null);
92 }); 91 });
93 92
94 test('get value at path ObservableBox', () { 93 test('get value at path ObservableBox', () {
95 var obj = new ObservableBox(new ObservableBox(new ObservableBox(1))); 94 var obj = new ObservableBox(new ObservableBox(new ObservableBox(1)));
96 95
97 expect(new PathObserver(obj, '').value, obj); 96 expect(new PathObserver(obj, '').value, obj);
98 expect(new PathObserver(obj, 'value').value, obj.value); 97 expect(new PathObserver(obj, 'value').value, obj.value);
99 expect(new PathObserver(obj, 'value.value').value, obj.value.value); 98 expect(new PathObserver(obj, 'value.value').value, obj.value.value);
100 expect(new PathObserver(obj, 'value.value.value').value, 1); 99 expect(new PathObserver(obj, 'value.value.value').value, 1);
101 100
102 obj.value.value.value = 2; 101 obj.value.value.value = 2;
103 expect(new PathObserver(obj, 'value.value.value').value, 2); 102 expect(new PathObserver(obj, 'value.value.value').value, 2);
104 103
105 obj.value.value = new ObservableBox(3); 104 obj.value.value = new ObservableBox(3);
106 expect(new PathObserver(obj, 'value.value.value').value, 3); 105 expect(new PathObserver(obj, 'value.value.value').value, 3);
107 106
108 obj.value = new ObservableBox(4); 107 obj.value = new ObservableBox(4);
109 expect(() => new PathObserver(obj, 'value.value.value').value, 108 expect(new PathObserver(obj, 'value.value.value').value, null);
110 _throwsNSM('value'));
111 expect(new PathObserver(obj, 'value.value').value, 4); 109 expect(new PathObserver(obj, 'value.value').value, 4);
112 }); 110 });
113 111
114 112
115 test('get value at path ObservableMap', () { 113 test('get value at path ObservableMap', () {
116 var obj = toObservable({'a': {'b': {'c': 1}}}); 114 var obj = toObservable({'a': {'b': {'c': 1}}});
117 115
118 expect(new PathObserver(obj, '').value, obj); 116 expect(new PathObserver(obj, '').value, obj);
119 expect(new PathObserver(obj, 'a').value, obj['a']); 117 expect(new PathObserver(obj, 'a').value, obj['a']);
120 expect(new PathObserver(obj, 'a.b').value, obj['a']['b']); 118 expect(new PathObserver(obj, 'a.b').value, obj['a']['b']);
121 expect(new PathObserver(obj, 'a.b.c').value, 1); 119 expect(new PathObserver(obj, 'a.b.c').value, 1);
122 120
123 obj['a']['b']['c'] = 2; 121 obj['a']['b']['c'] = 2;
124 expect(new PathObserver(obj, 'a.b.c').value, 2); 122 expect(new PathObserver(obj, 'a.b.c').value, 2);
125 123
126 obj['a']['b'] = toObservable({'c': 3}); 124 obj['a']['b'] = toObservable({'c': 3});
127 expect(new PathObserver(obj, 'a.b.c').value, 3); 125 expect(new PathObserver(obj, 'a.b.c').value, 3);
128 126
129 obj['a'] = toObservable({'b': 4}); 127 obj['a'] = toObservable({'b': 4});
130 expect(() => new PathObserver(obj, 'a.b.c').value, _throwsNSM('c')); 128 expect(new PathObserver(obj, 'a.b.c').value, null);
131 expect(new PathObserver(obj, 'a.b').value, 4); 129 expect(new PathObserver(obj, 'a.b').value, 4);
132 }); 130 });
133 131
134 test('set value at path', () { 132 test('set value at path', () {
135 var obj = toObservable({}); 133 var obj = toObservable({});
136 new PropertyPath('foo').setValueFrom(obj, 3); 134 new PropertyPath('foo').setValueFrom(obj, 3);
137 expect(obj['foo'], 3); 135 expect(obj['foo'], 3);
138 136
139 var bar = toObservable({ 'baz': 3 }); 137 var bar = toObservable({ 'baz': 3 });
140 new PropertyPath('bar').setValueFrom(obj, bar); 138 new PropertyPath('bar').setValueFrom(obj, bar);
141 expect(obj['bar'], bar); 139 expect(obj['bar'], bar);
142 140
143 expect(() => new PropertyPath('bar.baz.bat').setValueFrom(obj, 'not here'), 141 new PropertyPath('bar.baz.bat').setValueFrom(obj, 'not here');
144 _throwsNSM('bat=')); 142 expect(new PathObserver(obj, 'bar.baz.bat').value, null);
145 expect(() => new PathObserver(obj, 'bar.baz.bat').value, _throwsNSM('bat'));
146 }); 143 });
147 144
148 test('set value back to same', () { 145 test('set value back to same', () {
149 var obj = toObservable({}); 146 var obj = toObservable({});
150 var path = new PathObserver(obj, 'foo'); 147 var path = new PathObserver(obj, 'foo');
151 var values = []; 148 var values = [];
152 path.open((x) { 149 path.open((x) {
153 expect(x, path.value, reason: 'callback should get current value'); 150 expect(x, path.value, reason: 'callback should get current value');
154 values.add(x); 151 values.add(x);
155 }); 152 });
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after
235 }); 232 });
236 }); 233 });
237 234
238 for (var createModel in [() => new TestModel(), () => new WatcherModel()]) { 235 for (var createModel in [() => new TestModel(), () => new WatcherModel()]) {
239 test('Path Observation - ${createModel().runtimeType}', () { 236 test('Path Observation - ${createModel().runtimeType}', () {
240 var model = createModel()..a = 237 var model = createModel()..a =
241 (createModel()..b = (createModel()..c = 'hello, world')); 238 (createModel()..b = (createModel()..c = 'hello, world'));
242 239
243 var path = new PathObserver(model, 'a.b.c'); 240 var path = new PathObserver(model, 'a.b.c');
244 var lastValue = null; 241 var lastValue = null;
245 var errorSeen = false; 242 path.open((x) { lastValue = x; });
246 runZoned(() {
247 path.open((x) { lastValue = x; });
248 }, onError: (e) {
249 expect(e, _isNoSuchMethodOf('c'));
250 errorSeen = true;
251 });
252 243
253 model.a.b.c = 'hello, mom'; 244 model.a.b.c = 'hello, mom';
254 245
255 expect(lastValue, null); 246 expect(lastValue, null);
256 return new Future(() { 247 return new Future(() {
257 expect(lastValue, 'hello, mom'); 248 expect(lastValue, 'hello, mom');
258 249
259 model.a.b = createModel()..c = 'hello, dad'; 250 model.a.b = createModel()..c = 'hello, dad';
260 }).then(newMicrotask).then((_) { 251 }).then(newMicrotask).then((_) {
261 expect(lastValue, 'hello, dad'); 252 expect(lastValue, 'hello, dad');
262 253
263 model.a = createModel()..b = 254 model.a = createModel()..b =
264 (createModel()..c = 'hello, you'); 255 (createModel()..c = 'hello, you');
265 }).then(newMicrotask).then((_) { 256 }).then(newMicrotask).then((_) {
266 expect(lastValue, 'hello, you'); 257 expect(lastValue, 'hello, you');
267 258
268 model.a.b = 1; 259 model.a.b = 1;
269 expect(errorSeen, isFalse);
270 }).then(newMicrotask).then((_) { 260 }).then(newMicrotask).then((_) {
271 expect(errorSeen, isTrue); 261 expect(lastValue, null);
272 expect(lastValue, 'hello, you');
273 262
274 // Stop observing 263 // Stop observing
275 path.close(); 264 path.close();
276 265
277 model.a.b = createModel()..c = 'hello, back again -- but not observing'; 266 model.a.b = createModel()..c = 'hello, back again -- but not observing';
278 }).then(newMicrotask).then((_) { 267 }).then(newMicrotask).then((_) {
279 expect(lastValue, 'hello, you'); 268 expect(lastValue, null);
280 269
281 // Resume observing 270 // Resume observing
282 new PathObserver(model, 'a.b.c').open((x) { lastValue = x; }); 271 new PathObserver(model, 'a.b.c').open((x) { lastValue = x; });
283 272
284 model.a.b.c = 'hello. Back for reals'; 273 model.a.b.c = 'hello. Back for reals';
285 }).then(newMicrotask).then((_) { 274 }).then(newMicrotask).then((_) {
286 expect(lastValue, 'hello. Back for reals'); 275 expect(lastValue, 'hello. Back for reals');
287 }); 276 });
288 }); 277 });
289 } 278 }
(...skipping 14 matching lines...) Expand all
304 model['a'] = 3; 293 model['a'] = 3;
305 }).then(newMicrotask).then((_) { 294 }).then(newMicrotask).then((_) {
306 expect(values, [1, 2]); 295 expect(values, [1, 2]);
307 }); 296 });
308 }); 297 });
309 298
310 test('errors thrown from getter/setter', () { 299 test('errors thrown from getter/setter', () {
311 var model = new ObjectWithErrors(); 300 var model = new ObjectWithErrors();
312 var observer = new PathObserver(model, 'foo'); 301 var observer = new PathObserver(model, 'foo');
313 302
314 expect(() => observer.value, _throwsNSM('bar')); 303 expect(() => observer.value, throws);
315 expect(model.getFooCalled, 1); 304 expect(model.getFooCalled, 1);
316 305
317 expect(() { observer.value = 123; }, _throwsNSM('bar=')); 306 expect(() { observer.value = 123; }, throws);
318 expect(model.setFooCalled, [123]); 307 expect(model.setFooCalled, [123]);
319 }); 308 });
320 309
321 test('object with noSuchMethod', () { 310 test('object with noSuchMethod', () {
322 var model = new NoSuchMethodModel(); 311 var model = new NoSuchMethodModel();
323 var observer = new PathObserver(model, 'foo'); 312 var observer = new PathObserver(model, 'foo');
324 313
325 expect(observer.value, 42); 314 expect(observer.value, 42);
326 observer.value = 'hi'; 315 observer.value = 'hi';
327 expect(model._foo, 'hi'); 316 expect(model._foo, 'hi');
(...skipping 28 matching lines...) Expand all
356 expect(observer.value, null, reason: 'path not found'); 345 expect(observer.value, null, reason: 'path not found');
357 expect(model.log, ['[] bar']); 346 expect(model.log, ['[] bar']);
358 model.log.clear(); 347 model.log.clear();
359 348
360 observer.value = 42; 349 observer.value = 42;
361 expect(model.log, ['[]= bar 42']); 350 expect(model.log, ['[]= bar 42']);
362 model.log.clear(); 351 model.log.clear();
363 }); 352 });
364 } 353 }
365 354
366 /// A matcher that checks that a closure throws a NoSuchMethodError matching the
367 /// given [name].
368 _throwsNSM(String name) => throwsA(_isNoSuchMethodOf(name));
369
370 /// A matcher that checkes whether an exception is a NoSuchMethodError matching
371 /// the given [name].
372 _isNoSuchMethodOf(String name) => predicate((e) =>
373 e is NoSuchMethodError &&
374 // Dart2js and VM error messages are a bit different, but they both contain
375 // the name.
376 ('$e'.contains("'$name'") || // VM error
377 '$e'.contains('\'Symbol("$name")\''))); // dart2js error
378
379 class ObjectWithErrors { 355 class ObjectWithErrors {
380 int getFooCalled = 0; 356 int getFooCalled = 0;
381 List setFooCalled = []; 357 List setFooCalled = [];
382 @reflectable get foo { 358 @reflectable get foo {
383 getFooCalled++; 359 getFooCalled++;
384 (this as dynamic).bar; 360 (this as dynamic).bar;
385 } 361 }
386 @reflectable set foo(value) { 362 @reflectable set foo(value) {
387 setFooCalled.add(value); 363 setFooCalled.add(value);
388 (this as dynamic).bar = value; 364 (this as dynamic).bar = value;
(...skipping 11 matching lines...) Expand all
400 log.add(name); 376 log.add(name);
401 if (name == #foo && invocation.isGetter) return _foo; 377 if (name == #foo && invocation.isGetter) return _foo;
402 if (name == const Symbol('foo=')) { 378 if (name == const Symbol('foo=')) {
403 _foo = invocation.positionalArguments[0]; 379 _foo = invocation.positionalArguments[0];
404 return null; 380 return null;
405 } 381 }
406 return super.noSuchMethod(invocation); 382 return super.noSuchMethod(invocation);
407 } 383 }
408 } 384 }
409 385
410 class IndexerModel implements Indexable<String, dynamic> { 386 class IndexerModel {
411 var _foo = 42; 387 var _foo = 42;
412 List log = []; 388 List log = [];
413 389
414 operator [](index) { 390 operator [](index) {
415 log.add('[] $index'); 391 log.add('[] $index');
416 if (index == 'foo') return _foo; 392 if (index == 'foo') return _foo;
417 } 393 }
418 394
419 operator []=(index, value) { 395 operator []=(index, value) {
420 log.add('[]= $index $value'); 396 log.add('[]= $index $value');
(...skipping 28 matching lines...) Expand all
449 425
450 class WatcherModel extends Observable { 426 class WatcherModel extends Observable {
451 // 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:
452 // @observable var a, b, c; 428 // @observable var a, b, c;
453 @observable var a; 429 @observable var a;
454 @observable var b; 430 @observable var b;
455 @observable var c; 431 @observable var c;
456 432
457 WatcherModel(); 433 WatcherModel();
458 } 434 }
OLDNEW
« no previous file with comments | « pkg/observe/lib/src/path_observer.dart ('k') | pkg/polymer_expressions/lib/eval.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698