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