// Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License. See License.txt in the project root for license information. // /// /// /// module CorsicaTests { "use strict"; var lexer = WinJS.UI._optionsLexer; var parser = WinJS.Binding._bindingParser; var tt = lexer.tokenType; interface ILexerTest { input: string; result: any[]; } var lexerTests: ILexerTest[] = [ { input: "a:b c; d:e f", result: [tt.identifier, tt.colon, tt.identifier, tt.identifier, tt.semicolon, tt.identifier, tt.colon, tt.identifier, tt.identifier] }, { input: "a:b c; d:e f;", result: [tt.identifier, tt.colon, tt.identifier, tt.identifier, tt.semicolon, tt.identifier, tt.colon, tt.identifier, tt.identifier, tt.semicolon] }, { input: "a.b.c:d.e.f g.h.i", result: [tt.identifier, tt.dot, tt.identifier, tt.dot, tt.identifier, tt.colon, tt.identifier, tt.dot, tt.identifier, tt.dot, tt.identifier, tt.identifier, tt.dot, tt.identifier, tt.dot, tt.identifier] }, { input: "a['foo'].b:c d.c['juice']", result: [tt.identifier, tt.leftBracket, tt.stringLiteral, tt.rightBracket, tt.dot, tt.identifier, tt.colon, tt.identifier, tt.identifier, tt.dot, tt.identifier, tt.leftBracket, tt.stringLiteral, tt.rightBracket] }, { input: "a[12].b:c d.c[43]", result: [tt.identifier, tt.leftBracket, tt.numberLiteral, tt.rightBracket, tt.dot, tt.identifier, tt.colon, tt.identifier, tt.identifier, tt.dot, tt.identifier, tt.leftBracket, tt.numberLiteral, tt.rightBracket] } ]; // Used by the lexer tests so that you don't have to write separator and eof tokens in the exepected output var removeSeparatorsAndEof = function removeSeparatorsAndEof(tokens) { for (var i = 0; i < tokens.length; i++) { if (tokens[i].type === tt.separator) { tokens.splice(i, 1); i--; } } if (tokens[tokens.length - 1].type === tt.eof) { tokens.splice(tokens.length - 1, 1); } }; // Used by one of the parser tests // window['TestGlobal'] = 12; interface IParserTest { name: string; input: string; result?: any[]; context?: any; error?: string; } var parserTests: IParserTest[] = [ { name: "thisAlone", input: "this:this c", result: [{ destination: [], source: [], initializer: 1 }], context: { c: 1 } }, { name: "thisDotted", input: "this.a:this.b c", result: [{ destination: ["a"], source: ["b"], initializer: 1 }], context: { c: 1 } }, { name: "simple", input: "a:b c", result: [{ destination: ["a"], source: ["b"], initializer: 1 }], context: { c: 1 } }, { name: "simpleWithTrailingSemicolon", input: "a:b c;", result: [{ destination: ["a"], source: ["b"], initializer: 1 }], context: { c: 1 } }, { name: "lotsOfDots", input: "a.b.c:d.e.f g.h.i", result: [{ destination: ["a", "b", "c"], source: ["d", "e", "f"], initializer: 1 }], context: { g: { h: { i: 1 } } } }, { name: "multipleBindings", input: "a:b c; d:e f;", result: [ { destination: ["a"], source: ["b"], initializer: 1 }, { destination: ["d"], source: ["e"], initializer: 2 } ], context: { c: 1, f: 2 } }, { name: "multipleBindingsNoTrailingSemicolon", input: "a:b c; d:e f", result: [ { destination: ["a"], source: ["b"], initializer: 1 }, { destination: ["d"], source: ["e"], initializer: 2 } ], context: { c: 1, f: 2 } }, { name: "multipleBindingsWithoutInitializers", input: "a:b; d:e;", result: [ { destination: ["a"], source: ["b"] }, { destination: ["d"], source: ["e"] } ], context: { c: 1, f: 2 } }, { name: "multipleBindingsWithSomeInitializers", input: "a:b; d:e f;", result: [ { destination: ["a"], source: ["b"] }, { destination: ["d"], source: ["e"], initializer: 2 } ], context: { f: 2 } }, { name: "multipleBindingsWithSomeInitializers2", input: "textContent:b; innerHtml:e f;", result: [ { destination: ["textContent"], source: ["b"] }, { destination: ["innerHtml"], source: ["e"], initializer: 2 } ], context: { f: 2 } }, { name: "bindingWithStringLiterals", input: "foo['bar'].baz:a.b['c']", result: [ { destination: ["foo", "bar", "baz"], source: ["a", "b", "c"] } ] }, { name: "bindingWithStringLiteralsDoubleQuotes", input: 'foo["bar"].baz:a.b["c"]', result: [ { destination: ["foo", "bar", "baz"], source: ["a", "b", "c"] } ] }, { name: "bindingWithNumberLiterals", input: 'foo[1].baz:a.b[3]', result: [ { destination: ["foo", 1, "baz"], source: ["a", "b", 3] } ] }, { name: "bindingWithStringLiteralsWithSpaces", input: 'foo["for bar baz"].baz:a.b[3]', result: [ { destination: ["foo", "for bar baz", "baz"], source: ["a", "b", 3] } ] }, { name: "multipleBindingsWithStringLiterals", input: 'foo["for bar baz"].baz:a.b[3]; a["b"]["c"].d:e.f["g"].h["j"]', result: [ { destination: ["foo", "for bar baz", "baz"], source: ["a", "b", 3] }, { destination: ["a", "b", "c", "d"], source: ["e", "f", "g", "h", "j"] } ] }, { name: "lookupInitializerInArray", input: 'a:b c[2]', result: [ { destination: ["a"], source: ["b"], initializer: 12 } ], context: { c: [10, 11, 12] } }, { name: "errorBinding1", input: "textContent:b:c", error: "Invalid binding:'textContent:b:c'. Expected to be ':;'. Unexpected token: colon, expected one of: identifier, semicolon, eof, at offset 13" }, { name: "errorBinding2", input: "textContent:b c: innerHtml: d e", error: "Invalid binding:'textContent:b c: innerHtml: d e'. Expected to be ':;'. Unexpected token: colon, expected one of: identifier, semicolon, eof, at offset 14", context: { c: 1, e: 3 } }, { name: "errorBindingStartingWithStringLiteral", input: "['foo'].bar:baz", error: "Invalid binding:'['foo'].bar:baz'. Expected to be ':;'. Unexpected token: leftBracket, expected one of: identifier, semicolon, eof, at offset 0" }, { name: "errorBindingWithArrayLiteral", input: "foo[[1, 2, 3]]:baz", error: "Invalid binding:'foo[[1, 2, 3]]:baz'. Expected to be ':;'. Unexpected token: leftBracket, expected one of: stringLiteral, numberLiteral, at offset 4" }, { name: "testingReservedWords", input: 'a.else:b.if.while.eval c.for.foreach', result: [ { destination: ["a", "else"], source: ["b", "if", "while", "eval"], initializer: 12 } ], context: { c: { for: { foreach: 12 } } } } ]; export class BindingParser { } lexerTests.forEach(function (test, i) { var name = "testLexer" + i; BindingParser.prototype[name] = function () { var input = test.input; var result = test.result; // We use the same lexer as the options lexer. It needs to support ';' for this usage. var tokens = lexer(input); removeSeparatorsAndEof(tokens); var types = []; tokens.forEach(function (token) { types.push(token.type); }); LiveUnit.Assert.areEqual(result.length, types.length); for (var j = 0, len = result.length; j < len; j++) { LiveUnit.Assert.areEqual(result[j], types[j]); } }; }); parserTests.forEach(function (test, i) { var name = "testParser" + i; if (test.name) { name += "_" + test.name; } BindingParser.prototype[name] = function () { var input = test.input; var result = test.result; var jsonResult = JSON.stringify(result); try { var options = parser(input, test.context); var jsonOptions = JSON.stringify(options); LiveUnit.Assert.areEqual(jsonResult, jsonOptions); } catch (e) { if (test.error) { LiveUnit.Assert.areEqual(test.error, e.message); } else { throw e; } } }; }); }; LiveUnit.registerTestClass("CorsicaTests.BindingParser");