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:observe/observe.dart'; | 6 import 'package:observe/observe.dart'; |
7 import 'package:unittest/unittest.dart'; | 7 import 'package:unittest/unittest.dart'; |
8 import 'observe_test_utils.dart'; | 8 import 'observe_test_utils.dart'; |
9 | 9 |
10 // This file contains code ported from: | 10 // This file contains code ported from: |
11 // https://github.com/rafaelw/ChangeSummary/blob/master/tests/test.js | 11 // https://github.com/rafaelw/ChangeSummary/blob/master/tests/test.js |
12 | 12 |
13 main() { | 13 main() { |
14 // TODO(jmesserly): rename this? Is summarizeListChanges coming back? | 14 // TODO(jmesserly): rename this? Is summarizeListChanges coming back? |
15 group('summarizeListChanges', listChangeTests); | 15 group('summarizeListChanges', listChangeTests); |
16 } | 16 } |
17 | 17 |
18 // TODO(jmesserly): port or write array fuzzer tests | 18 // TODO(jmesserly): port or write array fuzzer tests |
19 listChangeTests() { | 19 listChangeTests() { |
20 StreamSubscription sub; | 20 StreamSubscription sub; |
| 21 var model; |
21 | 22 |
22 tearDown(() { sub.cancel(); }); | 23 tearDown(() { |
| 24 sub.cancel(); |
| 25 model = null; |
| 26 }); |
| 27 |
| 28 _delta(i, r, a) => new ListChangeRecord(model, i, removed: r, addedCount: a); |
23 | 29 |
24 observeTest('sequential adds', () { | 30 observeTest('sequential adds', () { |
25 var model = toObservable([]); | 31 model = toObservable([]); |
26 model.add(0); | 32 model.add(0); |
27 | 33 |
28 var summary; | 34 var summary; |
29 sub = model.changes.listen((r) { summary = _filter(r); }); | 35 sub = model.listChanges.listen((r) { summary = r; }); |
30 | 36 |
31 model.add(1); | 37 model.add(1); |
32 model.add(2); | 38 model.add(2); |
33 | 39 |
34 expect(summary, null); | 40 expect(summary, null); |
35 performMicrotaskCheckpoint(); | 41 performMicrotaskCheckpoint(); |
36 | 42 |
37 expectChanges(summary, [_delta(1, 0, 2)]); | 43 expectChanges(summary, [_delta(1, [], 2)]); |
38 }); | 44 }); |
39 | 45 |
40 observeTest('List Splice Truncate And Expand With Length', () { | 46 observeTest('List Splice Truncate And Expand With Length', () { |
41 var model = toObservable(['a', 'b', 'c', 'd', 'e']); | 47 model = toObservable(['a', 'b', 'c', 'd', 'e']); |
42 | 48 |
43 var summary; | 49 var summary; |
44 sub = model.changes.listen((r) { summary = _filter(r); }); | 50 sub = model.listChanges.listen((r) { summary = r; }); |
45 | 51 |
46 model.length = 2; | 52 model.length = 2; |
47 | 53 |
48 performMicrotaskCheckpoint(); | 54 performMicrotaskCheckpoint(); |
49 expectChanges(summary, [_delta(2, 3, 0)]); | 55 expectChanges(summary, [_delta(2, ['c', 'd', 'e'], 0)]); |
50 summary = null; | 56 summary = null; |
51 | 57 |
52 model.length = 5; | 58 model.length = 5; |
53 | 59 |
54 performMicrotaskCheckpoint(); | 60 performMicrotaskCheckpoint(); |
55 expectChanges(summary, [_delta(2, 0, 3)]); | 61 expectChanges(summary, [_delta(2, [], 3)]); |
56 }); | 62 }); |
57 | 63 |
58 group('List deltas can be applied', () { | 64 group('List deltas can be applied', () { |
59 | 65 |
60 var summary = null; | 66 var summary = null; |
61 | 67 |
62 observeArray(model) { | 68 observeArray(model) { |
63 sub = model.changes.listen((records) { summary = _filter(records); }); | 69 sub = model.listChanges.listen((r) { summary = r; }); |
64 } | 70 } |
65 | 71 |
66 applyAndCheckDeltas(model, copy) { | 72 applyAndCheckDeltas(model, copy) { |
67 summary = null; | 73 summary = null; |
68 performMicrotaskCheckpoint(); | 74 performMicrotaskCheckpoint(); |
69 | 75 |
70 // apply deltas to the copy | 76 // apply deltas to the copy |
71 for (var delta in summary) { | 77 for (var delta in summary) { |
72 copy.removeRange(delta.index, delta.index + delta.removedCount); | 78 copy.removeRange(delta.index, delta.index + delta.removed.length); |
73 for (int i = delta.addedCount - 1; i >= 0; i--) { | 79 for (int i = delta.addedCount - 1; i >= 0; i--) { |
74 copy.insert(delta.index, model[delta.index + i]); | 80 copy.insert(delta.index, model[delta.index + i]); |
75 } | 81 } |
76 } | 82 } |
77 | 83 |
78 // Note: compare strings for easier debugging. | 84 // Note: compare strings for easier debugging. |
79 expect('$copy', '$model', reason: 'summary $summary'); | 85 expect('$copy', '$model', reason: 'summary $summary'); |
80 } | 86 } |
81 | 87 |
82 observeTest('Contained', () { | 88 observeTest('Contained', () { |
(...skipping 143 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
226 model.removeAt(2); | 232 model.removeAt(2); |
227 | 233 |
228 applyAndCheckDeltas(model, copy); | 234 applyAndCheckDeltas(model, copy); |
229 }); | 235 }); |
230 }); | 236 }); |
231 | 237 |
232 group('edit distance', () { | 238 group('edit distance', () { |
233 var summary = null; | 239 var summary = null; |
234 | 240 |
235 observeArray(model) { | 241 observeArray(model) { |
236 sub = model.changes.listen((records) { summary = _filter(records); }); | 242 sub = model.listChanges.listen((r) { summary = r; }); |
237 } | 243 } |
238 | 244 |
239 assertEditDistance(orig, expectDistance) { | 245 assertEditDistance(orig, expectDistance) { |
240 summary = null; | 246 summary = null; |
241 performMicrotaskCheckpoint(); | 247 performMicrotaskCheckpoint(); |
242 var actualDistance = 0; | 248 var actualDistance = 0; |
243 | 249 |
244 if (summary != null) { | 250 if (summary != null) { |
245 for (var delta in summary) { | 251 for (var delta in summary) { |
246 actualDistance += delta.addedCount + delta.removedCount; | 252 actualDistance += delta.addedCount + delta.removed.length; |
247 } | 253 } |
248 } | 254 } |
249 | 255 |
250 expect(actualDistance, expectDistance); | 256 expect(actualDistance, expectDistance); |
251 } | 257 } |
252 | 258 |
253 observeTest('add items', () { | 259 observeTest('add items', () { |
254 var model = toObservable([]); | 260 var model = toObservable([]); |
255 observeArray(model); | 261 observeArray(model); |
256 model.addAll([1, 2, 3]); | 262 model.addAll([1, 2, 3]); |
257 assertEditDistance(model, 3); | 263 assertEditDistance(model, 3); |
258 }); | 264 }); |
259 | 265 |
260 observeTest('trunacte and add, sharing a contiguous block', () { | 266 observeTest('trunacte and add, sharing a contiguous block', () { |
261 var model = toObservable(['x', 'x', 'x', 'x', '1', '2', '3']); | 267 var model = toObservable(['x', 'x', 'x', 'x', '1', '2', '3']); |
262 observeArray(model); | 268 observeArray(model); |
263 model.length = 0; | 269 model.length = 0; |
264 model.addAll(['1', '2', '3', 'y', 'y', 'y', 'y']); | 270 model.addAll(['1', '2', '3', 'y', 'y', 'y', 'y']); |
265 // Note: unlike the JS implementation, we don't perform a full diff. | 271 assertEditDistance(model, 7); |
266 // The change records are computed with no regards to the *contents* of | |
267 // the array. Thus, we get 14 instead of 8. | |
268 assertEditDistance(model, 14); | |
269 }); | 272 }); |
270 | 273 |
271 observeTest('truncate and add, sharing a discontiguous block', () { | 274 observeTest('truncate and add, sharing a discontiguous block', () { |
272 var model = toObservable(['1', '2', '3', '4', '5']); | 275 var model = toObservable(['1', '2', '3', '4', '5']); |
273 observeArray(model); | 276 observeArray(model); |
274 model.length = 0; | 277 model.length = 0; |
275 model.addAll(['a', '2', 'y', 'y', '4', '5', 'z', 'z']); | 278 model.addAll(['a', '2', 'y', 'y', '4', '5', 'z', 'z']); |
276 // Note: unlike the JS implementation, we don't perform a full diff. | 279 assertEditDistance(model, 8); |
277 // The change records are computed with no regards to the *contents* of | |
278 // the array. Thus, we get 13 instead of 7. | |
279 assertEditDistance(model, 13); | |
280 }); | 280 }); |
281 | 281 |
282 observeTest('insert at beginning and end', () { | 282 observeTest('insert at beginning and end', () { |
283 var model = toObservable([2, 3, 4]); | 283 var model = toObservable([2, 3, 4]); |
284 observeArray(model); | 284 observeArray(model); |
285 model.insert(0, 5); | 285 model.insert(0, 5); |
286 model[2] = 6; | 286 model[2] = 6; |
287 model.add(7); | 287 model.add(7); |
288 assertEditDistance(model, 4); | 288 assertEditDistance(model, 4); |
289 }); | 289 }); |
290 }); | 290 }); |
291 } | 291 } |
292 | |
293 _delta(i, r, a) => new ListChangeRecord(i, removedCount: r, addedCount: a); | |
294 _filter(records) => records.where((r) => r is ListChangeRecord).toList(); | |
OLD | NEW |