Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(12)

Unified Diff: third_party/pkg/angular/test/change_detection/dirty_checking_change_detector_spec.dart

Issue 257423008: Update all Angular libs (run update_all.sh). (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 6 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
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
index 0d732f2dc0b0c22c4d16522fff8d0303f49c64a9..011f59a022e5033b8490276f91832a4682a7c92e 100644
--- 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
@@ -3,477 +3,810 @@ 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 'package:angular/change_detection/dirty_checking_change_detector_static.dart';
+import 'package:angular/change_detection/dirty_checking_change_detector_dynamic.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']));
+import 'dart:math';
+
+void main() {
+ describe('DirtyCheckingChangeDetector', () {
+ DirtyCheckingChangeDetector<String> detector;
+ FieldGetterFactory getterFactory = new StaticFieldGetterFactory({
+ "first": (o) => o.first,
+ "age": (o) => o.age,
+ "last": (o) => o.last,
+ "toString": (o) => o.toString,
+ "isUnderAge": (o) => o.isUnderAge,
+ "isUnderAgeAsVariable": (o) => o.isUnderAgeAsVariable
});
- 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();
+ beforeEach(() {
+ detector = new DirtyCheckingChangeDetector<String>(getterFactory);
});
- });
- 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: []));
+ describe('StaticFieldGetterFactory', () {
+ DirtyCheckingChangeDetector<String> detector;
+ var user = new _User('Marko', 'Vuksanovic', 30);
+ FieldGetterFactory getterFactory = new StaticFieldGetterFactory({
+ "first": (o) => o.first,
+ "age": (o) => o.age,
+ "last": (o) => o.last,
+ "toString": (o) => o.toString,
+ "isUnderAge": (o) => o.isUnderAge,
+ "isUnderAgeAsVariable": (o) => o.isUnderAgeAsVariable,
+ "list": (o) => o.list,
+ "map": (o) => o.map
+ });
+
+ beforeEach(() {
+ detector = new DirtyCheckingChangeDetector<String>(getterFactory);
+ });
+
+ it('should detect methods', () {
+ var obj = new _User();
+ expect(getterFactory.isMethod(obj, 'toString')).toEqual(true);
+ expect(getterFactory.isMethod(obj, 'age')).toEqual(false);
+ });
+
+ it('should return true is method is real method', () {
+ expect(getterFactory.isMethod(user, 'isUnderAge')).toEqual(true);
+ });
+
+ it('should return false is field is a function', () {
+ expect(getterFactory.isMethod(user, 'isUnderAgeAsVariable')).toEqual(false);
+ });
+
+ it('should return false is field is a list', () {
+ expect(getterFactory.isMethod(user, 'list')).toEqual(false);
+ });
+
+ it('should return false is field is a map', () {
+ expect(getterFactory.isMethod(user, 'map')).toEqual(false);
+ });
});
- 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: []));
- });
+ describe('Dynamic GetterFactory', () {
+ DirtyCheckingChangeDetector<String> detector;
+ var user = new _User('Marko', 'Vuksanovic', 30);
+ FieldGetterFactory getterFactory = new DynamicFieldGetterFactory();
- it('should test string by value rather than by reference', () {
- var list = ['a', 'boo'];
- detector..watch(list, null, null)..collectChanges();
+ beforeEach(() {
+ detector = new DirtyCheckingChangeDetector<String>(getterFactory);
+ });
- list[1] = 'b' + 'oo';
+ it('should return true is method is real method', () {
+ expect(getterFactory.isMethod(user, 'isUnderAge')).toEqual(true);
+ });
- expect(detector.collectChanges()).toEqual(null);
- });
+ it('should return false is field is a function', () {
+ expect(getterFactory.isMethod(user, 'isUnderAgeAsVariable')).toEqual(false);
+ });
- it('should ignore [NaN] != [NaN]', () {
- var list = [double.NAN];
- var record = detector..watch(list, null, null)..collectChanges();
+ it('should return false is field is a list', () {
+ expect(getterFactory.isMethod(user, 'list')).toEqual(false);
+ });
- expect(detector.collectChanges()).toEqual(null);
+ it('should return false is field is a map', () {
+ expect(getterFactory.isMethod(user, 'map')).toEqual(false);
+ });
});
- 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: []));
+ describe('object field', () {
+ it('should detect nothing', () {
+ var changes = detector.collectChanges();
+ expect(changes.moveNext()).toEqual(false);
+ });
+
+ it('should detect field changes', () {
+ var user = new _User('', '');
+ Iterator changeIterator;
+
+ detector..watch(user, 'first', null)
+ ..watch(user, 'last', null)
+ ..collectChanges(); // throw away first set
+
+ changeIterator = detector.collectChanges();
+ expect(changeIterator.moveNext()).toEqual(false);
+ user..first = 'misko'
+ ..last = 'hevery';
+
+ changeIterator = detector.collectChanges();
+ expect(changeIterator.moveNext()).toEqual(true);
+ expect(changeIterator.current.currentValue).toEqual('misko');
+ expect(changeIterator.current.previousValue).toEqual('');
+ expect(changeIterator.moveNext()).toEqual(true);
+ expect(changeIterator.current.currentValue).toEqual('hevery');
+ expect(changeIterator.current.previousValue).toEqual('');
+ expect(changeIterator.moveNext()).toEqual(false);
+
+ // force different instance
+ user.first = 'mis';
+ user.first += 'ko';
+
+ changeIterator = detector.collectChanges();
+ expect(changeIterator.moveNext()).toEqual(false);
+
+ user.last = 'Hevery';
+ changeIterator = detector.collectChanges();
+ expect(changeIterator.moveNext()).toEqual(true);
+ expect(changeIterator.current.currentValue).toEqual('Hevery');
+ expect(changeIterator.current.previousValue).toEqual('hevery');
+ expect(changeIterator.moveNext()).toEqual(false);
+ });
+
+ it('should ignore NaN != NaN', () {
+ var user = new _User();
+ user.age = double.NAN;
+ detector..watch(user, 'age', null)..collectChanges(); // throw away first set
+
+ var changeIterator = detector.collectChanges();
+ expect(changeIterator.moveNext()).toEqual(false);
+
+ user.age = 123;
+ changeIterator = detector.collectChanges();
+ expect(changeIterator.moveNext()).toEqual(true);
+ expect(changeIterator.current.currentValue).toEqual(123);
+ expect(changeIterator.current.previousValue.isNaN).toEqual(true);
+ expect(changeIterator.moveNext()).toEqual(false);
+ });
+
+ 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 changeIterator = detector.collectChanges();
+ expect(changeIterator.moveNext()).toEqual(true);
+ expect(changeIterator.current.currentValue).toEqual('Misko');
+ expect(changeIterator.current.previousValue).toEqual('misko');
+ });
});
- 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;
+ 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 changeIterator = detector.collectChanges();
+ expect(changeIterator.moveNext()).toEqual(true);
+ expect(changeIterator.current.handler).toEqual('a');
+ expect(changeIterator.moveNext()).toEqual(true);
+ expect(changeIterator.current.handler).toEqual('b');
+ expect(changeIterator.moveNext()).toEqual(false);
+
+ obj['a'] = obj['b'] = 2;
+ a.remove();
+ changeIterator = detector.collectChanges();
+ expect(changeIterator.moveNext()).toEqual(true);
+ expect(changeIterator.current.handler).toEqual('b');
+ expect(changeIterator.moveNext()).toEqual(false);
+
+ obj['a'] = obj['b'] = 3;
+ b.remove();
+ changeIterator = detector.collectChanges();
+ expect(changeIterator.moveNext()).toEqual(false);
+ });
+
+ 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');
+
+ var iterator;
+ 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');
+ var iterotar;
+
+ 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();
+ });
+
+ it('should properly disconnect group in case watch is removed in disconected group', () {
+ var map = {};
+ var detector0 = new DirtyCheckingChangeDetector<String>(getterFactory);
+ var detector1 = detector0.newGroup();
+ var detector2 = detector1.newGroup();
+ var watch2 = detector2.watch(map, 'f1', null);
+ var detector3 = detector0.newGroup();
+ detector1.remove();
+ watch2.remove(); // removing a dead record
+ detector3.watch(map, 'f2', null);
+ });
+
+ it('should find random bugs', () {
+ List detectors;
+ List records;
+ List steps;
+ var field = 'someField';
+ step(text) {
+ //print(text);
+ steps.add(text);
+ }
+ Map map = {};
+ var random = new Random();
+ try {
+ for (var i = 0; i < 100000; i++) {
+ if (i % 50 == 0) {
+ //print(steps);
+ //print('===================================');
+ records = [];
+ steps = [];
+ detectors = [new DirtyCheckingChangeDetector<String>(getterFactory)];
+ }
+ switch (random.nextInt(4)) {
+ case 0: // new child detector
+ if (detectors.length > 10) break;
+ var index = random.nextInt(detectors.length);
+ ChangeDetectorGroup detector = detectors[index];
+ step('detectors[$index].newGroup()');
+ var child = detector.newGroup();
+ detectors.add(child);
+ break;
+ case 1: // add watch
+ var index = random.nextInt(detectors.length);
+ ChangeDetectorGroup detector = detectors[index];
+ step('detectors[$index].watch(map, field, null)');
+ WatchRecord record = detector.watch(map, field, null);
+ records.add(record);
+ break;
+ case 2: // destroy watch group
+ if (detectors.length == 1) break;
+ var index = random.nextInt(detectors.length - 1) + 1;
+ ChangeDetectorGroup detector = detectors[index];
+ step('detectors[$index].remove()');
+ detector.remove();
+ detectors = detectors
+ .where((s) => s.isAttached)
+ .toList();
+ break;
+ case 3: // remove watch on watch group
+ if (records.length == 0) break;
+ var index = random.nextInt(records.length);
+ WatchRecord record = records.removeAt(index);
+ step('records.removeAt($index).remove()');
+ record.remove();
+ break;
+ }
+ }
+ } catch(e) {
+ print(steps);
+ rethrow;
+ }
+ });
- 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);
+ describe('list watching', () {
+ describe('previous state', () {
+ it('should store on addition', () {
+ var list = [];
+ var record = detector.watch(list, null, null);
+ expect(detector.collectChanges().moveNext()).toEqual(false);
+ var iterator;
+
+ list.add('a');
+ iterator = detector.collectChanges();
+ expect(iterator.moveNext()).toEqual(true);
+ expect(iterator.current.currentValue, toEqualCollectionRecord(
+ collection: ['a[null -> 0]'],
+ previous: [],
+ additions: ['a[null -> 0]'],
+ moves: [],
+ removals: []));
+
+ list.add('b');
+ iterator = detector.collectChanges();
+ expect(iterator.moveNext()).toEqual(true);
+ expect(iterator.current.currentValue, toEqualCollectionRecord(
+ collection: ['a', 'b[null -> 1]'],
+ previous: ['a'],
+ additions: ['b[null -> 1]'],
+ moves: [],
+ removals: []));
+ });
+
+ it('should handle swapping elements correctly', () {
+ var list = [1, 2];
+ var record = detector.watch(list, null, null);
+ detector.collectChanges().moveNext();
+ var iterator;
+
+ // reverse the list.
+ list.setAll(0, list.reversed.toList());
+ iterator = detector.collectChanges();
+ expect(iterator.moveNext()).toEqual(true);
+ expect(iterator.current.currentValue, toEqualCollectionRecord(
+ collection: ['2[1 -> 0]', '1[0 -> 1]'],
+ previous: ['1[0 -> 1]', '2[1 -> 0]'],
+ additions: [],
+ moves: ['2[1 -> 0]', '1[0 -> 1]'],
+ removals: []));
+ });
+ });
+
+ it('should detect changes in list', () {
+ var list = [];
+ var record = detector.watch(list, null, 'handler');
+ expect(detector.collectChanges().moveNext()).toEqual(false);
+ var iterator;
+
+ list.add('a');
+ iterator = detector.collectChanges();
+ expect(iterator.moveNext()).toEqual(true);
+ expect(iterator.current.currentValue, toEqualCollectionRecord(
+ collection: ['a[null -> 0]'],
+ additions: ['a[null -> 0]'],
+ moves: [],
+ removals: []));
+
+ list.add('b');
+ iterator = detector.collectChanges();
+ expect(iterator.moveNext()).toEqual(true);
+ expect(iterator.current.currentValue, toEqualCollectionRecord(
+ collection: ['a', 'b[null -> 1]'],
+ previous: ['a'],
+ additions: ['b[null -> 1]'],
+ moves: [],
+ removals: []));
+
+ list.add('c');
+ list.add('d');
+ iterator = detector.collectChanges();
+ expect(iterator.moveNext()).toEqual(true);
+ expect(iterator.current.currentValue, toEqualCollectionRecord(
+ collection: ['a', 'b', 'c[null -> 2]', 'd[null -> 3]'],
+ previous: ['a', 'b'],
+ additions: ['c[null -> 2]', 'd[null -> 3]'],
+ moves: [],
+ removals: []));
+
+ list.remove('c');
+ expect(list).toEqual(['a', 'b', 'd']);
+ iterator = detector.collectChanges();
+ expect(iterator.moveNext()).toEqual(true);
+ expect(iterator.current.currentValue, toEqualCollectionRecord(
+ collection: ['a', 'b', 'd[3 -> 2]'],
+ previous: ['a', 'b', 'c[2 -> null]', 'd[3 -> 2]'],
+ additions: [],
+ moves: ['d[3 -> 2]'],
+ removals: ['c[2 -> null]']));
+
+ list.clear();
+ list.addAll(['d', 'c', 'b', 'a']);
+ iterator = detector.collectChanges();
+ expect(iterator.moveNext()).toEqual(true);
+ expect(iterator.current.currentValue, toEqualCollectionRecord(
+ collection: ['d[2 -> 0]', 'c[null -> 1]', 'b[1 -> 2]', 'a[0 -> 3]'],
+ previous: ['a[0 -> 3]', 'b[1 -> 2]', 'd[2 -> 0]'],
+ 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().moveNext()).toEqual(false);
+ });
+
+ it('should ignore [NaN] != [NaN]', () {
+ var list = [double.NAN];
+ var record = detector..watch(list, null, null)..collectChanges();
+
+ expect(detector.collectChanges().moveNext()).toEqual(false);
+ });
+
+ it('should remove and add same item', () {
+ var list = ['a', 'b', 'c'];
+ var record = detector.watch(list, null, 'handler');
+ var iterator;
+ detector.collectChanges();
+
+ list.remove('b');
+ iterator = detector.collectChanges()..moveNext();
+ expect(iterator.current.currentValue, toEqualCollectionRecord(
+ collection: ['a', 'c[2 -> 1]'],
+ previous: ['a', 'b[1 -> null]', 'c[2 -> 1]'],
+ additions: [],
+ moves: ['c[2 -> 1]'],
+ removals: ['b[1 -> null]']));
+
+ list.insert(1, 'b');
+ expect(list).toEqual(['a', 'b', 'c']);
+ iterator = detector.collectChanges()..moveNext();
+ expect(iterator.current.currentValue, toEqualCollectionRecord(
+ collection: ['a', 'b[null -> 1]', 'c[1 -> 2]'],
+ previous: ['a', '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);
+ var iterator = detector.collectChanges()..moveNext();
+ expect(iterator.current.currentValue, toEqualCollectionRecord(
+ collection: ['a', 'a', 'b[3 -> 2]', 'b[4 -> 3]'],
+ previous: ['a', 'a', 'a[2 -> null]', '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');
+ var iterator;
+ detector.collectChanges();
+ list.insert(0, 'b');
+ expect(list).toEqual(['b', 'a', 'a', 'b', 'b']);
+ iterator = detector.collectChanges()..moveNext();
+ expect(iterator.current.currentValue, toEqualCollectionRecord(
+ collection: ['b[2 -> 0]', 'a[0 -> 1]', 'a[1 -> 2]', 'b', 'b[null -> 4]'],
+ previous: ['a[0 -> 1]', 'a[1 -> 2]', 'b[2 -> 0]', 'b'],
+ 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');
+ var iterator = detector.collectChanges()..moveNext();
+ expect(iterator.current.currentValue, toEqualCollectionRecord(
+ collection: ['1[null -> 0]'],
+ additions: ['1[null -> 0]'],
+ moves: [],
+ removals: []));
+
+ // assert no changes detected
+ expect(detector.collectChanges().moveNext()).toEqual(false);
+
+ // 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().moveNext()).toEqual(false);
+ });
+
+ it('should bug', () {
+ var list = [1, 2, 3, 4];
+ var record = detector.watch(list, null, 'handler');
+ var iterator;
+
+ iterator = detector.collectChanges()..moveNext();
+ expect(iterator.current.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);
+ iterator = detector.collectChanges()..moveNext();
+ expect(iterator.current.currentValue, toEqualCollectionRecord(
+ collection: ['2[1 -> 0]', '3[2 -> 1]', '4[3 -> 2]'],
+ previous: ['1[0 -> null]', '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);
+ iterator = detector.collectChanges()..moveNext();
+ expect(iterator.current.currentValue, toEqualCollectionRecord(
+ collection: ['1[null -> 0]', '2[0 -> 1]', '3[1 -> 2]', '4[2 -> 3]'],
+ previous: ['2[0 -> 1]', '3[1 -> 2]', '4[2 -> 3]'],
+ additions: ['1[null -> 0]'],
+ moves: ['2[0 -> 1]', '3[1 -> 2]', '4[2 -> 3]'],
+ removals: []));
+ });
+
+ it('should properly support objects with equality', () {
+ FooBar.fooIds = 0;
+ var list = [new FooBar('a', 'a'), new FooBar('a', 'a')];
+ var record = detector.watch(list, null, 'handler');
+ var iterator;
+
+ iterator = detector.collectChanges()..moveNext();
+ expect(iterator.current.currentValue, toEqualCollectionRecord(
+ collection: ['(0)a-a[null -> 0]', '(1)a-a[null -> 1]'],
+ additions: ['(0)a-a[null -> 0]', '(1)a-a[null -> 1]'],
+ moves: [],
+ removals: []));
+ detector.collectChanges();
+
+ list.removeRange(0, 1);
+ iterator = detector.collectChanges()..moveNext();
+ expect(iterator.current.currentValue, toEqualCollectionRecord(
+ collection: ['(1)a-a[1 -> 0]'],
+ previous: ['(0)a-a[0 -> null]', '(1)a-a[1 -> 0]'],
+ additions: [],
+ moves: ['(1)a-a[1 -> 0]'],
+ removals: ['(0)a-a[0 -> null]']));
+
+ list.insert(0, new FooBar('a', 'a'));
+ iterator = detector.collectChanges()..moveNext();
+ expect(iterator.current.currentValue, toEqualCollectionRecord(
+ collection: ['(2)a-a[null -> 0]', '(1)a-a[0 -> 1]'],
+ previous: ['(1)a-a[0 -> 1]'],
+ additions: ['(2)a-a[null -> 0]'],
+ moves: ['(1)a-a[0 -> 1]'],
+ removals: []));
+ });
});
- 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('map watching', () {
+ describe('previous state', () {
+ it('should store on insertion', () {
+ var map = {};
+ var record = detector.watch(map, null, null);
+ expect(detector.collectChanges().moveNext()).toEqual(false);
+ var iterator;
+
+ map['a'] = 1;
+ iterator = detector.collectChanges();
+ expect(iterator.moveNext()).toEqual(true);
+ expect(iterator.current.currentValue, toEqualMapRecord(
+ map: ['a[null -> 1]'],
+ previous: [],
+ additions: ['a[null -> 1]'],
+ changes: [],
+ removals: []));
+
+ map['b'] = 2;
+ iterator = detector.collectChanges();
+ expect(iterator.moveNext()).toEqual(true);
+ expect(iterator.current.currentValue, toEqualMapRecord(
+ map: ['a', 'b[null -> 2]'],
+ previous: ['a'],
+ additions: ['b[null -> 2]'],
+ changes: [],
+ removals: []));
+ });
+
+ it('should handle changing key/values correctly', () {
+ var map = {1: 10, 2: 20};
+ var record = detector.watch(map, null, null);
+ detector.collectChanges().moveNext();
+ var iterator;
+
+ map[1] = 20;
+ map[2] = 10;
+ iterator = detector.collectChanges();
+ expect(iterator.moveNext()).toEqual(true);
+ expect(iterator.current.currentValue, toEqualMapRecord(
+ map: ['1[10 -> 20]', '2[20 -> 10]'],
+ previous: ['1[10 -> 20]', '2[20 -> 10]'],
+ additions: [],
+ changes: ['1[10 -> 20]', '2[20 -> 10]'],
+ removals: []));
+ });
+ });
+
+ it('should do basic map watching', () {
+ var map = {};
+ var record = detector.watch(map, null, 'handler');
+ expect(detector.collectChanges().moveNext()).toEqual(false);
+
+ var changeIterator;
+ map['a'] = 'A';
+ changeIterator = detector.collectChanges();
+ expect(changeIterator.moveNext()).toEqual(true);
+ expect(changeIterator.current.currentValue, toEqualMapRecord(
+ map: ['a[null -> A]'],
+ previous: [],
+ additions: ['a[null -> A]'],
+ changes: [],
+ removals: []));
+
+ map['b'] = 'B';
+ changeIterator = detector.collectChanges();
+ expect(changeIterator.moveNext()).toEqual(true);
+ expect(changeIterator.current.currentValue, toEqualMapRecord(
+ map: ['a', 'b[null -> B]'],
+ previous: ['a'],
+ additions: ['b[null -> B]'],
+ changes: [],
+ removals: []));
+
+ map['b'] = 'BB';
+ map['d'] = 'D';
+ changeIterator = detector.collectChanges();
+ expect(changeIterator.moveNext()).toEqual(true);
+ expect(changeIterator.current.currentValue, toEqualMapRecord(
+ map: ['a', 'b[B -> BB]', 'd[null -> D]'],
+ previous: ['a', 'b[B -> BB]'],
+ additions: ['d[null -> D]'],
+ changes: ['b[B -> BB]'],
+ removals: []));
+
+ map.remove('b');
+ expect(map).toEqual({'a': 'A', 'd':'D'});
+ changeIterator = detector.collectChanges();
+ expect(changeIterator.moveNext()).toEqual(true);
+ expect(changeIterator.current.currentValue, toEqualMapRecord(
+ map: ['a', 'd'],
+ previous: ['a', 'b[BB -> null]', 'd'],
+ additions: [],
+ changes: [],
+ removals: ['b[BB -> null]']));
+
+ map.clear();
+ changeIterator = detector.collectChanges();
+ expect(changeIterator.moveNext()).toEqual(true);
+ expect(changeIterator.current.currentValue, toEqualMapRecord(
+ map: [],
+ previous: ['a[A -> null]', 'd[D -> null]'],
+ 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().moveNext()).toEqual(false);
+ });
+
+ 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().moveNext()).toEqual(false);
+ });
+
+ 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().moveNext()).toEqual(false);
+ });
});
- });
- 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);
+ describe('function watching', () {
+ it('should detect no changes when watching a function', () {
+ var user = new _User('marko', 'vuksanovic', 15);
+ Iterator changeIterator;
+
+ detector..watch(user, 'isUnderAge', null);
+ changeIterator = detector.collectChanges();
+ expect(changeIterator.moveNext()).toEqual(true);
+ expect(changeIterator.moveNext()).toEqual(false);
+
+ user.age = 17;
+ changeIterator = detector.collectChanges();
+ expect(changeIterator.moveNext()).toEqual(false);
+
+ user.age = 30;
+ changeIterator = detector.collectChanges();
+ expect(changeIterator.moveNext()).toEqual(false);
+ });
+
+ it('should detect change when watching a property function', () {
+ var user = new _User('marko', 'vuksanovic', 30);
+ Iterator changeIterator;
+
+ detector..watch(user, 'isUnderAgeAsVariable', null);
+ changeIterator = detector.collectChanges();
+ expect(changeIterator.moveNext()).toEqual(false);
+
+ user.isUnderAgeAsVariable = () => false;
+ changeIterator = detector.collectChanges();
+ expect(changeIterator.moveNext()).toEqual(true);
+ });
});
- 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);
+ 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;
+ var isUnderAgeAsVariable;
+ List<String> list = ['foo', 'bar', 'baz'];
+ Map map = {'foo': 'bar', 'baz': 'cux'};
+
+ _User([this.first, this.last, this.age]) {
+ isUnderAgeAsVariable = isUnderAge;
+ }
- _User([this.first, this.last, this.age]);
+ bool isUnderAge() {
+ return age != null ? age < 18 : false;
+ }
}
-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 toEqualCollectionRecord({collection, previous, additions, moves, removals}) =>
+ new CollectionRecordMatcher(collection:collection, previous: previous,
+ additions:additions, moves:moves, removals:removals);
+Matcher toEqualMapRecord({map, previous, additions, changes, removals}) =>
+ new MapRecordMatcher(map:map, previous: previous,
+ additions:additions, changes:changes, removals:removals);
Matcher toEqualChanges(List changes) => new ChangeMatcher(changes);
class ChangeMatcher extends Matcher {
@@ -484,38 +817,77 @@ class ChangeMatcher extends Matcher {
Description describe(Description description) =>
description..add(expected.toString());
- Description describeMismatch(changes, Description mismatchDescription,
+ Description describeMismatch(Iterator<Record> changes,
+ Description mismatchDescription,
Map matchState, bool verbose) {
List list = [];
- while(changes != null) {
- list.add(changes.handler);
- changes = changes.nextChange;
+ while(changes.moveNext()) {
+ list.add(changes.current.handler);
}
return mismatchDescription..add(list.toString());
}
- bool matches(changes, Map matchState) {
+ bool matches(Iterator<Record> changes, Map matchState) {
int count = 0;
- while(changes != null) {
- if (changes.handler != expected[count++]) return false;
- changes = changes.nextChange;
+ while(changes.moveNext()) {
+ if (changes.current.handler != expected[count++]) return false;
}
return count == expected.length;
}
}
-class CollectionRecordMatcher extends Matcher {
+abstract class _CollectionMatcher<T> extends Matcher {
+ List<T> _getList(Function it) {
+ var result = <T>[];
+ it((item) {
+ result.add(item);
+ });
+ return result;
+ }
+
+ bool _compareLists(String tag, List expected, List actual, List diffs) {
+ var equals = true;
+ Iterator iActual = actual.iterator;
+ iActual.moveNext();
+ T actualItem = iActual.current;
+ if (expected == null) {
+ expected = [];
+ }
+ for (String expectedItem in expected) {
+ if (actualItem == null) {
+ equals = false;
+ diffs.add('$tag too short: $expectedItem');
+ } else {
+ if ("$actualItem" != expectedItem) {
+ equals = false;
+ diffs.add('$tag mismatch: $actualItem != $expectedItem');
+ }
+ iActual.moveNext();
+ actualItem = iActual.current;
+ }
+ }
+ if (actualItem != null) {
+ diffs.add('$tag too long: $actualItem');
+ equals = false;
+ }
+ return equals;
+ }
+}
+
+class CollectionRecordMatcher extends _CollectionMatcher<ItemRecord> {
final List collection;
+ final List previous;
final List additions;
final List moves;
final List removals;
- CollectionRecordMatcher({this.collection, this.additions, this.moves,
- this.removals});
+ CollectionRecordMatcher({this.collection, this.previous,
+ this.additions, this.moves, this.removals});
Description describeMismatch(changes, Description mismatchDescription,
Map matchState, bool verbose) {
List diffs = matchState['diffs'];
+ if (diffs == null) return mismatchDescription;
return mismatchDescription..add(diffs.join('\n'));
}
@@ -527,6 +899,7 @@ class CollectionRecordMatcher extends Matcher {
}
add('collection', collection);
+ add('previous', previous);
add('additions', additions);
add('moves', moves);
add('removals', removals);
@@ -536,119 +909,57 @@ class CollectionRecordMatcher extends Matcher {
bool matches(CollectionChangeRecord changeRecord, Map matchState) {
var diffs = matchState['diffs'] = [];
return checkCollection(changeRecord, diffs) &&
+ checkPrevious(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;
- }
+ List items = _getList((fn) => changeRecord.forEachItem(fn));
+ bool equals = _compareLists("collection", collection, items, diffs);
+ int iterableLength = changeRecord.iterable.toList().length;
+ if (iterableLength != items.length) {
+ diffs.add('collection length mismatched: $iterableLength != ${items.length}');
+ equals = false;
}
return equals;
}
+ bool checkPrevious(CollectionChangeRecord changeRecord, List diffs) {
+ List items = _getList((fn) => changeRecord.forEachPreviousItem(fn));
+ return _compareLists("previous", previous, items, diffs);
+ }
+
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;
+ List items = _getList((fn) => changeRecord.forEachAddition(fn));
+ return _compareLists("additions", additions, items, diffs);
}
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;
+ List items = _getList((fn) => changeRecord.forEachMove(fn));
+ return _compareLists("moves", moves, items, diffs);
}
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;
+ List items = _getList((fn) => changeRecord.forEachRemoval(fn));
+ return _compareLists("removes", removals, items, diffs);
}
}
-class MapRecordMatcher extends Matcher {
+class MapRecordMatcher extends _CollectionMatcher<KeyValueRecord> {
final List map;
+ final List previous;
final List additions;
final List changes;
final List removals;
- MapRecordMatcher({this.map, this.additions, this.changes, this.removals});
+ MapRecordMatcher({this.map, this.previous, this.additions, this.changes, this.removals});
Description describeMismatch(changes, Description mismatchDescription,
Map matchState, bool verbose) {
List diffs = matchState['diffs'];
+ if (diffs == null) return mismatchDescription;
return mismatchDescription..add(diffs.join('\n'));
}
@@ -660,6 +971,7 @@ class MapRecordMatcher extends Matcher {
}
add('map', map);
+ add('previous', previous);
add('additions', additions);
add('changes', changes);
add('removals', removals);
@@ -669,104 +981,59 @@ class MapRecordMatcher extends Matcher {
bool matches(MapChangeRecord changeRecord, Map matchState) {
var diffs = matchState['diffs'] = [];
return checkMap(changeRecord, diffs) &&
+ checkPrevious(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;
- }
+ List items = _getList((fn) => changeRecord.forEachItem(fn));
+ bool equals = _compareLists("map", map, items, diffs);
+ int mapLength = changeRecord.map.length;
+ if (mapLength != items.length) {
+ diffs.add('map length mismatched: $mapLength != ${items.length}');
+ equals = false;
}
return equals;
}
+ bool checkPrevious(MapChangeRecord changeRecord, List diffs) {
+ List items = _getList((fn) => changeRecord.forEachPreviousItem(fn));
+ return _compareLists("previous", previous, items, diffs);
+ }
+
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;
+ List items = _getList((fn) => changeRecord.forEachAddition(fn));
+ return _compareLists("additions", additions, items, diffs);
}
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;
+ List items = _getList((fn) => changeRecord.forEachChange(fn));
+ return _compareLists("changes", changes, items, diffs);
}
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;
+ List items = _getList((fn) => changeRecord.forEachRemoval(fn));
+ return _compareLists("removals", removals, items, diffs);
}
}
+
+
+class FooBar {
+ static int fooIds = 0;
+
+ int id;
+ String foo, bar;
+
+ FooBar(this.foo, this.bar) {
+ id = fooIds++;
+ }
+
+ bool operator==(other) =>
+ other is FooBar && foo == other.foo && bar == other.bar;
+
+ int get hashCode => foo.hashCode ^ bar.hashCode;
+
+ String toString() => '($id)$foo-$bar';
+}
« no previous file with comments | « third_party/pkg/angular/test/bootstrap_spec.dart ('k') | third_party/pkg/angular/test/change_detection/watch_group_spec.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698