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

Side by Side Diff: packages/observable/test/observable_test.dart

Issue 2989763002: Update charted to 0.4.8 and roll (Closed)
Patch Set: Removed Cutch from list of reviewers Created 3 years, 4 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
OLDNEW
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2016, 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:logging/logging.dart';
7 import 'package:observe/observe.dart';
8 import 'package:observe/src/dirty_check.dart' as dirty_check;
9 import 'package:unittest/unittest.dart';
10 import 'observe_test_utils.dart';
11 6
12 import 'package:observe/mirrors_used.dart'; // make test smaller. 7 import 'package:observable/observable.dart';
13 import 'package:smoke/mirrors.dart'; 8 import 'package:test/test.dart';
14 9
15 main() { 10 import 'observable_test_utils.dart';
16 useMirrors();
17 dirtyCheckZone().run(_tests);
18 }
19 11
20 void _tests() { 12 main() => observableTests();
21 // Note: to test the basic Observable system, we use ObservableBox due to its
22 // simplicity. We also test a variant that is based on dirty-checking.
23 13
24 test('no observers at the start', () { 14 void observableTests() {
25 expect(dirty_check.allObservablesCount, 0);
26 });
27
28 group('WatcherModel', () => _observeTests((x) => new WatcherModel(x)));
29
30 group('ObservableBox', () => _observeTests((x) => new ObservableBox(x)));
31
32 group('ModelSubclass', () => _observeTests((x) => new ModelSubclass(x)));
33
34 group('dirtyCheck loops can be debugged', () {
35 var messages;
36 var subscription;
37 setUp(() {
38 messages = [];
39 subscription = Logger.root.onRecord.listen((record) {
40 messages.add(record.message);
41 });
42 });
43
44 tearDown(() {
45 subscription.cancel();
46 });
47
48 test('logs debug information', () {
49 var maxNumIterations = dirty_check.MAX_DIRTY_CHECK_CYCLES;
50
51 var x = new WatcherModel(0);
52 var sub = x.changes.listen(expectAsync((_) { x.value++; },
53 count: maxNumIterations));
54 x.value = 1;
55 Observable.dirtyCheck();
56 expect(x.value, maxNumIterations + 1);
57 expect(messages.length, 2);
58
59 expect(messages[0], contains('Possible loop'));
60 expect(messages[1], contains('index 0'));
61 expect(messages[1], contains('object: $x'));
62
63 sub.cancel();
64 });
65 });
66 }
67
68 void _observeTests(createModel(x)) {
69 final watch = createModel(null) is! ChangeNotifier;
70
71 // Track the subscriptions so we can clean them up in tearDown. 15 // Track the subscriptions so we can clean them up in tearDown.
72 List subs; 16 List subs;
73 17
74 int initialObservers;
75 setUp(() { 18 setUp(() {
76 initialObservers = dirty_check.allObservablesCount;
77 subs = []; 19 subs = [];
78
79 if (watch) scheduleMicrotask(Observable.dirtyCheck);
80 }); 20 });
81 21
82 tearDown(() { 22 tearDown(() {
83 for (var sub in subs) sub.cancel(); 23 for (var sub in subs) sub.cancel();
84 return new Future(() {
85 expect(dirty_check.allObservablesCount, initialObservers,
86 reason: 'Observable object leaked');
87 });
88 }); 24 });
89 25
90 test('handle future result', () { 26 test('handle future result', () {
91 var callback = expectAsync((){}); 27 var callback = expectAsync(() {});
92 return new Future(callback); 28 return new Future(callback);
93 }); 29 });
94 30
95 test('no observers', () { 31 test('no observers', () {
96 var t = createModel(123); 32 var t = createModel(123);
97 expect(t.value, 123); 33 expect(t.value, 123);
98 t.value = 42; 34 t.value = 42;
99 expect(t.value, 42); 35 expect(t.value, 42);
100 expect(t.hasObservers, false); 36 expect(t.hasObservers, false);
101 }); 37 });
102 38
103 test('listen adds an observer', () { 39 test('listen adds an observer', () {
104 var t = createModel(123); 40 var t = createModel(123);
105 expect(t.hasObservers, false); 41 expect(t.hasObservers, false);
106 42
107 subs.add(t.changes.listen((n) {})); 43 subs.add(t.changes.listen((n) {}));
108 expect(t.hasObservers, true); 44 expect(t.hasObservers, true);
109 }); 45 });
110 46
111 test('changes delived async', () { 47 test('changes delived async', () {
112 var t = createModel(123); 48 var t = createModel(123);
113 int called = 0; 49 int called = 0;
114 50
115 subs.add(t.changes.listen(expectAsync((records) { 51 subs.add(t.changes.listen(expectAsync((records) {
116 called++; 52 called++;
117 expectPropertyChanges(records, watch ? 1 : 2); 53 expectPropertyChanges(records, 2);
118 }))); 54 })));
119 55
120 t.value = 41; 56 t.value = 41;
121 t.value = 42; 57 t.value = 42;
122 expect(called, 0); 58 expect(called, 0);
123 }); 59 });
124 60
125 test('cause changes in handler', () { 61 test('cause changes in handler', () {
126 var t = createModel(123); 62 var t = createModel(123);
127 int called = 0; 63 int called = 0;
128 64
129 subs.add(t.changes.listen(expectAsync((records) { 65 subs.add(t.changes.listen(expectAsync((records) {
130 called++; 66 called++;
131 expectPropertyChanges(records, 1); 67 expectPropertyChanges(records, 1);
132 if (called == 1) { 68 if (called == 1) {
133 // Cause another change 69 // Cause another change
134 t.value = 777; 70 t.value = 777;
135 } 71 }
136 }, count: 2))); 72 }, count: 2)));
137 73
138 t.value = 42; 74 t.value = 42;
139 }); 75 });
140 76
141 test('multiple observers', () { 77 test('multiple observers', () {
142 var t = createModel(123); 78 var t = createModel(123);
143 79
144 verifyRecords(records) { 80 verifyRecords(records) {
145 expectPropertyChanges(records, watch ? 1 : 2); 81 expectPropertyChanges(records, 2);
146 }; 82 }
147 83
148 subs.add(t.changes.listen(expectAsync(verifyRecords))); 84 subs.add(t.changes.listen(expectAsync(verifyRecords)));
149 subs.add(t.changes.listen(expectAsync(verifyRecords))); 85 subs.add(t.changes.listen(expectAsync(verifyRecords)));
150 86
151 t.value = 41; 87 t.value = 41;
152 t.value = 42; 88 t.value = 42;
153 }); 89 });
154 90
155 test('async processing model', () { 91 test('async processing model', () {
156 var t = createModel(123); 92 var t = createModel(123);
157 var records = []; 93 var records = [];
158 subs.add(t.changes.listen((r) { records.addAll(r); })); 94 subs.add(t.changes.listen((r) {
95 records.addAll(r);
96 }));
159 t.value = 41; 97 t.value = 41;
160 t.value = 42; 98 t.value = 42;
161 expectChanges(records, [], reason: 'changes delived async'); 99 expectChanges(records, [], reason: 'changes delived async');
162 100
163 return new Future(() { 101 return new Future(() {
164 expectPropertyChanges(records, watch ? 1 : 2); 102 expectPropertyChanges(records, 2);
165 records.clear(); 103 records.clear();
166 104
167 t.value = 777; 105 t.value = 777;
168 expectChanges(records, [], reason: 'changes delived async'); 106 expectChanges(records, [], reason: 'changes delived async');
169
170 }).then(newMicrotask).then((_) { 107 }).then(newMicrotask).then((_) {
171 expectPropertyChanges(records, 1); 108 expectPropertyChanges(records, 1);
172
173 // Has no effect if there are no changes
174 Observable.dirtyCheck();
175 expectPropertyChanges(records, 1);
176 }); 109 });
177 }); 110 });
178 111
179 test('cancel listening', () { 112 test('cancel listening', () {
180 var t = createModel(123); 113 var t = createModel(123);
181 var sub; 114 var sub;
182 sub = t.changes.listen(expectAsync((records) { 115 sub = t.changes.listen(expectAsync((records) {
183 expectPropertyChanges(records, 1); 116 expectPropertyChanges(records, 1);
184 sub.cancel(); 117 sub.cancel();
185 t.value = 777; 118 t.value = 777;
186 scheduleMicrotask(Observable.dirtyCheck);
187 })); 119 }));
188 t.value = 42; 120 t.value = 42;
189 }); 121 });
190 122
191 test('cancel and reobserve', () { 123 test('cancel and reobserve', () {
192 var t = createModel(123); 124 var t = createModel(123);
193 var sub; 125 var sub;
194 sub = t.changes.listen(expectAsync((records) { 126 sub = t.changes.listen(expectAsync((records) {
195 expectPropertyChanges(records, 1); 127 expectPropertyChanges(records, 1);
196 sub.cancel(); 128 sub.cancel();
197 129
198 scheduleMicrotask(expectAsync(() { 130 scheduleMicrotask(() {
199 subs.add(t.changes.listen(expectAsync((records) { 131 subs.add(t.changes.listen(expectAsync((records) {
200 expectPropertyChanges(records, 1); 132 expectPropertyChanges(records, 1);
201 }))); 133 })));
202 t.value = 777; 134 t.value = 777;
203 scheduleMicrotask(Observable.dirtyCheck); 135 });
204 }));
205 })); 136 }));
206 t.value = 42; 137 t.value = 42;
207 }); 138 });
208 139
209 test('cannot modify changes list', () { 140 test('cannot modify changes list', () {
210 var t = createModel(123); 141 var t = createModel(123);
211 var records = null; 142 var records;
212 subs.add(t.changes.listen((r) { records = r; })); 143 subs.add(t.changes.listen((r) {
144 records = r;
145 }));
213 t.value = 42; 146 t.value = 42;
214 147
215 return new Future(() { 148 return new Future(() {
216 expectPropertyChanges(records, 1); 149 expectPropertyChanges(records, 1);
217 150
218 // Verify that mutation operations on the list fail: 151 // Verify that mutation operations on the list fail:
219 152
220 expect(() { 153 expect(() {
221 records[0] = new PropertyChangeRecord(t, #value, 0, 1); 154 records[0] = new PropertyChangeRecord(t, #value, 0, 1);
222 }, throwsUnsupportedError); 155 }, throwsUnsupportedError);
223 156
224 expect(() { records.clear(); }, throwsUnsupportedError); 157 expect(() {
158 records.clear();
159 }, throwsUnsupportedError);
225 160
226 expect(() { records.length = 0; }, throwsUnsupportedError); 161 expect(() {
162 records.length = 0;
163 }, throwsUnsupportedError);
227 }); 164 });
228 }); 165 });
229 166
230 test('notifyChange', () { 167 test('notifyChange', () {
231 var t = createModel(123); 168 var t = createModel(123);
232 var records = []; 169 var records = [];
233 subs.add(t.changes.listen((r) { records.addAll(r); })); 170 subs.add(t.changes.listen((r) {
171 records.addAll(r);
172 }));
234 t.notifyChange(new PropertyChangeRecord(t, #value, 123, 42)); 173 t.notifyChange(new PropertyChangeRecord(t, #value, 123, 42));
235 174
236 return new Future(() { 175 return new Future(() {
237 expectPropertyChanges(records, 1); 176 expectPropertyChanges(records, 1);
238 expect(t.value, 123, reason: 'value did not actually change.'); 177 expect(t.value, 123, reason: 'value did not actually change.');
239 }); 178 });
240 }); 179 });
241 180
242 test('notifyPropertyChange', () { 181 test('notifyPropertyChange', () {
243 var t = createModel(123); 182 var t = createModel(123);
244 var records = null; 183 var records;
245 subs.add(t.changes.listen((r) { records = r; })); 184 subs.add(t.changes.listen((r) {
185 records = r;
186 }));
246 expect(t.notifyPropertyChange(#value, t.value, 42), 42, 187 expect(t.notifyPropertyChange(#value, t.value, 42), 42,
247 reason: 'notifyPropertyChange returns newValue'); 188 reason: 'notifyPropertyChange returns newValue');
248 189
249 return new Future(() { 190 return new Future(() {
250 expectPropertyChanges(records, 1); 191 expectPropertyChanges(records, 1);
251 expect(t.value, 123, reason: 'value did not actually change.'); 192 expect(t.value, 123, reason: 'value did not actually change.');
252 }); 193 });
253 }); 194 });
254 } 195 }
255 196
256 expectPropertyChanges(records, int number) { 197 expectPropertyChanges(records, int number) {
257 expect(records.length, number, reason: 'expected $number change records'); 198 expect(records.length, number, reason: 'expected $number change records');
258 for (var record in records) { 199 for (var record in records) {
259 expect(record is PropertyChangeRecord, true, reason: 200 expect(record is PropertyChangeRecord, true,
260 'record should be PropertyChangeRecord'); 201 reason: 'record should be PropertyChangeRecord');
261 expect((record as PropertyChangeRecord).name, #value, reason: 202 expect((record as PropertyChangeRecord).name, #value,
262 'record should indicate a change to the "value" property'); 203 reason: 'record should indicate a change to the "value" property');
263 } 204 }
264 } 205 }
265 206
266 // A test model based on dirty checking. 207 createModel(int number) => new ObservableSubclass(number);
267 class WatcherModel<T> extends Observable {
268 @observable T value;
269 208
270 WatcherModel([T initialValue]) : value = initialValue; 209 class ObservableSubclass<T> extends Observable {
210 ObservableSubclass([T initialValue]) : _value = initialValue;
211
212 T get value => _value;
213 set value(T newValue) {
214 T oldValue = _value;
215 _value = newValue;
216 notifyPropertyChange(#value, oldValue, newValue);
217 }
218
219 T _value;
271 220
272 String toString() => '#<$runtimeType value: $value>'; 221 String toString() => '#<$runtimeType value: $value>';
273 } 222 }
274
275 class ModelSubclass<T> extends WatcherModel<T> {
276 ModelSubclass([T initialValue]) : super(initialValue);
277 }
OLDNEW
« no previous file with comments | « packages/observable/test/observable_map_test.dart ('k') | packages/observable/test/observable_test_utils.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698