OLD | NEW |
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:logging/logging.dart'; | 6 import 'package:logging/logging.dart'; |
7 import 'package:observe/observe.dart'; | 7 import 'package:observe/observe.dart'; |
8 import 'package:observe/src/dirty_check.dart' as dirty_check; | 8 import 'package:observe/src/dirty_check.dart' as dirty_check; |
9 import 'package:unittest/unittest.dart'; | 9 import 'package:unittest/unittest.dart'; |
10 import 'observe_test_utils.dart'; | 10 import 'observe_test_utils.dart'; |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
54 expect(messages[0], contains('Possible loop')); | 54 expect(messages[0], contains('Possible loop')); |
55 expect(messages[1], contains('index 0')); | 55 expect(messages[1], contains('index 0')); |
56 expect(messages[1], contains('object: $x')); | 56 expect(messages[1], contains('object: $x')); |
57 | 57 |
58 sub.cancel(); | 58 sub.cancel(); |
59 }); | 59 }); |
60 }); | 60 }); |
61 } | 61 } |
62 | 62 |
63 void _observeTests(createModel(x)) { | 63 void _observeTests(createModel(x)) { |
64 final watch = createModel(null) is! ChangeNotifierMixin; | 64 final watch = createModel(null) is! ChangeNotifier; |
65 | 65 |
66 // Track the subscriptions so we can clean them up in tearDown. | 66 // Track the subscriptions so we can clean them up in tearDown. |
67 List subs; | 67 List subs; |
68 | 68 |
69 int initialObservers; | 69 int initialObservers; |
70 setUp(() { | 70 setUp(() { |
71 initialObservers = dirty_check.allObservablesCount; | 71 initialObservers = dirty_check.allObservablesCount; |
72 subs = []; | 72 subs = []; |
73 | 73 |
74 if (watch) scheduleMicrotask(Observable.dirtyCheck); | 74 if (watch) scheduleMicrotask(Observable.dirtyCheck); |
(...skipping 27 matching lines...) Expand all Loading... |
102 subs.add(t.changes.listen((n) {})); | 102 subs.add(t.changes.listen((n) {})); |
103 expect(t.hasObservers, true); | 103 expect(t.hasObservers, true); |
104 }); | 104 }); |
105 | 105 |
106 observeTest('changes delived async', () { | 106 observeTest('changes delived async', () { |
107 var t = createModel(123); | 107 var t = createModel(123); |
108 int called = 0; | 108 int called = 0; |
109 | 109 |
110 subs.add(t.changes.listen(expectAsync1((records) { | 110 subs.add(t.changes.listen(expectAsync1((records) { |
111 called++; | 111 called++; |
112 expectChanges(records, _changedValue(watch ? 1 : 2)); | 112 expectPropertyChanges(records, watch ? 1 : 2); |
113 }))); | 113 }))); |
114 | 114 |
115 t.value = 41; | 115 t.value = 41; |
116 t.value = 42; | 116 t.value = 42; |
117 expect(called, 0); | 117 expect(called, 0); |
118 }); | 118 }); |
119 | 119 |
120 observeTest('cause changes in handler', () { | 120 observeTest('cause changes in handler', () { |
121 var t = createModel(123); | 121 var t = createModel(123); |
122 int called = 0; | 122 int called = 0; |
123 | 123 |
124 subs.add(t.changes.listen(expectAsync1((records) { | 124 subs.add(t.changes.listen(expectAsync1((records) { |
125 called++; | 125 called++; |
126 expectChanges(records, _changedValue(1)); | 126 expectPropertyChanges(records, 1); |
127 if (called == 1) { | 127 if (called == 1) { |
128 // Cause another change | 128 // Cause another change |
129 t.value = 777; | 129 t.value = 777; |
130 } | 130 } |
131 }, count: 2))); | 131 }, count: 2))); |
132 | 132 |
133 t.value = 42; | 133 t.value = 42; |
134 }); | 134 }); |
135 | 135 |
136 observeTest('multiple observers', () { | 136 observeTest('multiple observers', () { |
137 var t = createModel(123); | 137 var t = createModel(123); |
138 | 138 |
139 verifyRecords(records) { | 139 verifyRecords(records) { |
140 expectChanges(records, _changedValue(watch ? 1 : 2)); | 140 expectPropertyChanges(records, watch ? 1 : 2); |
141 }; | 141 }; |
142 | 142 |
143 subs.add(t.changes.listen(expectAsync1(verifyRecords))); | 143 subs.add(t.changes.listen(expectAsync1(verifyRecords))); |
144 subs.add(t.changes.listen(expectAsync1(verifyRecords))); | 144 subs.add(t.changes.listen(expectAsync1(verifyRecords))); |
145 | 145 |
146 t.value = 41; | 146 t.value = 41; |
147 t.value = 42; | 147 t.value = 42; |
148 }); | 148 }); |
149 | 149 |
150 observeTest('performMicrotaskCheckpoint', () { | 150 observeTest('performMicrotaskCheckpoint', () { |
151 var t = createModel(123); | 151 var t = createModel(123); |
152 var records = []; | 152 var records = []; |
153 subs.add(t.changes.listen((r) { records.addAll(r); })); | 153 subs.add(t.changes.listen((r) { records.addAll(r); })); |
154 t.value = 41; | 154 t.value = 41; |
155 t.value = 42; | 155 t.value = 42; |
156 expectChanges(records, [], reason: 'changes delived async'); | 156 expectChanges(records, [], reason: 'changes delived async'); |
157 | 157 |
158 performMicrotaskCheckpoint(); | 158 performMicrotaskCheckpoint(); |
159 expectChanges(records, _changedValue(watch ? 1 : 2)); | 159 expectPropertyChanges(records, watch ? 1 : 2); |
160 records.clear(); | 160 records.clear(); |
161 | 161 |
162 t.value = 777; | 162 t.value = 777; |
163 expectChanges(records, [], reason: 'changes delived async'); | 163 expectChanges(records, [], reason: 'changes delived async'); |
164 | 164 |
165 performMicrotaskCheckpoint(); | 165 performMicrotaskCheckpoint(); |
166 expectChanges(records, _changedValue(1)); | 166 expectPropertyChanges(records, 1); |
167 | 167 |
168 // Has no effect if there are no changes | 168 // Has no effect if there are no changes |
169 performMicrotaskCheckpoint(); | 169 performMicrotaskCheckpoint(); |
170 expectChanges(records, _changedValue(1)); | 170 expectPropertyChanges(records, 1); |
171 }); | 171 }); |
172 | 172 |
173 observeTest('cancel listening', () { | 173 observeTest('cancel listening', () { |
174 var t = createModel(123); | 174 var t = createModel(123); |
175 var sub; | 175 var sub; |
176 sub = t.changes.listen(expectAsync1((records) { | 176 sub = t.changes.listen(expectAsync1((records) { |
177 expectChanges(records, _changedValue(1)); | 177 expectPropertyChanges(records, 1); |
178 sub.cancel(); | 178 sub.cancel(); |
179 t.value = 777; | 179 t.value = 777; |
180 scheduleMicrotask(Observable.dirtyCheck); | 180 scheduleMicrotask(Observable.dirtyCheck); |
181 })); | 181 })); |
182 t.value = 42; | 182 t.value = 42; |
183 }); | 183 }); |
184 | 184 |
185 observeTest('cancel and reobserve', () { | 185 observeTest('cancel and reobserve', () { |
186 var t = createModel(123); | 186 var t = createModel(123); |
187 var sub; | 187 var sub; |
188 sub = t.changes.listen(expectAsync1((records) { | 188 sub = t.changes.listen(expectAsync1((records) { |
189 expectChanges(records, _changedValue(1)); | 189 expectPropertyChanges(records, 1); |
190 sub.cancel(); | 190 sub.cancel(); |
191 | 191 |
192 scheduleMicrotask(expectAsync0(() { | 192 scheduleMicrotask(expectAsync0(() { |
193 subs.add(t.changes.listen(expectAsync1((records) { | 193 subs.add(t.changes.listen(expectAsync1((records) { |
194 expectChanges(records, _changedValue(1)); | 194 expectPropertyChanges(records, 1); |
195 }))); | 195 }))); |
196 t.value = 777; | 196 t.value = 777; |
197 scheduleMicrotask(Observable.dirtyCheck); | 197 scheduleMicrotask(Observable.dirtyCheck); |
198 })); | 198 })); |
199 })); | 199 })); |
200 t.value = 42; | 200 t.value = 42; |
201 }); | 201 }); |
202 | 202 |
203 observeTest('cannot modify changes list', () { | 203 observeTest('cannot modify changes list', () { |
204 var t = createModel(123); | 204 var t = createModel(123); |
205 var records = null; | 205 var records = null; |
206 subs.add(t.changes.listen((r) { records = r; })); | 206 subs.add(t.changes.listen((r) { records = r; })); |
207 t.value = 42; | 207 t.value = 42; |
208 | 208 |
209 performMicrotaskCheckpoint(); | 209 performMicrotaskCheckpoint(); |
210 expectChanges(records, _changedValue(1)); | 210 expectPropertyChanges(records, 1); |
211 | 211 |
212 // Verify that mutation operations on the list fail: | 212 // Verify that mutation operations on the list fail: |
213 | 213 |
214 expect(() { | 214 expect(() { |
215 records[0] = new PropertyChangeRecord(#value); | 215 records[0] = new PropertyChangeRecord(t, #value, 0, 1); |
216 }, throwsUnsupportedError); | 216 }, throwsUnsupportedError); |
217 | 217 |
218 expect(() { records.clear(); }, throwsUnsupportedError); | 218 expect(() { records.clear(); }, throwsUnsupportedError); |
219 | 219 |
220 expect(() { records.length = 0; }, throwsUnsupportedError); | 220 expect(() { records.length = 0; }, throwsUnsupportedError); |
221 }); | 221 }); |
222 | 222 |
223 observeTest('notifyChange', () { | 223 observeTest('notifyChange', () { |
224 var t = createModel(123); | 224 var t = createModel(123); |
225 var records = []; | 225 var records = []; |
226 subs.add(t.changes.listen((r) { records.addAll(r); })); | 226 subs.add(t.changes.listen((r) { records.addAll(r); })); |
227 t.notifyChange(new PropertyChangeRecord(#value)); | 227 t.notifyChange(new PropertyChangeRecord(t, #value, 123, 42)); |
228 | 228 |
229 performMicrotaskCheckpoint(); | 229 performMicrotaskCheckpoint(); |
230 expectChanges(records, _changedValue(1)); | 230 expectPropertyChanges(records, 1); |
231 expect(t.value, 123, reason: 'value did not actually change.'); | 231 expect(t.value, 123, reason: 'value did not actually change.'); |
232 }); | 232 }); |
233 | 233 |
234 observeTest('notifyPropertyChange', () { | 234 observeTest('notifyPropertyChange', () { |
235 var t = createModel(123); | 235 var t = createModel(123); |
236 var records = null; | 236 var records = null; |
237 subs.add(t.changes.listen((r) { records = r; })); | 237 subs.add(t.changes.listen((r) { records = r; })); |
238 expect(t.notifyPropertyChange(#value, t.value, 42), 42, | 238 expect(t.notifyPropertyChange(#value, t.value, 42), 42, |
239 reason: 'notifyPropertyChange returns newValue'); | 239 reason: 'notifyPropertyChange returns newValue'); |
240 | 240 |
241 performMicrotaskCheckpoint(); | 241 performMicrotaskCheckpoint(); |
242 expectChanges(records, _changedValue(1)); | 242 expectPropertyChanges(records, 1); |
243 expect(t.value, 123, reason: 'value did not actually change.'); | 243 expect(t.value, 123, reason: 'value did not actually change.'); |
244 }); | 244 }); |
245 } | 245 } |
246 | 246 |
247 _changedValue(len) => new List.filled(len, new PropertyChangeRecord(#value)); | 247 expectPropertyChanges(records, int number) { |
| 248 expect(records.length, number, reason: 'expected $number change records'); |
| 249 for (var record in records) { |
| 250 expect(record is PropertyChangeRecord, true, reason: |
| 251 'record should be PropertyChangeRecord'); |
| 252 expect((record as PropertyChangeRecord).name, #value, reason: |
| 253 'record should indicate a change to the "value" property'); |
| 254 } |
| 255 } |
248 | 256 |
249 // A test model based on dirty checking. | 257 // A test model based on dirty checking. |
250 class WatcherModel<T> extends ObservableBase { | 258 class WatcherModel<T> extends Observable { |
251 @observable T value; | 259 @observable T value; |
252 | 260 |
253 WatcherModel([T initialValue]) : value = initialValue; | 261 WatcherModel([T initialValue]) : value = initialValue; |
254 | 262 |
255 String toString() => '#<$runtimeType value: $value>'; | 263 String toString() => '#<$runtimeType value: $value>'; |
256 } | 264 } |
257 | 265 |
258 class ModelSubclass<T> extends WatcherModel<T> { | 266 class ModelSubclass<T> extends WatcherModel<T> { |
259 ModelSubclass([T initialValue]) : super(initialValue); | 267 ModelSubclass([T initialValue]) : super(initialValue); |
260 } | 268 } |
OLD | NEW |