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

Unified Diff: pkg/observe/test/path_observer_test.dart

Issue 420673002: Roll polymer packages to version 0.3.4 (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 6 years, 5 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
« no previous file with comments | « pkg/observe/pubspec.yaml ('k') | pkg/pkg.status » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: pkg/observe/test/path_observer_test.dart
diff --git a/pkg/observe/test/path_observer_test.dart b/pkg/observe/test/path_observer_test.dart
index 674f8b27f0c470b51be97bfcbb1087758f131201..aae8887b657b2626edab0ffae5d4f0f6c03fcae0 100644
--- a/pkg/observe/test/path_observer_test.dart
+++ b/pkg/observe/test/path_observer_test.dart
@@ -5,6 +5,10 @@
import 'dart:async';
import 'package:observe/observe.dart';
import 'package:unittest/unittest.dart';
+import 'package:observe/src/path_observer.dart'
+ show getSegmentsOfPropertyPathForTesting,
+ observerSentinelForTesting;
+
import 'observe_test_utils.dart';
// This file contains code ported from:
@@ -17,34 +21,100 @@ main() => dirtyCheckZone().run(() {
group('PropertyPath', () {
test('toString length', () {
- expectPath(p, str, len) {
+ expectPath(p, str, len, [keys]) {
var path = new PropertyPath(p);
expect(path.toString(), str);
expect(path.length, len, reason: 'expected path length $len for $path');
+ if (keys == null) {
+ expect(path.isValid, isFalse);
+ } else {
+ expect(path.isValid, isTrue);
+ expect(getSegmentsOfPropertyPathForTesting(path), keys);
+ }
}
expectPath('/foo', '<invalid path>', 0);
- expectPath('abc', 'abc', 1);
- expectPath('a.b.c', 'a.b.c', 3);
- expectPath('a.b.c ', 'a.b.c', 3);
- expectPath(' a.b.c', 'a.b.c', 3);
- expectPath(' a.b.c ', 'a.b.c', 3);
- expectPath('1.abc', '1.abc', 2);
- expectPath([#qux], 'qux', 1);
- expectPath([1, #foo, #bar], '1.foo.bar', 3);
+ expectPath('1.abc', '<invalid path>', 0);
+ expectPath('abc', 'abc', 1, [#abc]);
+ expectPath('a.b.c', 'a.b.c', 3, [#a, #b, #c]);
+ expectPath('a.b.c ', 'a.b.c', 3, [#a, #b, #c]);
+ expectPath(' a.b.c', 'a.b.c', 3, [#a, #b, #c]);
+ expectPath(' a.b.c ', 'a.b.c', 3, [#a, #b, #c]);
+ expectPath('[1].abc', '[1].abc', 2, [1, #abc]);
+ expectPath([#qux], 'qux', 1, [#qux]);
+ expectPath([1, #foo, #bar], '[1].foo.bar', 3, [1, #foo, #bar]);
+ expectPath([1, #foo, 'bar'], '[1].foo["bar"]', 3, [1, #foo, 'bar']);
+
+ // From test.js: "path validity" test:
+
+ expectPath('', '', 0, []);
+ expectPath(' ', '', 0, []);
+ expectPath(null, '', 0, []);
+ expectPath('a', 'a', 1, [#a]);
+ expectPath('a.b', 'a.b', 2, [#a, #b]);
+ expectPath('a. b', 'a.b', 2, [#a, #b]);
+ expectPath('a .b', 'a.b', 2, [#a, #b]);
+ expectPath('a . b', 'a.b', 2, [#a, #b]);
+ expectPath(' a . b ', 'a.b', 2, [#a, #b]);
+ expectPath('a[0]', 'a[0]', 2, [#a, 0]);
+ expectPath('a [0]', 'a[0]', 2, [#a, 0]);
+ expectPath('a[0][1]', 'a[0][1]', 3, [#a, 0, 1]);
+ expectPath('a [ 0 ] [ 1 ] ', 'a[0][1]', 3, [#a, 0, 1]);
+ expectPath('[1234567890] ', '[1234567890]', 1, [1234567890]);
+ expectPath(' [1234567890] ', '[1234567890]', 1, [1234567890]);
+ expectPath('opt0', 'opt0', 1, [#opt0]);
+ // Dart note: Modified to avoid a private Dart symbol:
+ expectPath(r'$foo.$bar.baz_', r'$foo.$bar.baz_', 3,
+ [#$foo, #$bar, #baz_]);
+ // Dart note: this test is different because we treat ["baz"] always as a
+ // indexing operation.
+ expectPath('foo["baz"]', 'foo.baz', 2, [#foo, #baz]);
+ expectPath('foo["b\\"az"]', 'foo["b\\"az"]', 2, [#foo, 'b"az']);
+ expectPath("foo['b\\'az']", 'foo["b\'az"]', 2, [#foo, "b'az"]);
+ expectPath([#a, #b], 'a.b', 2, [#a, #b]);
+
+ expectPath('.', '<invalid path>', 0);
+ expectPath(' . ', '<invalid path>', 0);
+ expectPath('..', '<invalid path>', 0);
+ expectPath('a[4', '<invalid path>', 0);
+ expectPath('a.b.', '<invalid path>', 0);
+ expectPath('a,b', '<invalid path>', 0);
+ expectPath('a["foo]', '<invalid path>', 0);
+ expectPath('[0x04]', '<invalid path>', 0);
+ expectPath('[0foo]', '<invalid path>', 0);
+ expectPath('[foo-bar]', '<invalid path>', 0);
+ expectPath('foo-bar', '<invalid path>', 0);
+ expectPath('42', '<invalid path>', 0);
+ expectPath('a[04]', '<invalid path>', 0);
+ expectPath(' a [ 04 ]', '<invalid path>', 0);
+ expectPath(' 42 ', '<invalid path>', 0);
+ expectPath('foo["bar]', '<invalid path>', 0);
+ expectPath("foo['bar]", '<invalid path>', 0);
+ });
+
+ test('objects with toString are not supported', () {
+ // Dart note: this was intentionally not ported. See path_observer.dart.
+ expect(() => new PropertyPath([new Foo('a'), new Foo('b')]), throws);
});
+ test('invalid path returns null value', () {
+ var path = new PropertyPath('a b');
+ expect(path.isValid, isFalse);
+ expect(path.getValueFrom({'a': {'b': 2}}), isNull);
+ });
+
+
test('caching and ==', () {
- var start = new PropertyPath('abc.0');
+ var start = new PropertyPath('abc[0]');
for (int i = 1; i <= 100; i++) {
- expect(identical(new PropertyPath('abc.0'), start), true,
+ expect(identical(new PropertyPath('abc[0]'), start), true,
reason: 'should return identical path');
- var p = new PropertyPath('abc.$i');
+ var p = new PropertyPath('abc[$i]');
expect(identical(p, start), false,
reason: 'different paths should not be merged');
}
- var end = new PropertyPath('abc.0');
+ var end = new PropertyPath('abc[0]');
expect(identical(end, start), false,
reason: 'first entry expired');
expect(end, start, reason: 'different instances are equal');
@@ -52,7 +122,7 @@ main() => dirtyCheckZone().run(() {
test('hashCode equal', () {
var a = new PropertyPath([#foo, 2, #bar]);
- var b = new PropertyPath('foo.2.bar');
+ var b = new PropertyPath('foo[2].bar');
expect(identical(a, b), false, reason: 'only strings cached');
expect(a, b, reason: 'same paths are equal');
expect(a.hashCode, b.hashCode, reason: 'equal hashCodes');
@@ -68,6 +138,8 @@ main() => dirtyCheckZone().run(() {
expect(a.hashCode, isNot(b.hashCode), reason: 'different hashCodes');
});
});
+
+ group('CompoundObserver', compoundObserverTests);
});
observePathTests() {
@@ -203,7 +275,7 @@ observePathTests() {
test('Path Value With Indices', () {
var model = toObservable([]);
- var path = new PathObserver(model, '0');
+ var path = new PathObserver(model, '[0]');
path.open(expectAsync((x) {
expect(path.value, 123);
expect(x, 123);
@@ -361,6 +433,215 @@ observePathTests() {
expect(model.log, ['[]= bar 42']);
model.log.clear();
});
+
+ test('regression for TemplateBinding#161', () {
+ var model = toObservable({'obj': toObservable({'bar': false})});
+ var ob1 = new PathObserver(model, 'obj.bar');
+ var called = false;
+ ob1.open(() { called = true; });
+
+ var obj2 = new PathObserver(model, 'obj');
+ obj2.open(() { model['obj']['bar'] = true; });
+
+ model['obj'] = toObservable({ 'obj': 'obj' });
+
+ return new Future(() {})
+ .then((_) => expect(called, true));
+ });
+}
+
+compoundObserverTests() {
+ var model;
+ var observer;
+ bool called;
+ var newValues;
+ var oldValues;
+ var observed;
+
+ setUp(() {
+ model = new TestModel(1, 2, 3);
+ called = false;
+ });
+
+ callback(a, b, c) {
+ called = true;
+ newValues = a;
+ oldValues = b;
+ observed = c;
+ }
+
+ reset() {
+ called = false;
+ newValues = null;
+ oldValues = null;
+ observed = null;
+ }
+
+ expectNoChanges() {
+ observer.deliver();
+ expect(called, isFalse);
+ expect(newValues, isNull);
+ expect(oldValues, isNull);
+ expect(observed, isNull);
+ }
+
+ expectCompoundPathChanges(expectedNewValues,
+ expectedOldValues, expectedObserved, {deliver: true}) {
+ if (deliver) observer.deliver();
+ expect(called, isTrue);
+
+ expect(newValues, expectedNewValues);
+ var oldValuesAsMap = {};
+ for (int i = 0; i < expectedOldValues.length; i++) {
+ if (expectedOldValues[i] != null) {
+ oldValuesAsMap[i] = expectedOldValues[i];
+ }
+ }
+ expect(oldValues, oldValuesAsMap);
+ expect(observed, expectedObserved);
+
+ reset();
+ }
+
+ tearDown(() {
+ observer.close();
+ reset();
+ });
+
+ _path(s) => new PropertyPath(s);
+
+ test('simple', () {
+ observer = new CompoundObserver();
+ observer.addPath(model, 'a');
+ observer.addPath(model, 'b');
+ observer.addPath(model, _path('c'));
+ observer.open(callback);
+ expectNoChanges();
+
+ var expectedObs = [model, _path('a'), model, _path('b'), model, _path('c')];
+ model.a = -10;
+ model.b = 20;
+ model.c = 30;
+ expectCompoundPathChanges([-10, 20, 30], [1, 2, 3], expectedObs);
+
+ model.a = 'a';
+ model.c = 'c';
+ expectCompoundPathChanges(['a', 20, 'c'], [-10, null, 30], expectedObs);
+
+ model.a = 2;
+ model.b = 3;
+ model.c = 4;
+ expectCompoundPathChanges([2, 3, 4], ['a', 20, 'c'], expectedObs);
+
+ model.a = 'z';
+ model.b = 'y';
+ model.c = 'x';
+ expect(observer.value, ['z', 'y', 'x']);
+ expectNoChanges();
+
+ expect(model.a, 'z');
+ expect(model.b, 'y');
+ expect(model.c, 'x');
+ expectNoChanges();
+ });
+
+ test('reportChangesOnOpen', () {
+ observer = new CompoundObserver(true);
+ observer.addPath(model, 'a');
+ observer.addPath(model, 'b');
+ observer.addPath(model, _path('c'));
+
+ model.a = -10;
+ model.b = 20;
+ observer.open(callback);
+ var expectedObs = [model, _path('a'), model, _path('b'), model, _path('c')];
+ expectCompoundPathChanges([-10, 20, 3], [1, 2, null], expectedObs,
+ deliver: false);
+ });
+
+ test('All Observers', () {
+ observer = new CompoundObserver();
+ var pathObserver1 = new PathObserver(model, 'a');
+ var pathObserver2 = new PathObserver(model, 'b');
+ var pathObserver3 = new PathObserver(model, _path('c'));
+
+ observer.addObserver(pathObserver1);
+ observer.addObserver(pathObserver2);
+ observer.addObserver(pathObserver3);
+ observer.open(callback);
+
+ var expectedObs = [observerSentinelForTesting, pathObserver1,
+ observerSentinelForTesting, pathObserver2,
+ observerSentinelForTesting, pathObserver3];
+ model.a = -10;
+ model.b = 20;
+ model.c = 30;
+ expectCompoundPathChanges([-10, 20, 30], [1, 2, 3], expectedObs);
+
+ model.a = 'a';
+ model.c = 'c';
+ expectCompoundPathChanges(['a', 20, 'c'], [-10, null, 30], expectedObs);
+ });
+
+ test('Degenerate Values', () {
+ observer = new CompoundObserver();
+ observer.addPath(model, '.'); // invalid path
+ observer.addPath('obj-value', ''); // empty path
+ // Dart note: we don't port these two tests because in Dart we produce
+ // exceptions for these invalid paths.
+ // observer.addPath(model, 'foo'); // unreachable
+ // observer.addPath(3, 'bar'); // non-object with non-empty path
+ var values = observer.open(callback);
+ expect(values.length, 2);
+ expect(values[0], null);
+ expect(values[1], 'obj-value');
+ observer.close();
+ });
+
+ test('Heterogeneous', () {
+ model.c = null;
+ var otherModel = new TestModel(null, null, 3);
+
+ twice(value) => value * 2;
+ half(value) => value ~/ 2;
+
+ var compound = new CompoundObserver();
+ compound.addPath(model, 'a');
+ compound.addObserver(new ObserverTransform(new PathObserver(model, 'b'),
+ twice, setValue: half));
+ compound.addObserver(new PathObserver(otherModel, 'c'));
+
+ combine(values) => values[0] + values[1] + values[2];
+ observer = new ObserverTransform(compound, combine);
+
+ var newValue;
+ transformCallback(v) {
+ newValue = v;
+ called = true;
+ }
+ expect(observer.open(transformCallback), 8);
+
+ model.a = 2;
+ model.b = 4;
+ observer.deliver();
+ expect(called, isTrue);
+ expect(newValue, 13);
+ called = false;
+
+ model.b = 10;
+ otherModel.c = 5;
+ observer.deliver();
+ expect(called, isTrue);
+ expect(newValue, 27);
+ called = false;
+
+ model.a = 20;
+ model.b = 1;
+ otherModel.c = 5;
+ observer.deliver();
+ expect(called, isFalse);
+ expect(newValue, 27);
+ });
}
/// A matcher that checks that a closure throws a NoSuchMethodError matching the
@@ -426,7 +707,7 @@ class IndexerModel implements Indexable<String, dynamic> {
class TestModel extends ChangeNotifier {
var _a, _b, _c;
- TestModel();
+ TestModel([this._a, this._b, this._c]);
get a => _a;
@@ -456,3 +737,9 @@ class WatcherModel extends Observable {
WatcherModel();
}
+
+class Foo {
+ var value;
+ Foo(this.value);
+ String toString() => 'Foo$value';
+}
« no previous file with comments | « pkg/observe/pubspec.yaml ('k') | pkg/pkg.status » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698