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

Unified Diff: third_party/pkg/angular/test/core/parser/parser_spec.dart

Issue 180873006: Update the Angular/DI tests to latest from github. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Review feedback Created 6 years, 10 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/core/parser/parser_spec.dart
diff --git a/third_party/pkg/angular/test/core/parser/parser_spec.dart b/third_party/pkg/angular/test/core/parser/parser_spec.dart
index 6578931c3e39b5e6521cd024b953c0a177774ce8..6db4a5b3fc5977aac042de390b8843bea5b6dbfe 100644
--- a/third_party/pkg/angular/test/core/parser/parser_spec.dart
+++ b/third_party/pkg/angular/test/core/parser/parser_spec.dart
@@ -1,6 +1,7 @@
library parser_spec;
import '../../_specs.dart';
+import 'package:angular/utils.dart' show RESERVED_WORDS;
// Used to test getter / setter logic.
class TestData {
@@ -44,20 +45,23 @@ toBool(x) => (x is num) ? x != 0 : x == true;
main() {
describe('parse', () {
- var scope;
+ Map<String, dynamic> context;
Parser<Expression> parser;
+ FilterMap filters;
beforeEach(module((Module module) {
module.type(IncrementFilter);
module.type(SubstringFilter);
}));
- beforeEach(inject((Parser injectedParser) {
+ beforeEach(inject((Parser injectedParser, FilterMap injectedFilters) {
parser = injectedParser;
+ filters = injectedFilters;
}));
- eval(String text) => parser(text).eval(scope);
+ eval(String text, [FilterMap f])
+ => parser(text).eval(context, f == null ? filters : f);
expectEval(String expr) => expect(() => eval(expr));
- beforeEach(inject((Scope rootScope) { scope = rootScope; }));
+ beforeEach((){ context = {}; });
describe('expressions', () {
it('should parse numerical expressions', () {
@@ -123,11 +127,11 @@ main() {
expect(eval("true||false?10:20")).toEqual(true||false?10:20);
expect(eval("true&&false?10:20")).toEqual(true&&false?10:20);
expect(eval("true?a=10:a=20")).toEqual(true?a=10:a=20);
- expect([scope['a'], a]).toEqual([10, 10]);
- scope['a'] = a = null;
+ expect([context['a'], a]).toEqual([10, 10]);
+ context['a'] = a = null;
expect(eval("b=true?a=false?11:c=12:a=13")).toEqual(
b=true?a=false?11:c=12:a=13);
- expect([scope['a'], scope['b'], scope['c']]).toEqual([a, b, c]);
+ expect([context['a'], context['b'], context['c']]).toEqual([a, b, c]);
expect([a, b, c]).toEqual([12, 12, 12]);
});
@@ -139,6 +143,12 @@ main() {
expect(eval("4 + 4 + ' str'")).toEqual("8 str");
expect(eval("'str ' + 4 + 4")).toEqual("str 44");
});
+
+ it('should allow keyed access on non-maps', () {
+ context['nonmap'] = new BracketButNotMap();
+ expect(eval("nonmap['hello']")).toEqual('hello');
+ expect(eval("nonmap['hello']=3")).toEqual(3);
+ });
});
describe('error handling', () {
@@ -171,12 +181,6 @@ main() {
});
- it('should throw on non-list, non-map field access', () {
- expectEval("6[3]").toThrow(errStr('Eval Error: Attempted field access on a non-list, non-map while evaling [6[3]]'));
- expectEval("6[3]=2").toThrow(errStr('Eval Error: Attempting to set a field on a non-list, non-map while evaling [6[3]=2'));
- });
-
-
it('should throw on incorrect ternary operator syntax', () {
expectEval("true?1").toThrow('Parser Error: Conditional expression true?1 requires all 3 expressions');
});
@@ -267,7 +271,7 @@ main() {
it('should let null be null', () {
- scope['map'] = {};
+ context['map'] = {};
expect(eval('null')).toBe(null);
expect(eval('map.null')).toBe(null);
@@ -286,6 +290,13 @@ main() {
});
+ it('should pass noSuchMethExceptions through getters', () {
+ expect(() {
+ parser('getNoSuchMethod').eval(new ScopeWithErrors());
+ }).toThrow("iDontExist");
+ });
+
+
it('should pass exceptions through methods', () {
expect(() {
parser('foo()').eval(new ScopeWithErrors());
@@ -312,80 +323,140 @@ main() {
describe('setters', () {
it('should set a field in a map', () {
- scope['map'] = {};
+ context['map'] = {};
eval('map["square"] = 6');
eval('map.dot = 7');
- expect(scope['map']['square']).toEqual(6);
- expect(scope['map']['dot']).toEqual(7);
+ expect(context['map']['square']).toEqual(6);
+ expect(context['map']['dot']).toEqual(7);
});
it('should set a field in a list', () {
- scope['list'] = [];
+ context['list'] = [];
eval('list[3] = 2');
- expect(scope['list'].length).toEqual(4);
- expect(scope['list'][3]).toEqual(2);
+ expect(context['list'].length).toEqual(4);
+ expect(context['list'][3]).toEqual(2);
});
it('should set a field on an object', () {
- scope['obj'] = new SetterObject();
+ context['obj'] = new SetterObject();
eval('obj.field = 1');
- expect(scope['obj'].field).toEqual(1);
+ expect(context['obj'].field).toEqual(1);
});
it('should set a setter on an object', () {
- scope['obj'] = new SetterObject();
+ context['obj'] = new SetterObject();
eval('obj.setter = 2');
- expect(scope['obj'].setterValue).toEqual(2);
+ expect(context['obj'].setterValue).toEqual(2);
});
it('should set a []= on an object', () {
- scope['obj'] = new OverloadObject();
+ context['obj'] = new OverloadObject();
eval('obj.overload = 7');
- expect(scope['obj'].overloadValue).toEqual(7);
+ expect(context['obj'].overloadValue).toEqual(7);
});
it('should set a field in a nested map on an object', () {
- scope['obj'] = new SetterObject();
+ context['obj'] = new SetterObject();
eval('obj.map.mapKey = 3');
- expect(scope['obj'].map['mapKey']).toEqual(3);
+ expect(context['obj'].map['mapKey']).toEqual(3);
});
it('should set a field in a nested object on an object', () {
- scope['obj'] = new SetterObject();
+ context['obj'] = new SetterObject();
eval('obj.nested.field = 1');
- expect(scope['obj'].nested.field).toEqual(1);
+ expect(context['obj'].nested.field).toEqual(1);
});
it('should create a map for dotted acces', () {
- scope['obj'] = new SetterObject();
+ context['obj'] = new SetterObject();
eval('obj.field.key = 4');
- expect(scope['obj'].field['key']).toEqual(4);
+ expect(context['obj'].field['key']).toEqual(4);
});
xit('should throw a nice error for type mismatch', () {
- scope['obj'] = new SetterObject();
+ context['obj'] = new SetterObject();
expect(() {
eval('obj.integer = "hello"');
}).toThrow("Eval Error: Caught type 'String' is not a subtype of type 'int' of 'value'. while evaling [obj.integer = \"hello\"]");
});
});
+ describe('reserved words', () {
+ it('should support reserved words in member get access', () {
+ for (String reserved in RESERVED_WORDS) {
+ expect(parser("o.$reserved").eval({ 'o': new Object() })).toEqual(null);
+ expect(parser("o.$reserved").eval({ 'o': { reserved: reserved }})).toEqual(reserved);
+ }
+ });
+
+
+ it('should support reserved words in member set access', () {
+ for (String reserved in RESERVED_WORDS) {
+ expect(parser("o.$reserved = 42").eval({ 'o': new Object() })).toEqual(42);
+ var map = { reserved: 0 };
+ expect(parser("o.$reserved = 42").eval({ 'o': map })).toEqual(42);
+ expect(map[reserved]).toEqual(42);
+ }
+ });
+
+
+ it('should support reserved words in member calls', () {
+ for (String reserved in RESERVED_WORDS) {
+ expect(() {
+ parser("o.$reserved()").eval({ 'o': new Object() });
+ }).toThrow('Undefined function $reserved');
+ expect(parser("o.$reserved()").eval({ 'o': { reserved: () => reserved }})).toEqual(reserved);
+ }
+ });
+
+
+ it('should support reserved words in scope get access', () {
+ for (String reserved in RESERVED_WORDS) {
+ if ([ "true", "false", "null"].contains(reserved)) continue;
+ expect(parser("$reserved").eval(new Object())).toEqual(null);
+ expect(parser("$reserved").eval({ reserved: reserved })).toEqual(reserved);
+ }
+ });
+
+
+ it('should support reserved words in scope set access', () {
+ for (String reserved in RESERVED_WORDS) {
+ if ([ "true", "false", "null"].contains(reserved)) continue;
+ expect(parser("$reserved = 42").eval(new Object())).toEqual(42);
+ var map = { reserved: 0 };
+ expect(parser("$reserved = 42").eval(map)).toEqual(42);
+ expect(map[reserved]).toEqual(42);
+ }
+ });
+
+
+ it('should support reserved words in scope calls', () {
+ for (String reserved in RESERVED_WORDS) {
+ if ([ "true", "false", "null"].contains(reserved)) continue;
+ expect(() {
+ parser("$reserved()").eval(new Object());
+ }).toThrow('Undefined function $reserved');
+ expect(parser("$reserved()").eval({ reserved: () => reserved })).toEqual(reserved);
+ }
+ });
+ });
+
describe('test cases imported from AngularJS', () {
//// ==== IMPORTED ITs
it('should parse expressions', () {
@@ -420,11 +491,11 @@ main() {
it('should parse ternary', () {
- var returnTrue = scope['returnTrue'] = () => true;
- var returnFalse = scope['returnFalse'] = () => false;
- var returnString = scope['returnString'] = () => 'asd';
- var returnInt = scope['returnInt'] = () => 123;
- var identity = scope['identity'] = (x) => x;
+ var returnTrue = context['returnTrue'] = () => true;
+ var returnFalse = context['returnFalse'] = () => false;
+ var returnString = context['returnString'] = () => 'asd';
+ var returnInt = context['returnInt'] = () => 123;
+ var identity = context['identity'] = (x) => x;
var B = toBool;
// Simple.
@@ -457,10 +528,10 @@ main() {
expect(eval('0&&1?0:1')).toEqual(B(0)&&B(1)?0:1);
expect(eval('1||0?0:0')).toEqual(B(1)||B(0)?0:0);
- expect(eval('0?0&&1:2')).toEqual(B(0)?0&&1:2);
- expect(eval('0?1&&1:2')).toEqual(B(0)?1&&1:2);
- expect(eval('0?0||0:1')).toEqual(B(0)?0||0:1);
- expect(eval('0?0||1:2')).toEqual(B(0)?0||1:2);
+ expect(eval('0?0&&1:2')).toEqual(B(0)?B(0)&&B(1):2);
+ expect(eval('0?1&&1:2')).toEqual(B(0)?B(1)&&B(1):2);
+ expect(eval('0?0||0:1')).toEqual(B(0)?B(0)||B(0):1);
+ expect(eval('0?0||1:2')).toEqual(B(0)?B(0)||B(1):2);
expect(eval('1?0&&1:2')).toEqual(B(1)?B(0)&&B(1):2);
expect(eval('1?1&&1:2')).toEqual(B(1)?B(1)&&B(1):2);
@@ -495,8 +566,8 @@ main() {
it('should access scope', () {
- scope['a'] = 123;
- scope['b'] = {'c': 456};
+ context['a'] = 123;
+ context['b'] = {'c': 456};
expect(eval("a")).toEqual(123);
expect(eval("b.c")).toEqual(456);
expect(eval("x.y.z")).toEqual(null);
@@ -504,27 +575,27 @@ main() {
it('should access classes on scope', () {
- scope['ident'] = new Ident();
+ context['ident'] = new Ident();
expect(eval('ident.id(6)')).toEqual(6);
expect(eval('ident.doubleId(4,5)')).toEqual([4, 5]);
});
it('should resolve deeply nested paths (important for CSP mode)', () {
- scope['a'] = {'b': {'c': {'d': {'e': {'f': {'g': {'h': {'i': {'j': {'k': {'l': {'m': {'n': 'nooo!'}}}}}}}}}}}}};
+ context['a'] = {'b': {'c': {'d': {'e': {'f': {'g': {'h': {'i': {'j': {'k': {'l': {'m': {'n': 'nooo!'}}}}}}}}}}}}};
expect(eval("a.b.c.d.e.f.g.h.i.j.k.l.m.n")).toBe('nooo!');
});
it('should be forgiving', () {
- scope = {'a': {'b': 23}};
+ context = {'a': {'b': 23}};
expect(eval('b')).toBeNull();
expect(eval('a.x')).toBeNull();
});
it('should catch NoSuchMethod', () {
- scope = {'a': {'b': 23}};
+ context = {'a': {'b': 23}};
expect(() => eval('a.b.c.d')).toThrow('NoSuchMethod');
});
@@ -535,20 +606,20 @@ main() {
it('should evaluate assignments', () {
- scope = {'g': 4, 'arr': [3,4]};
+ context = {'g': 4, 'arr': [3,4]};
expect(eval("a=12")).toEqual(12);
- expect(scope["a"]).toEqual(12);
+ expect(context["a"]).toEqual(12);
expect(eval("arr[c=1]")).toEqual(4);
- expect(scope["c"]).toEqual(1);
+ expect(context["c"]).toEqual(1);
expect(eval("x.y.z=123;")).toEqual(123);
- expect(scope["x"]["y"]["z"]).toEqual(123);
+ expect(context["x"]["y"]["z"]).toEqual(123);
expect(eval("a=123; b=234")).toEqual(234);
- expect(scope["a"]).toEqual(123);
- expect(scope["b"]).toEqual(234);
+ expect(context["a"]).toEqual(123);
+ expect(context["b"]).toEqual(234);
});
// TODO: assignment to an arr[c]
@@ -557,18 +628,18 @@ main() {
it('should evaluate function call without arguments', () {
- scope['constN'] = () => 123;
+ context['constN'] = () => 123;
expect(eval("constN()")).toEqual(123);
});
it('should access a protected keyword on scope', () {
- scope['const'] = 3;
+ context['const'] = 3;
expect(eval('const')).toEqual(3);
});
it('should evaluate function call with arguments', () {
- scope["add"] = (a,b) {
+ context["add"] = (a,b) {
return a+b;
};
expect(eval("add(1,2)")).toEqual(3);
@@ -576,31 +647,31 @@ main() {
it('should evaluate function call from a return value', () {
- scope["val"] = 33;
- scope["getter"] = () { return () { return scope["val"]; };};
+ context["val"] = 33;
+ context["getter"] = () { return () { return context["val"]; };};
expect(eval("getter()()")).toBe(33);
});
it('should evaluate methods on object', () {
- scope['obj'] = ['ABC'];
+ context['obj'] = ['ABC'];
var fn = parser("obj.elementAt(0)").eval;
- expect(fn(scope)).toEqual('ABC');
- expect(scope.$eval(fn)).toEqual('ABC');
+ expect(fn(context)).toEqual('ABC');
});
it('should only check locals on first dereference', () {
- scope['a'] = {'b': 1};
+ context['a'] = {'b': 1};
+ context['this'] = context;
var locals = {'b': 2};
- var fn = parser("this['a'].b").bind(scope, ScopeLocals.wrapper);
+ var fn = parser("this['a'].b").bind(context, ScopeLocals.wrapper);
expect(fn(locals)).toEqual(1);
});
it('should evaluate multiplication and division', () {
- scope["taxRate"] = 8;
- scope["subTotal"] = 100;
+ context["taxRate"] = 8;
+ context["subTotal"] = 100;
expect(eval("taxRate / 100 * subTotal")).toEqual(8);
expect(eval("taxRate ~/ 100 * subTotal")).toEqual(0);
expect(eval("subTotal * taxRate / 100")).toEqual(8);
@@ -654,20 +725,13 @@ main() {
it('should evaluate objects on scope context', () {
- scope["a"] = "abc";
+ context["a"] = "abc";
expect(eval("{a:a}")["a"]).toEqual("abc");
});
- it('should evalulate objects on Scope', inject((Scope scope) {
- expect(eval(r'$id')).toEqual(scope.$id);
- expect(eval(r'$root')).toEqual(scope.$root);
- expect(eval(r'$parent')).toEqual(scope.$parent);
- }));
-
-
it('should evaluate field access on function call result', () {
- scope["a"] = () {
+ context["a"] = () {
return {'name':'misko'};
};
expect(eval("a().name")).toEqual("misko");
@@ -675,13 +739,13 @@ main() {
it('should evaluate field access after array access', () {
- scope["items"] = [{}, {'name':'misko'}];
+ context["items"] = [{}, {'name':'misko'}];
expect(eval('items[1].name')).toEqual("misko");
});
it('should evaluate array assignment', () {
- scope["items"] = [];
+ context["items"] = [];
expect(eval('items[1] = "abc"')).toEqual("abc");
expect(eval('items[1]')).toEqual("abc");
@@ -737,20 +801,20 @@ main() {
it('should evaluate undefined', () {
expect(eval("undefined")).toBeNull();
expect(eval("a=undefined")).toBeNull();
- expect(scope["a"]).toBeNull();
+ expect(context["a"]).toBeNull();
});
it('should allow assignment after array dereference', () {
- scope["obj"] = [{}];
+ context["obj"] = [{}];
eval('obj[0].name=1');
// can not be expressed in Dart expect(scope["obj"]["name"]).toBeNull();
- expect(scope["obj"][0]["name"]).toEqual(1);
+ expect(context["obj"][0]["name"]).toEqual(1);
});
it('should short-circuit AND operator', () {
- scope["run"] = () {
+ context["run"] = () {
throw "IT SHOULD NOT HAVE RUN";
};
expect(eval('false && run()')).toBe(false);
@@ -758,7 +822,7 @@ main() {
it('should short-circuit OR operator', () {
- scope["run"] = () {
+ context["run"] = () {
throw "IT SHOULD NOT HAVE RUN";
};
expect(eval('true || run()')).toBe(true);
@@ -766,9 +830,9 @@ main() {
it('should support method calls on primitive types', () {
- scope["empty"] = '';
- scope["zero"] = 0;
- scope["bool"] = false;
+ context["empty"] = '';
+ context["zero"] = 0;
+ context["bool"] = false;
// DOES NOT WORK. String.substring is not reflected. Or toString
// expect(eval('empty.substring(0)')).toEqual('');
@@ -862,8 +926,8 @@ main() {
it('should work with scopes', inject((Scope scope) {
- scope.a = {'b': 6};
- expect(parser('a.b').bind(scope, ScopeLocals.wrapper)({'a': {'b':1}})).toEqual(1);
+ scope.context['a'] = {'b': 6};
+ expect(parser('a.b').bind(scope.context, ScopeLocals.wrapper)({'a': {'b':1}})).toEqual(1);
}));
it('should expose assignment function', () {
@@ -880,28 +944,49 @@ main() {
describe('filters', () {
it('should call a filter', () {
- expect(eval("'Foo'|uppercase")).toEqual("FOO");
- expect(eval("'fOo'|uppercase|lowercase")).toEqual("foo");
+ expect(eval("'Foo'|uppercase", filters)).toEqual("FOO");
+ expect(eval("'fOo'|uppercase|lowercase", filters)).toEqual("foo");
});
it('should call a filter with arguments', () {
- expect(eval("1|increment:2")).toEqual(3);
- });
-
- it('should evaluate grouped filters', () {
- scope.name = 'MISKO';
- expect(scope.$eval('n = (name|lowercase)')).toEqual('misko');
- expect(scope.$eval('n')).toEqual('misko');
+ expect(eval("1|increment:2", filters)).toEqual(3);
});
it('should parse filters', () {
expect(() {
- scope.$eval("1|nonexistent");
+ eval("1|nonexistent");
+ }).toThrow('No NgFilter: nonexistent found!');
+ expect(() {
+ eval("1|nonexistent", filters);
}).toThrow('No NgFilter: nonexistent found!');
- scope.offset = 3;
- expect(scope.$eval("'abcd'|substring:1:offset")).toEqual("bc");
- expect(scope.$eval("'abcd'|substring:1:3|uppercase")).toEqual("BC");
+ context['offset'] = 3;
+ expect(eval("'abcd'|substring:1:offset")).toEqual("bc");
+ expect(eval("'abcd'|substring:1:3|uppercase")).toEqual("BC");
+ });
+
+ it('should only use filters that are passed as an argument', inject((Injector injector) {
+ var expression = parser("'World'|hello");
+ expect(() {
+ expression.eval({}, filters);
+ }).toThrow('No NgFilter: hello found!');
+
+ var module = new Module()
+ ..type(HelloFilter);
+ var childInjector = injector.createChild([module],
+ forceNewInstances: [FilterMap]);
+ var newFilters = childInjector.get(FilterMap);
+
+ expect(expression.eval({}, newFilters)).toEqual('Hello, World!');
+ }));
+
+ it('should not allow filters in a chain', () {
+ expect(() {
+ parser("1;'World'|hello");
+ }).toThrow('cannot have a filter in a chain the end of the expression [1;\'World\'|hello]');
+ expect(() {
+ parser("'World'|hello;1");
+ }).toThrow('cannot have a filter in a chain at column 15 in [\'World\'|hello;1]');
});
});
});
@@ -928,9 +1013,15 @@ class OverloadObject implements Map {
noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
}
+class BracketButNotMap {
+ operator[](String name) => name;
+ operator[]=(String name, value) {}
+}
+
class ScopeWithErrors {
String get boo { throw "boo to you"; }
String foo() { throw "foo to you"; }
+ get getNoSuchMethod => null.iDontExist();
}
@NgFilter(name:'increment')
@@ -944,3 +1035,10 @@ class SubstringFilter {
return str.substring(startIndex, endIndex);
}
}
+
+@NgFilter(name:'hello')
+class HelloFilter {
+ call(String str) {
+ return 'Hello, $str!';
+ }
+}

Powered by Google App Engine
This is Rietveld 408576698