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