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

Side by Side Diff: pkg/observe/test/observe_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 'dart:async';
6 import 'package:observe/observe.dart'; 6 import 'package:observe/observe.dart';
7 import 'package:observe/src/watcher.dart' as watcher;
7 import 'package:unittest/unittest.dart'; 8 import 'package:unittest/unittest.dart';
8 import 'utils.dart'; 9 import 'observe_test_utils.dart';
10
11 const _VALUE = const Symbol('value');
9 12
10 main() { 13 main() {
11 // Note: to test the basic Observable system, we use ObservableBox due to its 14 // Note: to test the basic Observable system, we use ObservableBox due to its
12 // simplicity. 15 // simplicity. We also test a variant that is based on dirty-checking.
13 16
14 const _VALUE = const Symbol('value'); 17 observeTest('no observers at the start', () {
18 expect(watcher.allObservablesCount, 0);
19 });
15 20
16 group('ObservableBox', () { 21 group('WatcherModel', () { observeTests(watch: true); });
17 test('no observers', () {
18 var t = new ObservableBox<int>(123);
19 expect(t.value, 123);
20 t.value = 42;
21 expect(t.value, 42);
22 expect(t.hasObservers, false);
23 });
24 22
25 test('listen adds an observer', () { 23 group('ObservableBox', () { observeTests(); });
26 var t = new ObservableBox<int>(123); 24 }
27 expect(t.hasObservers, false);
28 25
29 t.changes.listen((n) {}); 26 observeTests({bool watch: false}) {
30 expect(t.hasObservers, true);
31 });
32 27
33 test('changes delived async', () { 28 final createModel = watch ? (x) => new WatcherModel(x)
34 var t = new ObservableBox<int>(123); 29 : (x) => new ObservableBox(x);
35 int called = 0;
36 30
37 t.changes.listen(expectAsync1((records) { 31 // Track the subscriptions so we can clean them up in tearDown.
38 called++; 32 List subs;
39 expectChanges(records, [_record(_VALUE), _record(_VALUE)]); 33
34 int initialObservers;
35 setUp(() {
36 initialObservers = watcher.allObservablesCount;
37 subs = [];
38
39 if (watch) runAsync(Observable.dirtyCheck);
40 });
41
42 tearDown(() {
43 for (var sub in subs) sub.cancel();
44 performMicrotaskCheckpoint();
45
46 expect(watcher.allObservablesCount, initialObservers,
47 reason: 'Observable object leaked');
48 });
49
50 observeTest('no observers', () {
51 var t = createModel(123);
52 expect(t.value, 123);
53 t.value = 42;
54 expect(t.value, 42);
55 expect(t.hasObservers, false);
56 });
57
58 observeTest('listen adds an observer', () {
59 var t = createModel(123);
60 expect(t.hasObservers, false);
61
62 subs.add(t.changes.listen((n) {}));
63 expect(t.hasObservers, true);
64 });
65
66 observeTest('changes delived async', () {
67 var t = createModel(123);
68 int called = 0;
69
70 subs.add(t.changes.listen(expectAsync1((records) {
71 called++;
72 expectChanges(records, _changedValue(watch ? 1 : 2));
73 })));
74
75 t.value = 41;
76 t.value = 42;
77 expect(called, 0);
78 });
79
80 observeTest('cause changes in handler', () {
81 var t = createModel(123);
82 int called = 0;
83
84 subs.add(t.changes.listen(expectAsync1((records) {
85 called++;
86 expectChanges(records, _changedValue(1));
87 if (called == 1) {
88 // Cause another change
89 t.value = 777;
90 }
91 }, count: 2)));
92
93 t.value = 42;
94 });
95
96 observeTest('multiple observers', () {
97 var t = createModel(123);
98
99 verifyRecords(records) {
100 expectChanges(records, _changedValue(watch ? 1 : 2));
101 };
102
103 subs.add(t.changes.listen(expectAsync1(verifyRecords)));
104 subs.add(t.changes.listen(expectAsync1(verifyRecords)));
105
106 t.value = 41;
107 t.value = 42;
108 });
109
110 observeTest('performMicrotaskCheckpoint', () {
111 var t = createModel(123);
112 var records = [];
113 subs.add(t.changes.listen((r) { records.addAll(r); }));
114 t.value = 41;
115 t.value = 42;
116 expectChanges(records, [], reason: 'changes delived async');
117
118 performMicrotaskCheckpoint();
119 expectChanges(records, _changedValue(watch ? 1 : 2));
120 records.clear();
121
122 t.value = 777;
123 expectChanges(records, [], reason: 'changes delived async');
124
125 performMicrotaskCheckpoint();
126 expectChanges(records, _changedValue(1));
127
128 // Has no effect if there are no changes
129 performMicrotaskCheckpoint();
130 expectChanges(records, _changedValue(1));
131 });
132
133 observeTest('cancel listening', () {
134 var t = createModel(123);
135 var sub;
136 sub = t.changes.listen(expectAsync1((records) {
137 expectChanges(records, _changedValue(1));
138 sub.cancel();
139 t.value = 777;
140 runAsync(Observable.dirtyCheck);
141 }));
142 t.value = 42;
143 });
144
145 observeTest('cancel and reobserve', () {
146 var t = createModel(123);
147 var sub;
148 sub = t.changes.listen(expectAsync1((records) {
149 expectChanges(records, _changedValue(1));
150 sub.cancel();
151
152 runAsync(expectAsync0(() {
153 subs.add(t.changes.listen(expectAsync1((records) {
154 expectChanges(records, _changedValue(1));
155 })));
156 t.value = 777;
157 runAsync(Observable.dirtyCheck);
40 })); 158 }));
41 t.value = 41; 159 }));
42 t.value = 42; 160 t.value = 42;
43 expect(called, 0);
44 });
45
46 test('cause changes in handler', () {
47 var t = new ObservableBox<int>(123);
48 int called = 0;
49
50 t.changes.listen(expectAsync1((records) {
51 called++;
52 expectChanges(records, [_record(_VALUE)]);
53 if (called == 1) {
54 // Cause another change
55 t.value = 777;
56 }
57 }, count: 2));
58
59 t.value = 42;
60 });
61
62 test('multiple observers', () {
63 var t = new ObservableBox<int>(123);
64
65 verifyRecords(records) {
66 expectChanges(records, [_record(_VALUE), _record(_VALUE)]);
67 };
68
69 t.changes.listen(expectAsync1(verifyRecords));
70 t.changes.listen(expectAsync1(verifyRecords));
71
72 t.value = 41;
73 t.value = 42;
74 });
75
76 test('deliverChangeRecords', () {
77 var t = new ObservableBox<int>(123);
78 var records = [];
79 t.changes.listen((r) { records.addAll(r); });
80 t.value = 41;
81 t.value = 42;
82 expectChanges(records, [], reason: 'changes delived async');
83
84 deliverChangeRecords();
85 expectChanges(records,
86 [_record(_VALUE), _record(_VALUE)]);
87 records.clear();
88
89 t.value = 777;
90 expectChanges(records, [], reason: 'changes delived async');
91
92 deliverChangeRecords();
93 expectChanges(records, [_record(_VALUE)]);
94
95 // Has no effect if there are no changes
96 deliverChangeRecords();
97 expectChanges(records, [_record(_VALUE)]);
98 });
99
100 test('cancel listening', () {
101 var t = new ObservableBox<int>(123);
102 var sub;
103 sub = t.changes.listen(expectAsync1((records) {
104 expectChanges(records, [_record(_VALUE)]);
105 sub.cancel();
106 t.value = 777;
107 }));
108 t.value = 42;
109 });
110
111 test('cancel and reobserve', () {
112 var t = new ObservableBox<int>(123);
113 var sub;
114 sub = t.changes.listen(expectAsync1((records) {
115 expectChanges(records, [_record(_VALUE)]);
116 sub.cancel();
117
118 runAsync(expectAsync0(() {
119 sub = t.changes.listen(expectAsync1((records) {
120 expectChanges(records, [_record(_VALUE)]);
121 }));
122 t.value = 777;
123 }));
124 }));
125 t.value = 42;
126 });
127 }); 161 });
128 } 162 }
129 163
130 _record(key) => new PropertyChangeRecord(key); 164 _changedValue(len) => new List.filled(len, new PropertyChangeRecord(_VALUE));
165
166 // A test model based on dirty checking.
167 class WatcherModel<T> extends ObservableBase {
168 @observable T value;
169
170 WatcherModel([T initialValue]) : value = initialValue;
171
172 String toString() => '#<$runtimeType value: $value>';
173 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698