| 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 |