| OLD | NEW |
| (Empty) |
| 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 | |
| 3 // BSD-style license that can be found in the LICENSE file. | |
| 4 | |
| 5 import 'dart:async'; | |
| 6 import 'package:observe/observe.dart'; | |
| 7 import 'package:unittest/unittest.dart'; | |
| 8 import 'observe_test_utils.dart'; | |
| 9 | |
| 10 // This file contains code ported from: | |
| 11 // https://github.com/rafaelw/ChangeSummary/blob/master/tests/test.js | |
| 12 | |
| 13 main() => dirtyCheckZone().run(listChangeTests); | |
| 14 | |
| 15 // TODO(jmesserly): port or write array fuzzer tests | |
| 16 listChangeTests() { | |
| 17 StreamSubscription sub; | |
| 18 var model; | |
| 19 | |
| 20 tearDown(() { | |
| 21 sub.cancel(); | |
| 22 model = null; | |
| 23 }); | |
| 24 | |
| 25 _delta(i, r, a) => new ListChangeRecord(model, i, removed: r, addedCount: a); | |
| 26 | |
| 27 test('sequential adds', () { | |
| 28 model = toObservable([]); | |
| 29 model.add(0); | |
| 30 | |
| 31 var summary; | |
| 32 sub = model.listChanges.listen((r) { summary = r; }); | |
| 33 | |
| 34 model.add(1); | |
| 35 model.add(2); | |
| 36 | |
| 37 expect(summary, null); | |
| 38 return new Future(() => expectChanges(summary, [_delta(1, [], 2)])); | |
| 39 }); | |
| 40 | |
| 41 test('List Splice Truncate And Expand With Length', () { | |
| 42 model = toObservable(['a', 'b', 'c', 'd', 'e']); | |
| 43 | |
| 44 var summary; | |
| 45 sub = model.listChanges.listen((r) { summary = r; }); | |
| 46 | |
| 47 model.length = 2; | |
| 48 | |
| 49 return new Future(() { | |
| 50 expectChanges(summary, [_delta(2, ['c', 'd', 'e'], 0)]); | |
| 51 summary = null; | |
| 52 model.length = 5; | |
| 53 | |
| 54 }).then(newMicrotask).then((_) { | |
| 55 | |
| 56 expectChanges(summary, [_delta(2, [], 3)]); | |
| 57 }); | |
| 58 }); | |
| 59 | |
| 60 group('List deltas can be applied', () { | |
| 61 | |
| 62 applyAndCheckDeltas(model, copy, changes) => changes.then((summary) { | |
| 63 // apply deltas to the copy | |
| 64 for (var delta in summary) { | |
| 65 copy.removeRange(delta.index, delta.index + delta.removed.length); | |
| 66 for (int i = delta.addedCount - 1; i >= 0; i--) { | |
| 67 copy.insert(delta.index, model[delta.index + i]); | |
| 68 } | |
| 69 } | |
| 70 | |
| 71 // Note: compare strings for easier debugging. | |
| 72 expect('$copy', '$model', reason: 'summary $summary'); | |
| 73 }); | |
| 74 | |
| 75 test('Contained', () { | |
| 76 var model = toObservable(['a', 'b']); | |
| 77 var copy = model.toList(); | |
| 78 var changes = model.listChanges.first; | |
| 79 | |
| 80 model.removeAt(1); | |
| 81 model.insertAll(0, ['c', 'd', 'e']); | |
| 82 model.removeRange(1, 3); | |
| 83 model.insert(1, 'f'); | |
| 84 | |
| 85 return applyAndCheckDeltas(model, copy, changes); | |
| 86 }); | |
| 87 | |
| 88 test('Delete Empty', () { | |
| 89 var model = toObservable([1]); | |
| 90 var copy = model.toList(); | |
| 91 var changes = model.listChanges.first; | |
| 92 | |
| 93 model.removeAt(0); | |
| 94 model.insertAll(0, ['a', 'b', 'c']); | |
| 95 | |
| 96 return applyAndCheckDeltas(model, copy, changes); | |
| 97 }); | |
| 98 | |
| 99 test('Right Non Overlap', () { | |
| 100 var model = toObservable(['a', 'b', 'c', 'd']); | |
| 101 var copy = model.toList(); | |
| 102 var changes = model.listChanges.first; | |
| 103 | |
| 104 model.removeRange(0, 1); | |
| 105 model.insert(0, 'e'); | |
| 106 model.removeRange(2, 3); | |
| 107 model.insertAll(2, ['f', 'g']); | |
| 108 | |
| 109 return applyAndCheckDeltas(model, copy, changes); | |
| 110 }); | |
| 111 | |
| 112 test('Left Non Overlap', () { | |
| 113 var model = toObservable(['a', 'b', 'c', 'd']); | |
| 114 var copy = model.toList(); | |
| 115 var changes = model.listChanges.first; | |
| 116 | |
| 117 model.removeRange(3, 4); | |
| 118 model.insertAll(3, ['f', 'g']); | |
| 119 model.removeRange(0, 1); | |
| 120 model.insert(0, 'e'); | |
| 121 | |
| 122 return applyAndCheckDeltas(model, copy, changes); | |
| 123 }); | |
| 124 | |
| 125 test('Right Adjacent', () { | |
| 126 var model = toObservable(['a', 'b', 'c', 'd']); | |
| 127 var copy = model.toList(); | |
| 128 var changes = model.listChanges.first; | |
| 129 | |
| 130 model.removeRange(1, 2); | |
| 131 model.insert(3, 'e'); | |
| 132 model.removeRange(2, 3); | |
| 133 model.insertAll(0, ['f', 'g']); | |
| 134 | |
| 135 return applyAndCheckDeltas(model, copy, changes); | |
| 136 }); | |
| 137 | |
| 138 test('Left Adjacent', () { | |
| 139 var model = toObservable(['a', 'b', 'c', 'd']); | |
| 140 var copy = model.toList(); | |
| 141 var changes = model.listChanges.first; | |
| 142 | |
| 143 model.removeRange(2, 4); | |
| 144 model.insert(2, 'e'); | |
| 145 | |
| 146 model.removeAt(1); | |
| 147 model.insertAll(1, ['f', 'g']); | |
| 148 | |
| 149 return applyAndCheckDeltas(model, copy, changes); | |
| 150 }); | |
| 151 | |
| 152 test('Right Overlap', () { | |
| 153 var model = toObservable(['a', 'b', 'c', 'd']); | |
| 154 var copy = model.toList(); | |
| 155 var changes = model.listChanges.first; | |
| 156 | |
| 157 model.removeAt(1); | |
| 158 model.insert(1, 'e'); | |
| 159 model.removeAt(1); | |
| 160 model.insertAll(1, ['f', 'g']); | |
| 161 | |
| 162 return applyAndCheckDeltas(model, copy, changes); | |
| 163 }); | |
| 164 | |
| 165 test('Left Overlap', () { | |
| 166 var model = toObservable(['a', 'b', 'c', 'd']); | |
| 167 var copy = model.toList(); | |
| 168 var changes = model.listChanges.first; | |
| 169 | |
| 170 model.removeAt(2); | |
| 171 model.insertAll(2, ['e', 'f', 'g']); | |
| 172 // a b [e f g] d | |
| 173 model.removeRange(1, 3); | |
| 174 model.insertAll(1, ['h', 'i', 'j']); | |
| 175 // a [h i j] f g d | |
| 176 | |
| 177 return applyAndCheckDeltas(model, copy, changes); | |
| 178 }); | |
| 179 | |
| 180 test('Prefix And Suffix One In', () { | |
| 181 var model = toObservable(['a', 'b', 'c', 'd']); | |
| 182 var copy = model.toList(); | |
| 183 var changes = model.listChanges.first; | |
| 184 | |
| 185 model.insert(0, 'z'); | |
| 186 model.add('z'); | |
| 187 | |
| 188 return applyAndCheckDeltas(model, copy, changes); | |
| 189 }); | |
| 190 | |
| 191 test('Remove First', () { | |
| 192 var model = toObservable([16, 15, 15]); | |
| 193 var copy = model.toList(); | |
| 194 var changes = model.listChanges.first; | |
| 195 | |
| 196 model.removeAt(0); | |
| 197 | |
| 198 return applyAndCheckDeltas(model, copy, changes); | |
| 199 }); | |
| 200 | |
| 201 test('Update Remove', () { | |
| 202 var model = toObservable(['a', 'b', 'c', 'd']); | |
| 203 var copy = model.toList(); | |
| 204 var changes = model.listChanges.first; | |
| 205 | |
| 206 model.removeAt(2); | |
| 207 model.insertAll(2, ['e', 'f', 'g']); // a b [e f g] d | |
| 208 model[0] = 'h'; | |
| 209 model.removeAt(1); | |
| 210 | |
| 211 return applyAndCheckDeltas(model, copy, changes); | |
| 212 }); | |
| 213 | |
| 214 test('Remove Mid List', () { | |
| 215 var model = toObservable(['a', 'b', 'c', 'd']); | |
| 216 var copy = model.toList(); | |
| 217 var changes = model.listChanges.first; | |
| 218 | |
| 219 model.removeAt(2); | |
| 220 | |
| 221 return applyAndCheckDeltas(model, copy, changes); | |
| 222 }); | |
| 223 }); | |
| 224 | |
| 225 group('edit distance', () { | |
| 226 | |
| 227 assertEditDistance(orig, changes, expectedDist) => changes.then((summary) { | |
| 228 var actualDistance = 0; | |
| 229 for (var delta in summary) { | |
| 230 actualDistance += delta.addedCount + delta.removed.length; | |
| 231 } | |
| 232 | |
| 233 expect(actualDistance, expectedDist); | |
| 234 }); | |
| 235 | |
| 236 test('add items', () { | |
| 237 var model = toObservable([]); | |
| 238 var changes = model.listChanges.first; | |
| 239 model.addAll([1, 2, 3]); | |
| 240 return assertEditDistance(model, changes, 3); | |
| 241 }); | |
| 242 | |
| 243 test('trunacte and add, sharing a contiguous block', () { | |
| 244 var model = toObservable(['x', 'x', 'x', 'x', '1', '2', '3']); | |
| 245 var changes = model.listChanges.first; | |
| 246 model.length = 0; | |
| 247 model.addAll(['1', '2', '3', 'y', 'y', 'y', 'y']); | |
| 248 return assertEditDistance(model, changes, 8); | |
| 249 }); | |
| 250 | |
| 251 test('truncate and add, sharing a discontiguous block', () { | |
| 252 var model = toObservable(['1', '2', '3', '4', '5']); | |
| 253 var changes = model.listChanges.first; | |
| 254 model.length = 0; | |
| 255 model.addAll(['a', '2', 'y', 'y', '4', '5', 'z', 'z']); | |
| 256 return assertEditDistance(model, changes, 7); | |
| 257 }); | |
| 258 | |
| 259 test('insert at beginning and end', () { | |
| 260 var model = toObservable([2, 3, 4]); | |
| 261 var changes = model.listChanges.first; | |
| 262 model.insert(0, 5); | |
| 263 model[2] = 6; | |
| 264 model.add(7); | |
| 265 return assertEditDistance(model, changes, 4); | |
| 266 }); | |
| 267 }); | |
| 268 } | |
| OLD | NEW |