| Index: third_party/pkg/angular/test/change_detection/dirty_checking_change_detector_spec.dart
 | 
| diff --git a/third_party/pkg/angular/test/change_detection/dirty_checking_change_detector_spec.dart b/third_party/pkg/angular/test/change_detection/dirty_checking_change_detector_spec.dart
 | 
| deleted file mode 100644
 | 
| index 0d732f2dc0b0c22c4d16522fff8d0303f49c64a9..0000000000000000000000000000000000000000
 | 
| --- a/third_party/pkg/angular/test/change_detection/dirty_checking_change_detector_spec.dart
 | 
| +++ /dev/null
 | 
| @@ -1,772 +0,0 @@
 | 
| -library dirty_chekcing_change_detector_spec;
 | 
| -
 | 
| -import '../_specs.dart';
 | 
| -import 'package:angular/change_detection/change_detection.dart';
 | 
| -import 'package:angular/change_detection/dirty_checking_change_detector.dart';
 | 
| -import 'dart:collection';
 | 
| -
 | 
| -main() => describe('DirtyCheckingChangeDetector', () {
 | 
| -  DirtyCheckingChangeDetector<String> detector;
 | 
| -
 | 
| -  beforeEach(() {
 | 
| -    GetterCache getterCache = new GetterCache({
 | 
| -      "first": (o) => o.first,
 | 
| -      "age": (o) => o.age
 | 
| -    });
 | 
| -    detector = new DirtyCheckingChangeDetector<String>(getterCache);
 | 
| -  });
 | 
| -
 | 
| -  describe('object field', () {
 | 
| -    it('should detect nothing', () {
 | 
| -      var changes = detector.collectChanges();
 | 
| -      expect(changes).toEqual(null);
 | 
| -    });
 | 
| -
 | 
| -    it('should detect field changes', () {
 | 
| -      var user = new _User('', '');
 | 
| -      var change;
 | 
| -
 | 
| -      detector
 | 
| -          ..watch(user, 'first', null)
 | 
| -          ..watch(user, 'last', null)
 | 
| -          ..collectChanges(); // throw away first set
 | 
| -
 | 
| -      change = detector.collectChanges();
 | 
| -      expect(change).toEqual(null);
 | 
| -      user..first = 'misko'
 | 
| -          ..last = 'hevery';
 | 
| -
 | 
| -      change = detector.collectChanges();
 | 
| -      expect(change.currentValue).toEqual('misko');
 | 
| -      expect(change.previousValue).toEqual('');
 | 
| -      expect(change.nextChange.currentValue).toEqual('hevery');
 | 
| -      expect(change.nextChange.previousValue).toEqual('');
 | 
| -      expect(change.nextChange.nextChange).toEqual(null);
 | 
| -
 | 
| -      // force different instance
 | 
| -      user.first = 'mis';
 | 
| -      user.first += 'ko';
 | 
| -
 | 
| -      change = detector.collectChanges();
 | 
| -      expect(change).toEqual(null);
 | 
| -
 | 
| -      user.last = 'Hevery';
 | 
| -      change = detector.collectChanges();
 | 
| -      expect(change.currentValue).toEqual('Hevery');
 | 
| -      expect(change.previousValue).toEqual('hevery');
 | 
| -      expect(change.nextChange).toEqual(null);
 | 
| -    });
 | 
| -
 | 
| -    it('should ignore NaN != NaN', () {
 | 
| -      var user = new _User();
 | 
| -      user.age = double.NAN;
 | 
| -      detector..watch(user, 'age', null)..collectChanges(); // throw away first set
 | 
| -
 | 
| -      var changes = detector.collectChanges();
 | 
| -      expect(changes).toEqual(null);
 | 
| -
 | 
| -      user.age = 123;
 | 
| -      changes = detector.collectChanges();
 | 
| -      expect(changes.currentValue).toEqual(123);
 | 
| -      expect(changes.previousValue.isNaN).toEqual(true);
 | 
| -      expect(changes.nextChange).toEqual(null);
 | 
| -    });
 | 
| -
 | 
| -    it('should treat map field dereference as []', () {
 | 
| -      var obj = {'name':'misko'};
 | 
| -      detector.watch(obj, 'name', null);
 | 
| -      detector.collectChanges(); // throw away first set
 | 
| -
 | 
| -      obj['name'] = 'Misko';
 | 
| -      var changes = detector.collectChanges();
 | 
| -      expect(changes.currentValue).toEqual('Misko');
 | 
| -      expect(changes.previousValue).toEqual('misko');
 | 
| -    });
 | 
| -  });
 | 
| -
 | 
| -  describe('insertions / removals', () {
 | 
| -    it('should insert at the end of list', () {
 | 
| -      var obj = {};
 | 
| -      var a = detector.watch(obj, 'a', 'a');
 | 
| -      var b = detector.watch(obj, 'b', 'b');
 | 
| -
 | 
| -      obj['a'] = obj['b'] = 1;
 | 
| -      var changes = detector.collectChanges();
 | 
| -      expect(changes.handler).toEqual('a');
 | 
| -      expect(changes.nextChange.handler).toEqual('b');
 | 
| -      expect(changes.nextChange.nextChange).toEqual(null);
 | 
| -
 | 
| -      obj['a'] = obj['b'] = 2;
 | 
| -      a.remove();
 | 
| -      changes = detector.collectChanges();
 | 
| -      expect(changes.handler).toEqual('b');
 | 
| -      expect(changes.nextChange).toEqual(null);
 | 
| -
 | 
| -      obj['a'] = obj['b'] = 3;
 | 
| -      b.remove();
 | 
| -      changes = detector.collectChanges();
 | 
| -      expect(changes).toEqual(null);
 | 
| -    });
 | 
| -
 | 
| -    it('should remove all watches in group and group\'s children', () {
 | 
| -      var obj = {};
 | 
| -      detector.watch(obj, 'a', '0a');
 | 
| -      var child1a = detector.newGroup();
 | 
| -      var child1b = detector.newGroup();
 | 
| -      var child2 = child1a.newGroup();
 | 
| -      child1a.watch(obj,'a', '1a');
 | 
| -      child1b.watch(obj,'a', '1b');
 | 
| -      detector.watch(obj, 'a', '0A');
 | 
| -      child1a.watch(obj,'a', '1A');
 | 
| -      child2.watch(obj,'a', '2A');
 | 
| -
 | 
| -      obj['a'] = 1;
 | 
| -      expect(detector.collectChanges(),
 | 
| -          toEqualChanges(['0a', '0A', '1a', '1A', '2A', '1b']));
 | 
| -
 | 
| -      obj['a'] = 2;
 | 
| -      child1a.remove(); // should also remove child2
 | 
| -      expect(detector.collectChanges(), toEqualChanges(['0a', '0A', '1b']));
 | 
| -    });
 | 
| -
 | 
| -    it('should add watches within its own group', () {
 | 
| -      var obj = {};
 | 
| -      var ra = detector.watch(obj, 'a', 'a');
 | 
| -      var child = detector.newGroup();
 | 
| -      var cb = child.watch(obj,'b', 'b');
 | 
| -
 | 
| -      obj['a'] = obj['b'] = 1;
 | 
| -      expect(detector.collectChanges(), toEqualChanges(['a', 'b']));
 | 
| -
 | 
| -      obj['a'] = obj['b'] = 2;
 | 
| -      ra.remove();
 | 
| -      expect(detector.collectChanges(), toEqualChanges(['b']));
 | 
| -
 | 
| -      obj['a'] = obj['b'] = 3;
 | 
| -      cb.remove();
 | 
| -      expect(detector.collectChanges(), toEqualChanges([]));
 | 
| -
 | 
| -      // TODO: add them back in wrong order, assert events in right order
 | 
| -      cb = child.watch(obj,'b', 'b');
 | 
| -      ra = detector.watch(obj, 'a', 'a');
 | 
| -      obj['a'] = obj['b'] = 4;
 | 
| -      expect(detector.collectChanges(), toEqualChanges(['a', 'b']));
 | 
| -    });
 | 
| -
 | 
| -    it('should properly add children', () {
 | 
| -      var a = detector.newGroup();
 | 
| -      var aChild = a.newGroup();
 | 
| -      var b = detector.newGroup();
 | 
| -      expect(detector.collectChanges).not.toThrow();
 | 
| -    });
 | 
| -  });
 | 
| -
 | 
| -  describe('list watching', () {
 | 
| -    it('should detect changes in list', () {
 | 
| -      var list = [];
 | 
| -      var record = detector.watch(list, null, 'handler');
 | 
| -      expect(detector.collectChanges()).toEqual(null);
 | 
| -
 | 
| -      list.add('a');
 | 
| -      expect(detector.collectChanges().currentValue, toEqualCollectionRecord(
 | 
| -          collection: ['a[null -> 0]'],
 | 
| -          additions: ['a[null -> 0]'],
 | 
| -          moves: [],
 | 
| -          removals: []));
 | 
| -
 | 
| -      list.add('b');
 | 
| -      expect(detector.collectChanges().currentValue, toEqualCollectionRecord(
 | 
| -          collection: ['a', 'b[null -> 1]'],
 | 
| -          additions: ['b[null -> 1]'],
 | 
| -          moves: [],
 | 
| -          removals: []));
 | 
| -
 | 
| -      list.add('c');
 | 
| -      list.add('d');
 | 
| -      expect(detector.collectChanges().currentValue, toEqualCollectionRecord(
 | 
| -          collection: ['a', 'b', 'c[null -> 2]', 'd[null -> 3]'],
 | 
| -          additions: ['c[null -> 2]', 'd[null -> 3]'],
 | 
| -          moves: [],
 | 
| -          removals: []));
 | 
| -
 | 
| -      list.remove('c');
 | 
| -      expect(list).toEqual(['a', 'b', 'd']);
 | 
| -      expect(detector.collectChanges().currentValue, toEqualCollectionRecord(
 | 
| -          collection: ['a', 'b', 'd[3 -> 2]'],
 | 
| -          additions: [],
 | 
| -          moves: ['d[3 -> 2]'],
 | 
| -          removals: ['c[2 -> null]']));
 | 
| -
 | 
| -      list.clear();
 | 
| -      list.addAll(['d', 'c', 'b', 'a']);
 | 
| -      expect(detector.collectChanges().currentValue, toEqualCollectionRecord(
 | 
| -          collection: ['d[2 -> 0]', 'c[null -> 1]', 'b[1 -> 2]', 'a[0 -> 3]'],
 | 
| -          additions: ['c[null -> 1]'],
 | 
| -          moves: ['d[2 -> 0]', 'b[1 -> 2]', 'a[0 -> 3]'],
 | 
| -          removals: []));
 | 
| -    });
 | 
| -
 | 
| -    it('should detect changes in list', () {
 | 
| -      var list = [];
 | 
| -      var record = detector.watch(list.map((i) => i), null, 'handler');
 | 
| -      expect(detector.collectChanges()).toEqual(null);
 | 
| -
 | 
| -      list.add('a');
 | 
| -      expect(detector.collectChanges().currentValue, toEqualCollectionRecord(
 | 
| -          collection: ['a[null -> 0]'],
 | 
| -          additions: ['a[null -> 0]'],
 | 
| -          moves: [],
 | 
| -          removals: []));
 | 
| -
 | 
| -      list.add('b');
 | 
| -      expect(detector.collectChanges().currentValue, toEqualCollectionRecord(
 | 
| -          collection: ['a', 'b[null -> 1]'],
 | 
| -          additions: ['b[null -> 1]'],
 | 
| -          moves: [],
 | 
| -          removals: []));
 | 
| -
 | 
| -      list.add('c');
 | 
| -      list.add('d');
 | 
| -      expect(detector.collectChanges().currentValue, toEqualCollectionRecord(
 | 
| -          collection: ['a', 'b', 'c[null -> 2]', 'd[null -> 3]'],
 | 
| -          additions: ['c[null -> 2]', 'd[null -> 3]'],
 | 
| -          moves: [],
 | 
| -          removals: []));
 | 
| -
 | 
| -      list.remove('c');
 | 
| -      expect(list).toEqual(['a', 'b', 'd']);
 | 
| -      expect(detector.collectChanges().currentValue, toEqualCollectionRecord(
 | 
| -          collection: ['a', 'b', 'd[3 -> 2]'],
 | 
| -          additions: [],
 | 
| -          moves: ['d[3 -> 2]'],
 | 
| -          removals: ['c[2 -> null]']));
 | 
| -
 | 
| -      list.clear();
 | 
| -      list.addAll(['d', 'c', 'b', 'a']);
 | 
| -      expect(detector.collectChanges().currentValue, toEqualCollectionRecord(
 | 
| -          collection: ['d[2 -> 0]', 'c[null -> 1]', 'b[1 -> 2]', 'a[0 -> 3]'],
 | 
| -          additions: ['c[null -> 1]'],
 | 
| -          moves: ['d[2 -> 0]', 'b[1 -> 2]', 'a[0 -> 3]'],
 | 
| -          removals: []));
 | 
| -    });
 | 
| -
 | 
| -    it('should test string by value rather than by reference', () {
 | 
| -      var list = ['a', 'boo'];
 | 
| -      detector..watch(list, null, null)..collectChanges();
 | 
| -
 | 
| -      list[1] = 'b' + 'oo';
 | 
| -
 | 
| -      expect(detector.collectChanges()).toEqual(null);
 | 
| -    });
 | 
| -
 | 
| -    it('should ignore [NaN] != [NaN]', () {
 | 
| -      var list = [double.NAN];
 | 
| -      var record = detector..watch(list, null, null)..collectChanges();
 | 
| -
 | 
| -      expect(detector.collectChanges()).toEqual(null);
 | 
| -    });
 | 
| -
 | 
| -    it('should remove and add same item', () {
 | 
| -      var list = ['a', 'b', 'c'];
 | 
| -      var record = detector.watch(list, null, 'handler');
 | 
| -      detector.collectChanges();
 | 
| -
 | 
| -      list.remove('b');
 | 
| -      expect(detector.collectChanges().currentValue, toEqualCollectionRecord(
 | 
| -          collection: ['a', 'c[2 -> 1]'],
 | 
| -          additions: [],
 | 
| -          moves: ['c[2 -> 1]'],
 | 
| -          removals: ['b[1 -> null]']));
 | 
| -
 | 
| -      list.insert(1, 'b');
 | 
| -      expect(list).toEqual(['a', 'b', 'c']);
 | 
| -      expect(detector.collectChanges().currentValue, toEqualCollectionRecord(
 | 
| -          collection: ['a', 'b[null -> 1]', 'c[1 -> 2]'],
 | 
| -          additions: ['b[null -> 1]'],
 | 
| -          moves: ['c[1 -> 2]'],
 | 
| -          removals: []));
 | 
| -    });
 | 
| -
 | 
| -    it('should support duplicates', () {
 | 
| -      var list = ['a', 'a', 'a', 'b', 'b'];
 | 
| -      var record = detector.watch(list, null, 'handler');
 | 
| -      detector.collectChanges();
 | 
| -
 | 
| -      list.removeAt(0);
 | 
| -      expect(detector.collectChanges().currentValue, toEqualCollectionRecord(
 | 
| -          collection: ['a', 'a', 'b[3 -> 2]', 'b[4 -> 3]'],
 | 
| -          additions: [],
 | 
| -          moves: ['b[3 -> 2]', 'b[4 -> 3]'],
 | 
| -          removals: ['a[2 -> null]']));
 | 
| -    });
 | 
| -
 | 
| -
 | 
| -    it('should support insertions/moves', () {
 | 
| -      var list = ['a', 'a', 'b', 'b'];
 | 
| -      var record = detector.watch(list, null, 'handler');
 | 
| -      detector.collectChanges();
 | 
| -      list.insert(0, 'b');
 | 
| -      expect(list).toEqual(['b', 'a', 'a', 'b', 'b']);
 | 
| -      expect(detector.collectChanges().currentValue, toEqualCollectionRecord(
 | 
| -          collection: ['b[2 -> 0]', 'a[0 -> 1]', 'a[1 -> 2]', 'b', 'b[null -> 4]'],
 | 
| -          additions: ['b[null -> 4]'],
 | 
| -          moves: ['b[2 -> 0]', 'a[0 -> 1]', 'a[1 -> 2]'],
 | 
| -          removals: []));
 | 
| -    });
 | 
| -
 | 
| -    it('should support UnmodifiableListView', () {
 | 
| -      var hiddenList = [1];
 | 
| -      var list = new UnmodifiableListView(hiddenList);
 | 
| -      var record = detector.watch(list, null, 'handler');
 | 
| -      expect(detector.collectChanges().currentValue, toEqualCollectionRecord(
 | 
| -          collection: ['1[null -> 0]'],
 | 
| -          additions: ['1[null -> 0]'],
 | 
| -          moves: [],
 | 
| -          removals: []));
 | 
| -
 | 
| -      // assert no changes detected
 | 
| -      expect(detector.collectChanges()).toEqual(null);
 | 
| -
 | 
| -      // change the hiddenList normally this should trigger change detection
 | 
| -      // but because we are wrapped in UnmodifiableListView we see nothing.
 | 
| -      hiddenList[0] = 2;
 | 
| -      expect(detector.collectChanges()).toEqual(null);
 | 
| -    });
 | 
| -
 | 
| -    it('should bug', () {
 | 
| -      var list = [1, 2, 3, 4];
 | 
| -      var record = detector.watch(list, null, 'handler');
 | 
| -      expect(detector.collectChanges().currentValue, toEqualCollectionRecord(
 | 
| -          collection: ['1[null -> 0]', '2[null -> 1]', '3[null -> 2]', '4[null -> 3]'],
 | 
| -          additions: ['1[null -> 0]', '2[null -> 1]', '3[null -> 2]', '4[null -> 3]'],
 | 
| -          moves: [],
 | 
| -          removals: []));
 | 
| -      detector.collectChanges();
 | 
| -
 | 
| -      list.removeRange(0, 1);
 | 
| -      expect(detector.collectChanges().currentValue, toEqualCollectionRecord(
 | 
| -          collection: ['2[1 -> 0]', '3[2 -> 1]', '4[3 -> 2]'],
 | 
| -          additions: [],
 | 
| -          moves: ['2[1 -> 0]', '3[2 -> 1]', '4[3 -> 2]'],
 | 
| -          removals: ['1[0 -> null]']));
 | 
| -
 | 
| -      list.insert(0, 1);
 | 
| -      expect(detector.collectChanges().currentValue, toEqualCollectionRecord(
 | 
| -          collection: ['1[null -> 0]', '2[0 -> 1]', '3[1 -> 2]', '4[2 -> 3]'],
 | 
| -          additions: ['1[null -> 0]'],
 | 
| -          moves: ['2[0 -> 1]', '3[1 -> 2]', '4[2 -> 3]'],
 | 
| -          removals: []));
 | 
| -    });
 | 
| -  });
 | 
| -
 | 
| -  describe('map watching', () {
 | 
| -    it('should do basic map watching', () {
 | 
| -      var map = {};
 | 
| -      var record = detector.watch(map, null, 'handler');
 | 
| -      expect(detector.collectChanges()).toEqual(null);
 | 
| -
 | 
| -      map['a'] = 'A';
 | 
| -      expect(detector.collectChanges().currentValue, toEqualMapRecord(
 | 
| -          map: ['a[null -> A]'],
 | 
| -          additions: ['a[null -> A]'],
 | 
| -          changes: [],
 | 
| -          removals: []));
 | 
| -
 | 
| -      map['b'] = 'B';
 | 
| -      expect(detector.collectChanges().currentValue, toEqualMapRecord(
 | 
| -          map: ['a', 'b[null -> B]'],
 | 
| -          additions: ['b[null -> B]'],
 | 
| -          changes: [],
 | 
| -          removals: []));
 | 
| -
 | 
| -      map['b'] = 'BB';
 | 
| -      map['d'] = 'D';
 | 
| -      expect(detector.collectChanges().currentValue, toEqualMapRecord(
 | 
| -          map: ['a', 'b[B -> BB]', 'd[null -> D]'],
 | 
| -          additions: ['d[null -> D]'],
 | 
| -          changes: ['b[B -> BB]'],
 | 
| -          removals: []));
 | 
| -
 | 
| -      map.remove('b');
 | 
| -      expect(map).toEqual({'a': 'A', 'd':'D'});
 | 
| -      expect(detector.collectChanges().currentValue, toEqualMapRecord(
 | 
| -          map: ['a', 'd'],
 | 
| -          additions: [],
 | 
| -          changes: [],
 | 
| -          removals: ['b[BB -> null]']));
 | 
| -
 | 
| -      map.clear();
 | 
| -      expect(detector.collectChanges().currentValue, toEqualMapRecord(
 | 
| -          map: [],
 | 
| -          additions: [],
 | 
| -          changes: [],
 | 
| -          removals: ['a[A -> null]', 'd[D -> null]']));
 | 
| -    });
 | 
| -
 | 
| -    it('should test string keys by value rather than by reference', () {
 | 
| -      var map = {'foo': 0};
 | 
| -      detector..watch(map, null, null)..collectChanges();
 | 
| -
 | 
| -      map['f' + 'oo'] = 0;
 | 
| -
 | 
| -      expect(detector.collectChanges()).toEqual(null);
 | 
| -    });
 | 
| -
 | 
| -    it('should test string values by value rather than by reference', () {
 | 
| -      var map = {'foo': 'bar'};
 | 
| -      detector..watch(map, null, null)..collectChanges();
 | 
| -
 | 
| -      map['foo'] = 'b' + 'ar';
 | 
| -
 | 
| -      expect(detector.collectChanges()).toEqual(null);
 | 
| -    });
 | 
| -
 | 
| -    it('should not see a NaN value as a change', () {
 | 
| -      var map = {'foo': double.NAN};
 | 
| -      var record = detector..watch(map, null, null)..collectChanges();
 | 
| -
 | 
| -      expect(detector.collectChanges()).toEqual(null);
 | 
| -    });
 | 
| -  });
 | 
| -
 | 
| -  describe('DuplicateMap', () {
 | 
| -    DuplicateMap map;
 | 
| -    beforeEach(() => map = new DuplicateMap());
 | 
| -
 | 
| -    it('should do basic operations', () {
 | 
| -      var k1 = 'a';
 | 
| -      var r1 = new ItemRecord(k1)..currentIndex = 1;
 | 
| -      map.put(r1);
 | 
| -      expect(map.get(k1, 2)).toEqual(null);
 | 
| -      expect(map.get(k1, 1)).toEqual(null);
 | 
| -      expect(map.get(k1, 0)).toEqual(r1);
 | 
| -      expect(map.remove(r1)).toEqual(r1);
 | 
| -      expect(map.get(k1, -1)).toEqual(null);
 | 
| -    });
 | 
| -
 | 
| -    it('should do basic operations on duplicate keys', () {
 | 
| -      var k1 = 'a';
 | 
| -      var r1 = new ItemRecord(k1)..currentIndex = 1;
 | 
| -      var r2 = new ItemRecord(k1)..currentIndex = 2;
 | 
| -      map..put(r1)..put(r2);
 | 
| -      expect(map.get(k1, 0)).toEqual(r1);
 | 
| -      expect(map.get(k1, 1)).toEqual(r2);
 | 
| -      expect(map.get(k1, 2)).toEqual(null);
 | 
| -      expect(map.remove(r2)).toEqual(r2);
 | 
| -      expect(map.get(k1, 0)).toEqual(r1);
 | 
| -      expect(map.remove(r1)).toEqual(r1);
 | 
| -      expect(map.get(k1, 0)).toEqual(null);
 | 
| -    });
 | 
| -  });
 | 
| -});
 | 
| -
 | 
| -class _User {
 | 
| -  String first;
 | 
| -  String last;
 | 
| -  num age;
 | 
| -
 | 
| -  _User([this.first, this.last, this.age]);
 | 
| -}
 | 
| -
 | 
| -Matcher toEqualCollectionRecord({collection, additions, moves, removals}) =>
 | 
| -    new CollectionRecordMatcher(collection:collection, additions:additions,
 | 
| -                                moves:moves, removals:removals);
 | 
| -Matcher toEqualMapRecord({map, additions, changes, removals}) =>
 | 
| -    new MapRecordMatcher(map:map, additions:additions,
 | 
| -                         changes:changes, removals:removals);
 | 
| -Matcher toEqualChanges(List changes) => new ChangeMatcher(changes);
 | 
| -
 | 
| -class ChangeMatcher extends Matcher {
 | 
| -  List expected;
 | 
| -
 | 
| -  ChangeMatcher(this.expected);
 | 
| -
 | 
| -  Description describe(Description description) =>
 | 
| -      description..add(expected.toString());
 | 
| -
 | 
| -  Description describeMismatch(changes, Description mismatchDescription,
 | 
| -                               Map matchState, bool verbose) {
 | 
| -    List list = [];
 | 
| -    while(changes != null) {
 | 
| -      list.add(changes.handler);
 | 
| -      changes = changes.nextChange;
 | 
| -    }
 | 
| -    return mismatchDescription..add(list.toString());
 | 
| -  }
 | 
| -
 | 
| -  bool matches(changes, Map matchState) {
 | 
| -    int count = 0;
 | 
| -    while(changes != null) {
 | 
| -      if (changes.handler != expected[count++]) return false;
 | 
| -      changes = changes.nextChange;
 | 
| -    }
 | 
| -    return count == expected.length;
 | 
| -  }
 | 
| -}
 | 
| -
 | 
| -class CollectionRecordMatcher extends Matcher {
 | 
| -  final List collection;
 | 
| -  final List additions;
 | 
| -  final List moves;
 | 
| -  final List removals;
 | 
| -
 | 
| -  CollectionRecordMatcher({this.collection, this.additions, this.moves,
 | 
| -                          this.removals});
 | 
| -
 | 
| -  Description describeMismatch(changes, Description mismatchDescription,
 | 
| -                               Map matchState, bool verbose) {
 | 
| -    List diffs = matchState['diffs'];
 | 
| -    return mismatchDescription..add(diffs.join('\n'));
 | 
| -  }
 | 
| -
 | 
| -  Description describe(Description description) {
 | 
| -    add(name, collection) {
 | 
| -      if (collection != null) {
 | 
| -        description.add('$name: ${collection.join(', ')}\n   ');
 | 
| -      }
 | 
| -    }
 | 
| -
 | 
| -    add('collection', collection);
 | 
| -    add('additions', additions);
 | 
| -    add('moves', moves);
 | 
| -    add('removals', removals);
 | 
| -    return description;
 | 
| -  }
 | 
| -
 | 
| -  bool matches(CollectionChangeRecord changeRecord, Map matchState) {
 | 
| -    var diffs = matchState['diffs'] = [];
 | 
| -    return checkCollection(changeRecord, diffs) &&
 | 
| -           checkAdditions(changeRecord, diffs) &&
 | 
| -           checkMoves(changeRecord, diffs) &&
 | 
| -           checkRemovals(changeRecord, diffs);
 | 
| -  }
 | 
| -
 | 
| -  bool checkCollection(CollectionChangeRecord changeRecord, List diffs) {
 | 
| -    var equals = true;
 | 
| -    if (collection != null) {
 | 
| -      CollectionItem collectionItem = changeRecord.collectionHead;
 | 
| -      for (var item in collection) {
 | 
| -        if (collectionItem == null) {
 | 
| -          equals = false;
 | 
| -          diffs.add('collection too short: $item');
 | 
| -        } else {
 | 
| -          if (collectionItem.toString() != item) {
 | 
| -            equals = false;
 | 
| -            diffs.add('collection mismatch: $collectionItem != $item');
 | 
| -          }
 | 
| -          collectionItem = collectionItem.nextCollectionItem;
 | 
| -        }
 | 
| -      }
 | 
| -      if (collectionItem != null) {
 | 
| -        diffs.add('collection too long: $collectionItem');
 | 
| -        equals = false;
 | 
| -      }
 | 
| -    }
 | 
| -    return equals;
 | 
| -  }
 | 
| -
 | 
| -  bool checkAdditions(CollectionChangeRecord changeRecord, List diffs) {
 | 
| -    var equals = true;
 | 
| -    if (additions != null) {
 | 
| -      AddedItem addedItem = changeRecord.additionsHead;
 | 
| -      for (var item in additions) {
 | 
| -        if (addedItem == null) {
 | 
| -          equals = false;
 | 
| -          diffs.add('additions too short: $item');
 | 
| -        } else {
 | 
| -          if (addedItem.toString() != item) {
 | 
| -            equals = false;
 | 
| -            diffs.add('additions mismatch: $addedItem != $item');
 | 
| -          }
 | 
| -          addedItem = addedItem.nextAddedItem;
 | 
| -        }
 | 
| -      }
 | 
| -      if (addedItem != null) {
 | 
| -        equals = false;
 | 
| -        diffs.add('additions too long: $addedItem');
 | 
| -      }
 | 
| -    }
 | 
| -    return equals;
 | 
| -  }
 | 
| -
 | 
| -  bool checkMoves(CollectionChangeRecord changeRecord, List diffs) {
 | 
| -    var equals = true;
 | 
| -    if (moves != null) {
 | 
| -      MovedItem movedItem = changeRecord.movesHead;
 | 
| -      for (var item in moves) {
 | 
| -        if (movedItem == null) {
 | 
| -          equals = false;
 | 
| -          diffs.add('moves too short: $item');
 | 
| -        } else {
 | 
| -          if (movedItem.toString() != item) {
 | 
| -            equals = false;
 | 
| -            diffs.add('moves too mismatch: $movedItem != $item');
 | 
| -          }
 | 
| -          movedItem = movedItem.nextMovedItem;
 | 
| -        }
 | 
| -      }
 | 
| -      if (movedItem != null) {
 | 
| -        equals = false;
 | 
| -        diffs.add('moves too long: $movedItem');
 | 
| -      }
 | 
| -    }
 | 
| -    return equals;
 | 
| -  }
 | 
| -
 | 
| -  bool checkRemovals(CollectionChangeRecord changeRecord, List diffs) {
 | 
| -    var equals = true;
 | 
| -    if (removals != null) {
 | 
| -      RemovedItem removedItem = changeRecord.removalsHead;
 | 
| -      for (var item in removals) {
 | 
| -        if (removedItem == null) {
 | 
| -          equals = false;
 | 
| -          diffs.add('removes too short: $item');
 | 
| -        } else {
 | 
| -          if (removedItem.toString() != item) {
 | 
| -            equals = false;
 | 
| -            diffs.add('removes too mismatch: $removedItem != $item');
 | 
| -          }
 | 
| -          removedItem = removedItem.nextRemovedItem;
 | 
| -        }
 | 
| -      }
 | 
| -      if (removedItem != null) {
 | 
| -        equals = false;
 | 
| -        diffs.add('removes too long: $removedItem');
 | 
| -      }
 | 
| -    }
 | 
| -    return equals;
 | 
| -  }
 | 
| -}
 | 
| -
 | 
| -class MapRecordMatcher extends Matcher {
 | 
| -  final List map;
 | 
| -  final List additions;
 | 
| -  final List changes;
 | 
| -  final List removals;
 | 
| -
 | 
| -  MapRecordMatcher({this.map, this.additions, this.changes, this.removals});
 | 
| -
 | 
| -  Description describeMismatch(changes, Description mismatchDescription,
 | 
| -                               Map matchState, bool verbose) {
 | 
| -    List diffs = matchState['diffs'];
 | 
| -    return mismatchDescription..add(diffs.join('\n'));
 | 
| -  }
 | 
| -
 | 
| -  Description describe(Description description) {
 | 
| -    add(name, map) {
 | 
| -      if (map != null) {
 | 
| -        description.add('$name: ${map.join(', ')}\n   ');
 | 
| -      }
 | 
| -    }
 | 
| -
 | 
| -    add('map', map);
 | 
| -    add('additions', additions);
 | 
| -    add('changes', changes);
 | 
| -    add('removals', removals);
 | 
| -    return description;
 | 
| -  }
 | 
| -
 | 
| -  bool matches(MapChangeRecord changeRecord, Map matchState) {
 | 
| -    var diffs = matchState['diffs'] = [];
 | 
| -    return checkMap(changeRecord, diffs) &&
 | 
| -           checkAdditions(changeRecord, diffs) &&
 | 
| -           checkChanges(changeRecord, diffs) &&
 | 
| -           checkRemovals(changeRecord, diffs);
 | 
| -  }
 | 
| -
 | 
| -  bool checkMap(MapChangeRecord changeRecord, List diffs) {
 | 
| -    var equals = true;
 | 
| -    if (map != null) {
 | 
| -      KeyValue mapKeyValue = changeRecord.mapHead;
 | 
| -      for (var item in map) {
 | 
| -        if (mapKeyValue == null) {
 | 
| -          equals = false;
 | 
| -          diffs.add('map too short: $item');
 | 
| -        } else {
 | 
| -          if (mapKeyValue.toString() != item) {
 | 
| -            equals = false;
 | 
| -            diffs.add('map mismatch: $mapKeyValue != $item');
 | 
| -          }
 | 
| -          mapKeyValue = mapKeyValue.nextKeyValue;
 | 
| -        }
 | 
| -      }
 | 
| -      if (mapKeyValue != null) {
 | 
| -        diffs.add('map too long: $mapKeyValue');
 | 
| -        equals = false;
 | 
| -      }
 | 
| -    }
 | 
| -    return equals;
 | 
| -  }
 | 
| -
 | 
| -  bool checkAdditions(MapChangeRecord changeRecord, List diffs) {
 | 
| -    var equals = true;
 | 
| -    if (additions != null) {
 | 
| -      AddedKeyValue addedKeyValue = changeRecord.additionsHead;
 | 
| -      for (var item in additions) {
 | 
| -        if (addedKeyValue == null) {
 | 
| -          equals = false;
 | 
| -          diffs.add('additions too short: $item');
 | 
| -        } else {
 | 
| -          if (addedKeyValue.toString() != item) {
 | 
| -            equals = false;
 | 
| -            diffs.add('additions mismatch: $addedKeyValue != $item');
 | 
| -          }
 | 
| -          addedKeyValue = addedKeyValue.nextAddedKeyValue;
 | 
| -        }
 | 
| -      }
 | 
| -      if (addedKeyValue != null) {
 | 
| -        equals = false;
 | 
| -        diffs.add('additions too long: $addedKeyValue');
 | 
| -      }
 | 
| -    }
 | 
| -    return equals;
 | 
| -  }
 | 
| -
 | 
| -  bool checkChanges(MapChangeRecord changeRecord, List diffs) {
 | 
| -    var equals = true;
 | 
| -    if (changes != null) {
 | 
| -      ChangedKeyValue movedKeyValue = changeRecord.changesHead;
 | 
| -      for (var item in changes) {
 | 
| -        if (movedKeyValue == null) {
 | 
| -          equals = false;
 | 
| -          diffs.add('changes too short: $item');
 | 
| -        } else {
 | 
| -          if (movedKeyValue.toString() != item) {
 | 
| -            equals = false;
 | 
| -            diffs.add('changes too mismatch: $movedKeyValue != $item');
 | 
| -          }
 | 
| -          movedKeyValue = movedKeyValue.nextChangedKeyValue;
 | 
| -        }
 | 
| -      }
 | 
| -      if (movedKeyValue != null) {
 | 
| -        equals = false;
 | 
| -        diffs.add('changes too long: $movedKeyValue');
 | 
| -      }
 | 
| -    }
 | 
| -    return equals;
 | 
| -  }
 | 
| -
 | 
| -  bool checkRemovals(MapChangeRecord changeRecord, List diffs) {
 | 
| -    var equals = true;
 | 
| -    if (removals != null) {
 | 
| -      RemovedKeyValue removedKeyValue = changeRecord.removalsHead;
 | 
| -      for (var item in removals) {
 | 
| -        if (removedKeyValue == null) {
 | 
| -          equals = false;
 | 
| -          diffs.add('rechanges too short: $item');
 | 
| -        } else {
 | 
| -          if (removedKeyValue.toString() != item) {
 | 
| -            equals = false;
 | 
| -            diffs.add('rechanges too mismatch: $removedKeyValue != $item');
 | 
| -          }
 | 
| -          removedKeyValue = removedKeyValue.nextRemovedKeyValue;
 | 
| -        }
 | 
| -      }
 | 
| -      if (removedKeyValue != null) {
 | 
| -        equals = false;
 | 
| -        diffs.add('rechanges too long: $removedKeyValue');
 | 
| -      }
 | 
| -    }
 | 
| -    return equals;
 | 
| -  }
 | 
| -}
 | 
| 
 |