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

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

Issue 817483003: delete observe from the repo (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 6 years 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/observe/test/transformer_test.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(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 'package:observe/src/path_observer.dart'
9 show getSegmentsOfPropertyPathForTesting,
10 observerSentinelForTesting;
11
12 import 'observe_test_utils.dart';
13
14 // This file contains code ported from:
15 // https://github.com/rafaelw/ChangeSummary/blob/master/tests/test.js
16 // Dart note: getting invalid properties is an error, unlike in JS where it
17 // returns undefined. This difference comes up where we check for _throwsNSM in
18 // the tests below.
19 main() => dirtyCheckZone().run(() {
20 group('PathObserver', observePathTests);
21
22 group('PropertyPath', () {
23 test('toString length', () {
24 expectPath(p, str, len, [keys]) {
25 var path = new PropertyPath(p);
26 expect(path.toString(), str);
27 expect(path.length, len, reason: 'expected path length $len for $path');
28 if (keys == null) {
29 expect(path.isValid, isFalse);
30 } else {
31 expect(path.isValid, isTrue);
32 expect(getSegmentsOfPropertyPathForTesting(path), keys);
33 }
34 }
35
36 expectPath('/foo', '<invalid path>', 0);
37 expectPath('1.abc', '<invalid path>', 0);
38 expectPath('abc', 'abc', 1, [#abc]);
39 expectPath('a.b.c', 'a.b.c', 3, [#a, #b, #c]);
40 expectPath('a.b.c ', 'a.b.c', 3, [#a, #b, #c]);
41 expectPath(' a.b.c', 'a.b.c', 3, [#a, #b, #c]);
42 expectPath(' a.b.c ', 'a.b.c', 3, [#a, #b, #c]);
43 expectPath('[1].abc', '[1].abc', 2, [1, #abc]);
44 expectPath([#qux], 'qux', 1, [#qux]);
45 expectPath([1, #foo, #bar], '[1].foo.bar', 3, [1, #foo, #bar]);
46 expectPath([1, #foo, 'bar'], '[1].foo["bar"]', 3, [1, #foo, 'bar']);
47
48 // From test.js: "path validity" test:
49
50 expectPath('', '', 0, []);
51 expectPath(' ', '', 0, []);
52 expectPath(null, '', 0, []);
53 expectPath('a', 'a', 1, [#a]);
54 expectPath('a.b', 'a.b', 2, [#a, #b]);
55 expectPath('a. b', 'a.b', 2, [#a, #b]);
56 expectPath('a .b', 'a.b', 2, [#a, #b]);
57 expectPath('a . b', 'a.b', 2, [#a, #b]);
58 expectPath(' a . b ', 'a.b', 2, [#a, #b]);
59 expectPath('a[0]', 'a[0]', 2, [#a, 0]);
60 expectPath('a [0]', 'a[0]', 2, [#a, 0]);
61 expectPath('a[0][1]', 'a[0][1]', 3, [#a, 0, 1]);
62 expectPath('a [ 0 ] [ 1 ] ', 'a[0][1]', 3, [#a, 0, 1]);
63 expectPath('[1234567890] ', '[1234567890]', 1, [1234567890]);
64 expectPath(' [1234567890] ', '[1234567890]', 1, [1234567890]);
65 expectPath('opt0', 'opt0', 1, [#opt0]);
66 // Dart note: Modified to avoid a private Dart symbol:
67 expectPath(r'$foo.$bar.baz_', r'$foo.$bar.baz_', 3,
68 [#$foo, #$bar, #baz_]);
69 // Dart note: this test is different because we treat ["baz"] always as a
70 // indexing operation.
71 expectPath('foo["baz"]', 'foo.baz', 2, [#foo, #baz]);
72 expectPath('foo["b\\"az"]', 'foo["b\\"az"]', 2, [#foo, 'b"az']);
73 expectPath("foo['b\\'az']", 'foo["b\'az"]', 2, [#foo, "b'az"]);
74 expectPath([#a, #b], 'a.b', 2, [#a, #b]);
75 expectPath([], '', 0, []);
76
77 expectPath('.', '<invalid path>', 0);
78 expectPath(' . ', '<invalid path>', 0);
79 expectPath('..', '<invalid path>', 0);
80 expectPath('a[4', '<invalid path>', 0);
81 expectPath('a.b.', '<invalid path>', 0);
82 expectPath('a,b', '<invalid path>', 0);
83 expectPath('a["foo]', '<invalid path>', 0);
84 expectPath('[0x04]', '<invalid path>', 0);
85 expectPath('[0foo]', '<invalid path>', 0);
86 expectPath('[foo-bar]', '<invalid path>', 0);
87 expectPath('foo-bar', '<invalid path>', 0);
88 expectPath('42', '<invalid path>', 0);
89 expectPath('a[04]', '<invalid path>', 0);
90 expectPath(' a [ 04 ]', '<invalid path>', 0);
91 expectPath(' 42 ', '<invalid path>', 0);
92 expectPath('foo["bar]', '<invalid path>', 0);
93 expectPath("foo['bar]", '<invalid path>', 0);
94 });
95
96 test('objects with toString are not supported', () {
97 // Dart note: this was intentionally not ported. See path_observer.dart.
98 expect(() => new PropertyPath([new Foo('a'), new Foo('b')]), throws);
99 });
100
101 test('invalid path returns null value', () {
102 var path = new PropertyPath('a b');
103 expect(path.isValid, isFalse);
104 expect(path.getValueFrom({'a': {'b': 2}}), isNull);
105 });
106
107
108 test('caching and ==', () {
109 var start = new PropertyPath('abc[0]');
110 for (int i = 1; i <= 100; i++) {
111 expect(identical(new PropertyPath('abc[0]'), start), true,
112 reason: 'should return identical path');
113
114 var p = new PropertyPath('abc[$i]');
115 expect(identical(p, start), false,
116 reason: 'different paths should not be merged');
117 }
118 var end = new PropertyPath('abc[0]');
119 expect(identical(end, start), false,
120 reason: 'first entry expired');
121 expect(end, start, reason: 'different instances are equal');
122 });
123
124 test('hashCode equal', () {
125 var a = new PropertyPath([#foo, 2, #bar]);
126 var b = new PropertyPath('foo[2].bar');
127 expect(identical(a, b), false, reason: 'only strings cached');
128 expect(a, b, reason: 'same paths are equal');
129 expect(a.hashCode, b.hashCode, reason: 'equal hashCodes');
130 });
131
132 test('hashCode not equal', () {
133 expect(2.hashCode, isNot(3.hashCode),
134 reason: 'test depends on 2 and 3 having different hashcodes');
135
136 var a = new PropertyPath([2]);
137 var b = new PropertyPath([3]);
138 expect(a, isNot(b), reason: 'different paths');
139 expect(a.hashCode, isNot(b.hashCode), reason: 'different hashCodes');
140 });
141 });
142
143 group('CompoundObserver', compoundObserverTests);
144 });
145
146 observePathTests() {
147 test('Degenerate Values', () {
148 expect(new PathObserver(null, '').value, null);
149 expect(new PathObserver(123, '').value, 123);
150 expect(() => new PathObserver(123, 'foo.bar.baz').value, _throwsNSM('foo'));
151
152 // shouldn't throw:
153 new PathObserver(123, '')..open((_) {})..close();
154 new PropertyPath('').setValueFrom(null, null);
155 new PropertyPath('').setValueFrom(123, 42);
156 expect(() => new PropertyPath('foo.bar.baz').setValueFrom(123, 42),
157 _throwsNSM('foo'));
158 var foo = {};
159 expect(new PathObserver(foo, '').value, foo);
160
161 foo = new Object();
162 expect(new PathObserver(foo, '').value, foo);
163
164 expect(new PathObserver(foo, 'a/3!').value, null);
165 });
166
167 test('get value at path ObservableBox', () {
168 var obj = new ObservableBox(new ObservableBox(new ObservableBox(1)));
169
170 expect(new PathObserver(obj, '').value, obj);
171 expect(new PathObserver(obj, 'value').value, obj.value);
172 expect(new PathObserver(obj, 'value.value').value, obj.value.value);
173 expect(new PathObserver(obj, 'value.value.value').value, 1);
174
175 obj.value.value.value = 2;
176 expect(new PathObserver(obj, 'value.value.value').value, 2);
177
178 obj.value.value = new ObservableBox(3);
179 expect(new PathObserver(obj, 'value.value.value').value, 3);
180
181 obj.value = new ObservableBox(4);
182 expect(() => new PathObserver(obj, 'value.value.value').value,
183 _throwsNSM('value'));
184 expect(new PathObserver(obj, 'value.value').value, 4);
185 });
186
187
188 test('get value at path ObservableMap', () {
189 var obj = toObservable({'a': {'b': {'c': 1}}});
190
191 expect(new PathObserver(obj, '').value, obj);
192 expect(new PathObserver(obj, 'a').value, obj['a']);
193 expect(new PathObserver(obj, 'a.b').value, obj['a']['b']);
194 expect(new PathObserver(obj, 'a.b.c').value, 1);
195
196 obj['a']['b']['c'] = 2;
197 expect(new PathObserver(obj, 'a.b.c').value, 2);
198
199 obj['a']['b'] = toObservable({'c': 3});
200 expect(new PathObserver(obj, 'a.b.c').value, 3);
201
202 obj['a'] = toObservable({'b': 4});
203 expect(() => new PathObserver(obj, 'a.b.c').value, _throwsNSM('c'));
204 expect(new PathObserver(obj, 'a.b').value, 4);
205 });
206
207 test('set value at path', () {
208 var obj = toObservable({});
209 new PropertyPath('foo').setValueFrom(obj, 3);
210 expect(obj['foo'], 3);
211
212 var bar = toObservable({ 'baz': 3 });
213 new PropertyPath('bar').setValueFrom(obj, bar);
214 expect(obj['bar'], bar);
215
216 expect(() => new PropertyPath('bar.baz.bat').setValueFrom(obj, 'not here'),
217 _throwsNSM('bat='));
218 expect(() => new PathObserver(obj, 'bar.baz.bat').value, _throwsNSM('bat'));
219 });
220
221 test('set value back to same', () {
222 var obj = toObservable({});
223 var path = new PathObserver(obj, 'foo');
224 var values = [];
225 path.open((x) {
226 expect(x, path.value, reason: 'callback should get current value');
227 values.add(x);
228 });
229
230 path.value = 3;
231 expect(obj['foo'], 3);
232 expect(path.value, 3);
233
234 new PropertyPath('foo').setValueFrom(obj, 2);
235 return new Future(() {
236 expect(path.value, 2);
237 expect(new PathObserver(obj, 'foo').value, 2);
238
239 new PropertyPath('foo').setValueFrom(obj, 3);
240 }).then(newMicrotask).then((_) {
241 expect(path.value, 3);
242
243 }).then(newMicrotask).then((_) {
244 expect(values, [2, 3]);
245 });
246 });
247
248 test('Observe and Unobserve - Paths', () {
249 var arr = toObservable({});
250
251 arr['foo'] = 'bar';
252 var fooValues = [];
253 var fooPath = new PathObserver(arr, 'foo');
254 fooPath.open(fooValues.add);
255 arr['foo'] = 'baz';
256 arr['bat'] = 'bag';
257 var batValues = [];
258 var batPath = new PathObserver(arr, 'bat');
259 batPath.open(batValues.add);
260
261 return new Future(() {
262 expect(fooValues, ['baz']);
263 expect(batValues, []);
264
265 arr['foo'] = 'bar';
266 fooPath.close();
267 arr['bat'] = 'boo';
268 batPath.close();
269 arr['bat'] = 'boot';
270
271 }).then(newMicrotask).then((_) {
272 expect(fooValues, ['baz']);
273 expect(batValues, []);
274 });
275 });
276
277 test('Path Value With Indices', () {
278 var model = toObservable([]);
279 var path = new PathObserver(model, '[0]');
280 path.open(expectAsync((x) {
281 expect(path.value, 123);
282 expect(x, 123);
283 }));
284 model.add(123);
285 });
286
287 group('ObservableList', () {
288 test('isNotEmpty', () {
289 var model = new ObservableList();
290 var path = new PathObserver(model, 'isNotEmpty');
291 expect(path.value, false);
292
293 path.open(expectAsync((_) {
294 expect(path.value, true);
295 }));
296 model.add(123);
297 });
298
299 test('isEmpty', () {
300 var model = new ObservableList();
301 var path = new PathObserver(model, 'isEmpty');
302 expect(path.value, true);
303
304 path.open(expectAsync((_) {
305 expect(path.value, false);
306 }));
307 model.add(123);
308 });
309 });
310
311 for (var createModel in [() => new TestModel(), () => new WatcherModel()]) {
312 test('Path Observation - ${createModel().runtimeType}', () {
313 var model = createModel()..a =
314 (createModel()..b = (createModel()..c = 'hello, world'));
315
316 var path = new PathObserver(model, 'a.b.c');
317 var lastValue = null;
318 var errorSeen = false;
319 runZoned(() {
320 path.open((x) { lastValue = x; });
321 }, onError: (e) {
322 expect(e, _isNoSuchMethodOf('c'));
323 errorSeen = true;
324 });
325
326 model.a.b.c = 'hello, mom';
327
328 expect(lastValue, null);
329 return new Future(() {
330 expect(lastValue, 'hello, mom');
331
332 model.a.b = createModel()..c = 'hello, dad';
333 }).then(newMicrotask).then((_) {
334 expect(lastValue, 'hello, dad');
335
336 model.a = createModel()..b =
337 (createModel()..c = 'hello, you');
338 }).then(newMicrotask).then((_) {
339 expect(lastValue, 'hello, you');
340
341 model.a.b = 1;
342 expect(errorSeen, isFalse);
343 }).then(newMicrotask).then((_) {
344 expect(errorSeen, isTrue);
345 expect(lastValue, 'hello, you');
346
347 // Stop observing
348 path.close();
349
350 model.a.b = createModel()..c = 'hello, back again -- but not observing';
351 }).then(newMicrotask).then((_) {
352 expect(lastValue, 'hello, you');
353
354 // Resume observing
355 new PathObserver(model, 'a.b.c').open((x) { lastValue = x; });
356
357 model.a.b.c = 'hello. Back for reals';
358 }).then(newMicrotask).then((_) {
359 expect(lastValue, 'hello. Back for reals');
360 });
361 });
362 }
363
364 test('observe map', () {
365 var model = toObservable({'a': 1});
366 var path = new PathObserver(model, 'a');
367
368 var values = [path.value];
369 path.open(values.add);
370 expect(values, [1]);
371
372 model['a'] = 2;
373 return new Future(() {
374 expect(values, [1, 2]);
375
376 path.close();
377 model['a'] = 3;
378 }).then(newMicrotask).then((_) {
379 expect(values, [1, 2]);
380 });
381 });
382
383 test('errors thrown from getter/setter', () {
384 var model = new ObjectWithErrors();
385 var observer = new PathObserver(model, 'foo');
386
387 expect(() => observer.value, _throwsNSM('bar'));
388 expect(model.getFooCalled, 1);
389
390 expect(() { observer.value = 123; }, _throwsNSM('bar='));
391 expect(model.setFooCalled, [123]);
392 });
393
394 test('object with noSuchMethod', () {
395 var model = new NoSuchMethodModel();
396 var observer = new PathObserver(model, 'foo');
397
398 expect(observer.value, 42);
399 observer.value = 'hi';
400 expect(model._foo, 'hi');
401 expect(observer.value, 'hi');
402
403 expect(model.log, [#foo, const Symbol('foo='), #foo]);
404
405 // These shouldn't throw
406 observer = new PathObserver(model, 'bar');
407 expect(observer.value, null, reason: 'path not found');
408 observer.value = 42;
409 expect(observer.value, null, reason: 'path not found');
410 });
411
412 test('object with indexer', () {
413 var model = new IndexerModel();
414 var observer = new PathObserver(model, 'foo');
415
416 expect(observer.value, 42);
417 expect(model.log, ['[] foo']);
418 model.log.clear();
419
420 observer.value = 'hi';
421 expect(model.log, ['[]= foo hi']);
422 expect(model._foo, 'hi');
423
424 expect(observer.value, 'hi');
425
426 // These shouldn't throw
427 model.log.clear();
428 observer = new PathObserver(model, 'bar');
429 expect(observer.value, null, reason: 'path not found');
430 expect(model.log, ['[] bar']);
431 model.log.clear();
432
433 observer.value = 42;
434 expect(model.log, ['[]= bar 42']);
435 model.log.clear();
436 });
437
438 test('regression for TemplateBinding#161', () {
439 var model = toObservable({'obj': toObservable({'bar': false})});
440 var ob1 = new PathObserver(model, 'obj.bar');
441 var called = false;
442 ob1.open(() { called = true; });
443
444 var obj2 = new PathObserver(model, 'obj');
445 obj2.open(() { model['obj']['bar'] = true; });
446
447 model['obj'] = toObservable({ 'obj': 'obj' });
448
449 return new Future(() {})
450 .then((_) => expect(called, true));
451 });
452 }
453
454 compoundObserverTests() {
455 var model;
456 var observer;
457 bool called;
458 var newValues;
459 var oldValues;
460 var observed;
461
462 setUp(() {
463 model = new TestModel(1, 2, 3);
464 called = false;
465 });
466
467 callback(a, b, c) {
468 called = true;
469 newValues = a;
470 oldValues = b;
471 observed = c;
472 }
473
474 reset() {
475 called = false;
476 newValues = null;
477 oldValues = null;
478 observed = null;
479 }
480
481 expectNoChanges() {
482 observer.deliver();
483 expect(called, isFalse);
484 expect(newValues, isNull);
485 expect(oldValues, isNull);
486 expect(observed, isNull);
487 }
488
489 expectCompoundPathChanges(expectedNewValues,
490 expectedOldValues, expectedObserved, {deliver: true}) {
491 if (deliver) observer.deliver();
492 expect(called, isTrue);
493
494 expect(newValues, expectedNewValues);
495 var oldValuesAsMap = {};
496 for (int i = 0; i < expectedOldValues.length; i++) {
497 if (expectedOldValues[i] != null) {
498 oldValuesAsMap[i] = expectedOldValues[i];
499 }
500 }
501 expect(oldValues, oldValuesAsMap);
502 expect(observed, expectedObserved);
503
504 reset();
505 }
506
507 tearDown(() {
508 observer.close();
509 reset();
510 });
511
512 _path(s) => new PropertyPath(s);
513
514 test('simple', () {
515 observer = new CompoundObserver();
516 observer.addPath(model, 'a');
517 observer.addPath(model, 'b');
518 observer.addPath(model, _path('c'));
519 observer.open(callback);
520 expectNoChanges();
521
522 var expectedObs = [model, _path('a'), model, _path('b'), model, _path('c')];
523 model.a = -10;
524 model.b = 20;
525 model.c = 30;
526 expectCompoundPathChanges([-10, 20, 30], [1, 2, 3], expectedObs);
527
528 model.a = 'a';
529 model.c = 'c';
530 expectCompoundPathChanges(['a', 20, 'c'], [-10, null, 30], expectedObs);
531
532 model.a = 2;
533 model.b = 3;
534 model.c = 4;
535 expectCompoundPathChanges([2, 3, 4], ['a', 20, 'c'], expectedObs);
536
537 model.a = 'z';
538 model.b = 'y';
539 model.c = 'x';
540 expect(observer.value, ['z', 'y', 'x']);
541 expectNoChanges();
542
543 expect(model.a, 'z');
544 expect(model.b, 'y');
545 expect(model.c, 'x');
546 expectNoChanges();
547 });
548
549 test('reportChangesOnOpen', () {
550 observer = new CompoundObserver(true);
551 observer.addPath(model, 'a');
552 observer.addPath(model, 'b');
553 observer.addPath(model, _path('c'));
554
555 model.a = -10;
556 model.b = 20;
557 observer.open(callback);
558 var expectedObs = [model, _path('a'), model, _path('b'), model, _path('c')];
559 expectCompoundPathChanges([-10, 20, 3], [1, 2, null], expectedObs,
560 deliver: false);
561 });
562
563 test('All Observers', () {
564 observer = new CompoundObserver();
565 var pathObserver1 = new PathObserver(model, 'a');
566 var pathObserver2 = new PathObserver(model, 'b');
567 var pathObserver3 = new PathObserver(model, _path('c'));
568
569 observer.addObserver(pathObserver1);
570 observer.addObserver(pathObserver2);
571 observer.addObserver(pathObserver3);
572 observer.open(callback);
573
574 var expectedObs = [observerSentinelForTesting, pathObserver1,
575 observerSentinelForTesting, pathObserver2,
576 observerSentinelForTesting, pathObserver3];
577 model.a = -10;
578 model.b = 20;
579 model.c = 30;
580 expectCompoundPathChanges([-10, 20, 30], [1, 2, 3], expectedObs);
581
582 model.a = 'a';
583 model.c = 'c';
584 expectCompoundPathChanges(['a', 20, 'c'], [-10, null, 30], expectedObs);
585 });
586
587 test('Degenerate Values', () {
588 observer = new CompoundObserver();
589 observer.addPath(model, '.'); // invalid path
590 observer.addPath('obj-value', ''); // empty path
591 // Dart note: we don't port these two tests because in Dart we produce
592 // exceptions for these invalid paths.
593 // observer.addPath(model, 'foo'); // unreachable
594 // observer.addPath(3, 'bar'); // non-object with non-empty path
595 var values = observer.open(callback);
596 expect(values.length, 2);
597 expect(values[0], null);
598 expect(values[1], 'obj-value');
599 observer.close();
600 });
601
602 test('Heterogeneous', () {
603 model.c = null;
604 var otherModel = new TestModel(null, null, 3);
605
606 twice(value) => value * 2;
607 half(value) => value ~/ 2;
608
609 var compound = new CompoundObserver();
610 compound.addPath(model, 'a');
611 compound.addObserver(new ObserverTransform(new PathObserver(model, 'b'),
612 twice, setValue: half));
613 compound.addObserver(new PathObserver(otherModel, 'c'));
614
615 combine(values) => values[0] + values[1] + values[2];
616 observer = new ObserverTransform(compound, combine);
617
618 var newValue;
619 transformCallback(v) {
620 newValue = v;
621 called = true;
622 }
623 expect(observer.open(transformCallback), 8);
624
625 model.a = 2;
626 model.b = 4;
627 observer.deliver();
628 expect(called, isTrue);
629 expect(newValue, 13);
630 called = false;
631
632 model.b = 10;
633 otherModel.c = 5;
634 observer.deliver();
635 expect(called, isTrue);
636 expect(newValue, 27);
637 called = false;
638
639 model.a = 20;
640 model.b = 1;
641 otherModel.c = 5;
642 observer.deliver();
643 expect(called, isFalse);
644 expect(newValue, 27);
645 });
646 }
647
648 /// A matcher that checks that a closure throws a NoSuchMethodError matching the
649 /// given [name].
650 _throwsNSM(String name) => throwsA(_isNoSuchMethodOf(name));
651
652 /// A matcher that checkes whether an exception is a NoSuchMethodError matching
653 /// the given [name].
654 _isNoSuchMethodOf(String name) => predicate((e) =>
655 e is NoSuchMethodError &&
656 // Dart2js and VM error messages are a bit different, but they both contain
657 // the name.
658 ('$e'.contains("'$name'") || // VM error
659 '$e'.contains('\'Symbol("$name")\''))); // dart2js error
660
661 class ObjectWithErrors {
662 int getFooCalled = 0;
663 List setFooCalled = [];
664 @reflectable get foo {
665 getFooCalled++;
666 (this as dynamic).bar;
667 }
668 @reflectable set foo(value) {
669 setFooCalled.add(value);
670 (this as dynamic).bar = value;
671 }
672 }
673
674 class NoSuchMethodModel {
675 var _foo = 42;
676 List log = [];
677
678 // TODO(ahe): Remove @reflectable from here (once either of
679 // http://dartbug.com/15408 or http://dartbug.com/15409 are fixed).
680 @reflectable noSuchMethod(Invocation invocation) {
681 final name = invocation.memberName;
682 log.add(name);
683 if (name == #foo && invocation.isGetter) return _foo;
684 if (name == const Symbol('foo=')) {
685 _foo = invocation.positionalArguments[0];
686 return null;
687 }
688 return super.noSuchMethod(invocation);
689 }
690 }
691
692 class IndexerModel implements Indexable<String, dynamic> {
693 var _foo = 42;
694 List log = [];
695
696 operator [](index) {
697 log.add('[] $index');
698 if (index == 'foo') return _foo;
699 }
700
701 operator []=(index, value) {
702 log.add('[]= $index $value');
703 if (index == 'foo') _foo = value;
704 }
705 }
706
707 @reflectable
708 class TestModel extends ChangeNotifier {
709 var _a, _b, _c;
710
711 TestModel([this._a, this._b, this._c]);
712
713 get a => _a;
714
715 void set a(newValue) {
716 _a = notifyPropertyChange(#a, _a, newValue);
717 }
718
719 get b => _b;
720
721 void set b(newValue) {
722 _b = notifyPropertyChange(#b, _b, newValue);
723 }
724
725 get c => _c;
726
727 void set c(newValue) {
728 _c = notifyPropertyChange(#c, _c, newValue);
729 }
730 }
731
732 class WatcherModel extends Observable {
733 // TODO(jmesserly): dart2js does not let these be on the same line:
734 // @observable var a, b, c;
735 @observable var a;
736 @observable var b;
737 @observable var c;
738
739 WatcherModel();
740 }
741
742 class Foo {
743 var value;
744 Foo(this.value);
745 String toString() => 'Foo$value';
746 }
OLDNEW
« no previous file with comments | « pkg/observe/test/observe_test_utils.dart ('k') | pkg/observe/test/transformer_test.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698