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