| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422 |
- //-------------------------------------------------------------------------------------------------------
- // Copyright (C) Microsoft. All rights reserved.
- // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
- //-------------------------------------------------------------------------------------------------------
- WScript.LoadScriptFile("..\\UnitTestFramework\\UnitTestFramework.js");
- var tests = [
- {
- name: "Basic destructuring syntax as params",
- body: function () {
- assert.doesNotThrow(function () { eval("function foo({x:x}) {}"); }, "Object destructuring pattern as a formal is valid syntax");
- assert.doesNotThrow(function () { eval("function foo({x}) {}"); }, "Object destructuring pattern (shorthand) as a formal is valid syntax");
- assert.doesNotThrow(function () { eval("function foo([x]) {}"); }, "Array destructuring pattern as a formal is valid syntax");
- assert.doesNotThrow(function () { eval("function foo({x:x}, y) {}"); }, "Object destructuring pattern as a first formal is valid syntax");
- assert.doesNotThrow(function () { eval("function foo([x], y) {}"); }, "Array destructuring pattern as a first formal is valid syntax");
- assert.doesNotThrow(function () { eval("function foo(y, {x:x}) {}"); }, "Object destructuring pattern as a second formal is valid syntax");
- assert.doesNotThrow(function () { eval("function foo(y, [x]) {}"); }, "Array destructuring pattern as a second formal is valid syntax");
- assert.doesNotThrow(function () { eval("function foo({}) {}"); }, "Object destructuring pattern (with empty syntax) as a formal is valid syntax");
- assert.doesNotThrow(function () { eval("function foo([]) {}"); }, "Array destructuring pattern (with empty syntax) as a formal is valid syntax");
- assert.doesNotThrow(function () { eval("function foo([,]) {}"); }, "Array destructuring pattern (with empty syntax and comma) as a formal is valid syntax");
- }
- },
- {
- name: "Destructuring syntax as params - invalid syntax",
- body: function () {
- assert.throws(function () { eval("function foo({,}) {}"); }, SyntaxError, "Object destructuring pattern as a formal with empty names is not valid syntax", "Expected identifier, string or number");
- assert.throws(function () { eval("function foo(({})) {}"); }, SyntaxError, "Object destructuring pattern as a formal surrounded with parens is not valid syntax", "Expected identifier");
- assert.throws(function () { eval("function foo(([])) {}"); }, SyntaxError, "Array destructuring pattern as a formal surrounded with parens is not valid syntax", "Expected identifier");
- assert.throws(function () { eval("function foo([x}) {}"); }, SyntaxError, "Array destructuring pattern without right bracket is not valid syntax", "Unexpected operator in destructuring expression");
- assert.throws(function () { eval("function foo({x:abc+1}) {}"); }, SyntaxError, "Object destructuring pattern with operator is not valid syntax", "Unexpected operator in destructuring expression");
- assert.throws(function () { eval("function foo({x:abc.d}) {}"); }, SyntaxError, "Object destructuring pattern as a formal with property reference is not valid syntax", "Syntax error");
- assert.throws(function () { eval("function foo([abc.d]) {}"); }, SyntaxError, "Array destructuring pattern as a formal with property reference is not valid syntax", "Syntax error");
- assert.throws(function () { eval("function foo([super]) {}"); }, SyntaxError, "Array destructuring pattern as a formal identifier as super is not valid syntax", "The use of a keyword for an identifier is invalid");
- assert.throws(function () { eval("function foo({x:super}) {}"); }, SyntaxError, "Object destructuring pattern as a formal identifier as super is not valid syntax", "The use of a keyword for an identifier is invalid");
- assert.throws(function () { eval("function foo({x:super()}) {}"); }, SyntaxError, "Object destructuring pattern as a formal identifier as super call is not valid syntax", "The use of a keyword for an identifier is invalid");
- assert.throws(function () { eval("function foo([super()]) {}"); }, SyntaxError, "Array destructuring pattern as a formal identifier as super call is not valid syntax", "The use of a keyword for an identifier is invalid");
- }
- },
- {
- name: "Destructuring syntax as params - Multiple and mixed patterns",
- body: function () {
- assert.doesNotThrow(function () { eval("function foo({x:x}, {y:y}, {z:z}) {}"); }, "Three params as object pattern is valid syntax");
- assert.doesNotThrow(function () { eval("function foo([x], [y], [z]) {}"); }, "Three params as array pattern is valid syntax");
- assert.doesNotThrow(function () { eval("function foo({x1:x1, x2:x2, x3:x3}, {y1:y1, y1:y2}) {}"); }, "Two params as object pattern, and each pattern has more than one matching name is valid syntax");
- assert.doesNotThrow(function () { eval("function foo([x1, x2, x3], [y1, y2, y3]) {}"); }, "Two params as array pattern, and each pattern has more than one matching name is valid syntax");
- assert.doesNotThrow(function () { eval("function foo({x1:x1}, [y1]) {}"); }, "Two params with first object pattern and second array pattern is valid syntax");
- assert.doesNotThrow(function () { eval("function foo([x1], {y1:y1}) {}"); }, "Two params with first array pattern and second object pattern is valid syntax");
- assert.doesNotThrow(function () { eval("function foo(x1, {x2, x3}, [x4, x5], x6) {}"); }, "Multiple params with mixed of binding identifier and binding pattern is valid syntax");
- assert.doesNotThrow(function () { eval("function foo({x1:[y1]}) {}"); }, "Object destructuring pattern nesting array pattern as a formal is valid syntax");
- assert.doesNotThrow(function () { eval("function foo([x1, {y1:y1}]) {}"); }, "Array destructuring pattern nesting object pattern as a formal is valid syntax");
- }
- },
- {
- name: "Destructuring syntax as params - class/function expression/function expression with names/lambda",
- body: function () {
- assert.doesNotThrow(function () { eval("({x}) => x;"); }, "Object destructuring pattern as a formal on lambda is valid syntax");
- assert.doesNotThrow(function () { eval("([x]) => x;"); }, "Array destructuring pattern as a formal on lambda is valid syntax");
- assert.doesNotThrow(function () { eval("class foo { constructor({x1}){} }"); }, "Object destructuring pattern as a formal on constructor of class is valid syntax");
- assert.doesNotThrow(function () { eval("class foo { constructor([x1]){} }"); }, "Array destructuring pattern as a formal on constructor of class is valid syntax");
- assert.doesNotThrow(function () { eval("class foo { method({x1}){ }; set prop({x1}){} }"); }, "Object destructuring pattern on method and setter of class is valid syntax");
- assert.doesNotThrow(function () { eval("class foo { method([x1]){ }; set prop([x1]){} }"); }, "Array destructuring pattern on method and setter of class is valid syntax");
- assert.doesNotThrow(function () { eval("let foo = function ({x1}, [x2]){};"); }, "Destructuring patterns as formals on function expression is valid syntax");
- assert.doesNotThrow(function () { eval("(function({x1}, [x2]){})"); }, "Destructuring patterns as formals on anonymous function is valid syntax");
- assert.doesNotThrow(function () { eval("let bar = function foo({x1}, [x2]){};"); }, "Destructuring patterns as formals on named function expression is valid syntax");
- assert.doesNotThrow(function () { eval("new Function('{x}', '[y]', 'return x + y');"); }, "Destructuring patterns as formals on function constructor is valid syntax");
- assert.doesNotThrow(function () { eval("let obj = { foo({x}) {}, set prop([x]) {} }"); }, "Destructuring pattern as a formal on functions of object literal is valid syntax");
- }
- },
- {
- name: "Destructuring syntax as params - Initializer",
- body: function () {
- assert.doesNotThrow(function () { eval("function foo({x:x = 10}) {}"); }, "One param as object destructuring pattern with initializer is valid syntax");
- assert.doesNotThrow(function () { eval("function foo([x = 20]) {}"); }, "One param as array destructuring pattern with initializer is valid syntax");
- assert.doesNotThrow(function () { eval("function foo({x1:x1 = 1}, {y1:y1 = 2}) {}"); }, "Two params as object destructuring pattern with initializer is valid syntax");
- assert.doesNotThrow(function () { eval("function foo([x1 = 1], [y1 = 2]) {}"); }, "Two params as array destructuring pattern with initializer is valid syntax");
- assert.doesNotThrow(function () { eval("function foo({x1:x1 = 1, x2:x2 = 2, x3:x3 = 3}) {}"); }, "One param as object destructuring pattern has three names with initializer is valid syntax");
- assert.doesNotThrow(function () { eval("function foo([x1 = 1, x2 = 2, x3 = 3]) {}"); }, "One param as array destructuring pattern has three names with initializer is valid syntax");
- assert.doesNotThrow(function () { eval("function foo({x1:x1 = 1}, [y1 = 2]) {}"); }, "First param as object pattern and second as array pattern with initializer is valid syntax");
- assert.doesNotThrow(function () { eval("function foo([x1 = 1], {y1:y1 = 2}) {}"); }, "First param as array pattern and second as object pattern with initializer is valid syntax");
- assert.doesNotThrow(function () { eval("function foo({x:x} = {x:1}) {}"); }, "Object destructuring pattern has default value is valid syntax");
- assert.doesNotThrow(function () { eval("function foo([x] = [1]) {}"); }, "Array destructuring pattern has default value is valid syntax");
- assert.doesNotThrow(function () { eval("function foo({x:x = 1} = {x:2}) {}"); }, "Object destructuring pattern has default and identifier has initializer is valid syntax");
- assert.doesNotThrow(function () { eval("function foo([x = 1] = [2]) {}"); }, "Array destructuring pattern has default and identifier has initializer is valid syntax");
- assert.doesNotThrow(function () { eval("function foo({x1:[y1 = 1]}) {}"); }, "Object destructuring pattern nesting array pattern which has initializer is valid syntax");
- assert.doesNotThrow(function () { eval("function foo([x1, {y1:y1 = 1}]) {}"); }, "Array destructuring pattern nesting object pattern which has initializer is valid syntax");
- assert.doesNotThrow(function () { eval("function foo({x1:[y1 = 1] = [2]} = {x1:[3]}) {}"); }, "Object destructuring pattern has default and nesting array pattern which has initializer is valid syntax");
- assert.doesNotThrow(function () { eval("function foo([{y1:y1 = 1} = {y1:2}] = [{y1:3}]) {}"); }, "Array destructuring pattern has default and nesting object pattern which has initializer is valid syntax");
- }
- },
- {
- name: "Destructuring syntax as params - redeclarations",
- body: function () {
- assert.throws(function () { eval("function foo({x:x, x:x}) {}"); }, SyntaxError, "One formal as object pattern has duplicate binding identifiers is not valid syntax", "Let/Const redeclaration");
- assert.throws(function () { eval("function foo({x:x}, {x:x}) {}"); }, SyntaxError, "Two formals as object patterns have duplicate binding identifiers is not valid syntax", "Let/Const redeclaration");
- assert.throws(function () { eval("function foo([x, x]) {}"); }, SyntaxError, "One formal as array pattern has duplicate binding identifiers is not valid syntax", "Let/Const redeclaration");
- assert.throws(function () { eval("function foo([x], [x]) {}"); }, SyntaxError, "Two formals as array patterns have duplicate binding identifiers is not valid syntax", "Let/Const redeclaration");
- assert.throws(function () { eval("function foo([x], {x:x}) {}"); }, SyntaxError, "Mixed array and object pattern with duplicate identifiers is not valid syntax", "Let/Const redeclaration");
- assert.throws(function () { eval("function foo([x], x) {}"); }, SyntaxError, "First formal as array pattern has matching name with the second formal is not valid syntax", "Duplicate formal parameter names not allowed in this context");
- assert.throws(function () { eval("function foo(x, [x]) {}"); }, SyntaxError, "First normal formal is matching with the second formal which is array pattern is not valid syntax", "Let/Const redeclaration");
- assert.throws(function () { eval("function foo({x:{z:[z1]}}, z1) {}"); }, SyntaxError, "First formal as nesting object pattern has matching name with the second formal is not valid syntax", "Duplicate formal parameter names not allowed in this context");
- assert.throws(function () { eval("function foo([x]) { let x = 10;}"); }, SyntaxError, "Object destructuring pattern as a formal is valid syntax", "Let/Const redeclaration");
- assert.doesNotThrow(function () { eval("function foo([x]) { var x = 10;}"); }, "var declared names matching with formal (as array pattern) is valid syntax");
- }
- },
- {
- name: "Destructuring on param - basic functionality",
- body : function () {
- function f1({x:x}) {
- return x;
- }
- let ret = f1({x:1});
- assert.areEqual(ret, 1, "Object pattern as a formal matches with actual param and initializes the identifier correctly");
- function f2([x]) {
- return x;
- }
- ret = f2([2]);
- assert.areEqual(ret, 2, "Array pattern as a formal matches with actual param and initializes the identifier correctly");
- function f3({x}, [y], z) {
- return x + y + z;
- }
- ret = f3({x:1}, [2], 3);
- assert.areEqual(ret, 6, "First formal as object pattern and second formal as array pattern should match and initialize identifiers correctly");
- let f4 = function ([x], {y:y}, z) {
- return x + y + z;
- }
- ret = f4([1], {y:2}, 3);
- assert.areEqual(ret, 6, "First formal as array pattern and second formal as object pattern should match and initialize identifiers correctly");
- }
- },
- {
- name: "Destructuring on param - initializer",
- body : function () {
- function f1({x:x1 = 11}, [x2 = 22]) {
- assert.areEqual(x1, 1, "Identifier from the first pattern has initializer but matches the actual first param and initializes correctly");
- assert.areEqual(x2, 2, "Identifier from the second pattern has initializer byt matches the actual second param and initializes correctly");
- }
- f1({x:1}, [2]);
- function f2({x:x1 = 11}, [x2 = 22]) {
- assert.areEqual(x1, 11, "Identifier from the first pattern gets undefined from the actual first param so initializes with initializer");
- assert.areEqual(x2, 22, "Identifier from the second pattern gets undefined from the actual second param so initializes with initializer");
- }
- f2({}, []);
- (function ({x:x1 = 11} = {x:111}, [x2 = 22] = [222]) {
- assert.areEqual(x1, 111, "First pattern matches with default as the actual first param is undefined");
- assert.areEqual(x2, 222, "Second pattern matches with default as the actual second param is undefined");
- })(undefined, undefined);
- }
- },
- {
- name: "Destructuring on param - functionality on lambda/function expression",
- body : function () {
- (function({x:x1}) {
- assert.areEqual(x1, 1, "Anonymous function - object pattern as a formal matches with actual param and initializes identifier correctly");
- })({x:1});
- let f1 = ([x1]) => x1 * 2;
- assert.areEqual(f1([2]), 4, "Lambda - array pattern as a formal matches with actual param and initializes identifier correctly");
- let f2 = ({x:x2}) => x2 * 4;
- assert.areEqual(f2({x:2}), 8, "Lambda - object pattern as a formal matches with actual param and initializes identifier correctly");
- let f3 = function foo({x:x1}) {
- assert.areEqual(x1, 1, "Named function expression - object pattern as a formal matches with actual param and initializes identifier correctly");
- }
- f3({x:1});
- let f4 = new Function("{x}", "[y]", "return x + y");
- assert.areEqual(f4({x:1}, [2]), 3, "Function constructor - patterns as formals match with actual params and initialize identifiers correctly");
- }
- },
- {
- name: "Destructuring on param - captures",
- body : function () {
- function f1({x:x1}) {
- function f1_1() {
- assert.areEqual(x1, 1, "Identifier from object pattern is captured and initialized correctly");
- }
- f1_1();
- }
- f1({x:1});
- function f2([x1]) {
- function f2_1() {
- assert.areEqual(x1, 2, "Identifier from array pattern is captured and initialized correctly");
- }
- f2_1();
- }
- f2([2]);
- function f3({x:x1}, [y1], z) {
- (function () {
- x1++;
- })();
- (function () {
- y1++;
- })();
- var k = x1 + y1 + z;
- assert.areEqual(k, 62, "Identifiers from patterns are captured and initialized correctly");
- }
- f3({x:10}, [20], 30);
- }
- },
- {
- name: "Destructuring on param - capture due to eval",
- body : function () {
- function f1({x:x1}, [x2]) {
- eval('');
- assert.areEqual(x1, 1, "Function has eval - identifier from the object pattern is initialized correctly");
- assert.areEqual(x2, 2, "Function has eval - identifier from the array pattern is initialized correctly under eval");
- }
- f1({x:1}, [2]);
- function f2({x:x1}, [x2]) {
- eval('');
- (function () {
- x1;
- x2;
- })();
- assert.areEqual(x1, 3, "Function has eval and inner function - identifier from the object pattern is initialized correctly");
- assert.areEqual(x2, 4, "Function has eval and inner function - identifier from the array pattern is initialized correctly");
- }
- f2({x:3}, [4]);
- function f3({x:x1}, [x2]) {
- (function () {
- eval('');
- assert.areEqual(x1, 5, "Function's inner function has eval - identifier from the object pattern is initialized correctly");
- assert.areEqual(x2, 6, "Function's inner function has eval - identifier from the object pattern is initialized correctly");
- })();
- }
- f3({x:5}, [6]);
- }
- },
- {
- name: "Destructuring on param - captures (eval and arguments)",
- body : function () {
- function f1({x:x1}, [x2]) {
- assert.areEqual(arguments[0], {x:1}, "arguments[0] is initialized correctly with first actual argument");
- assert.areEqual(arguments[1], [2], "arguments[1] is initialized correctly with second actual argument");
- }
- f1({x:1}, [2]);
- function f2({x:x1}, [x2]) {
- (function() {
- })();
- eval('');
- assert.areEqual(arguments[0], {x:1}, "Function has inner function and eval - arguments[0] is initialized correctly with first actual argument");
- assert.areEqual(arguments[1], [2], "Function has inner function and eval - arguments[1] is initialized correctly with second actual argument");
- }
- f2({x:1}, [2]);
- function f3({x:x1}, [x2]) {
- (function() {
- eval('');
- })();
- assert.areEqual(arguments[0], {x:1}, "Function's inner function has eval - arguments[0] is initialized correctly with first actual argument");
- assert.areEqual(arguments[1], [2], "Function's inner function has eval - arguments[1] is initialized correctly with second actual argument");
- }
- f3({x:1}, [2]);
- (function({x:x1}, x2) {
- x2 = 3;
- assert.areEqual(arguments[1], 2, "arguments object is unmapped - changing second formal does not change arguments[1]");
- })({x:1}, 2);
- (function ([x1], x2) {
- arguments[1] = 2;
- assert.areEqual(x2, 1, "arguments object is unmapped - changing arguments[1] does not change second param");
- })([], 1);
- (function ({x:x1}, x2) {
- x2 = 2;
- (function() {
- eval('');
- })();
- assert.areEqual(arguments[1], 1, "Function's inner function has eval - arguments object is unmapped - changing second formal does not change arguments[1]");
- })({}, 1);
- (function ([x1], x2) {
- (function() {
- eval('');
- })();
- arguments[1] = 2;
- assert.areEqual(x2, 1, "Function's inner function has eval - arguments object is unmapped - changing arguments[1] does not change second param");
- })([], 1);
- }
- },
- {
- name: "Destructuring on param - multiple/mixed/nested parameters",
- body : function () {
- (function (x1, {x2, x3}, [x4, x5], x6) {
- var k = x1 + x2 + x3 + x4 + x5 + x6;
- assert.areEqual(k, 21, "Identifiers under various patterns are matched and initialized correctly");
- })(1, {x2:2, x3:3}, [4, 5], 6);
- (function (x1, {x2, x3}, [x4, x5], x6) {
- var k = x1 + x2 + x3 + x4 + x5 + x6;
- eval('');
- assert.areEqual(k, 21, "Function has eval - identifiers under various patterns are matched and initialized correctly");
- })(1, {x2:2, x3:3}, [4, 5], 6);
- (function (x1, {x2, x3}, [x4, x5], x6) {
- var k = x1 + x2 + x3 + x4 + x5 + x6;
- (function() {
- eval('');
- });
- assert.areEqual(k, 21, "Function's inner function has eval - identifiers under various patterns are matched and initialized correctly");
- })(1, {x2:2, x3:3}, [4, 5], 6);
- }
- },
- {
- name: "Destructuring on param - misc",
- body : function () {
- let f1 = function foo(x0, {x:x1}, [x2]) {
- assert.areEqual(x1, 1, "Function expression with name - identifier from second formal is matched and initialized correctly");
- assert.areEqual(x2, 2, "Function expression with name - identifier from third formal is matched and initialized correctly");
- }
- f1(0, {x:1}, [2]);
- let f2 = function foo1(x0, {x:x1}, [x2]) {
- eval('');
- assert.areEqual(x1, 1, "Function expression with name has eval - identifier from second formal is matched and initialized correctly");
- assert.areEqual(x2, 2, "Function expression with name has eval - identifier from third formal is matched and initialized correctly");
- }
- f2(0, {x:1}, [2]);
- let f3 = function foo2(x0, {x:x1}, [x2]) {
- with(x1) {
- assert.areEqual(x1_1, 1, "Function expression with name has 'with' - identifier from second formal is matched and initialized correctly");
- assert.areEqual(x2, 2, "Function expression with name has 'with' - identifier from third formal is matched and initialized correctly");
- }
- }
- f3(0, {x:{x1_1:1}}, [2]);
- let f4 = function foo3(x0, {x:x1}, [x2]) {
- try {
- throw 'abc';
- }
- catch(e) {
- (function () {
- assert.areEqual(x1, 1, "Function expression with name has 'try/catch' - identifier from second formal is matched and initialized correctly");
- assert.areEqual(x2, 2, "Function expression with name has 'try/catch' - identifier from third formal is matched and initialized correctly");
- })();
- }
- }
- f4(0, {x:1}, [2]);
- let f5 = function foo4(x0, {x:x1}, [x2]) {
- try {
- throw 'abc';
- }
- catch(e) {
- (function () {
- eval('');
- assert.areEqual(x1, 1, "Function expression with name has 'try/catch and eval' - identifier from second formal is matched and initialized correctly");
- assert.areEqual(x2, 2, "Function expression with name has 'try/catch and eval' - identifier from third formal is matched and initialized correctly");
- })();
- }
- }
- f5(0, {x:1}, [2]);
- }
- },
- {
- name: "Destructuring on param - class",
- body : function () {
- class Foo {
- add([x1]) {
- this.x1 += x1;
- }
- set prop({x1}) {
- this.x1 = x1;
- }
- get prop() {
- return this.x1;
- }
- static Avg({x1}, [x2], x3) {
- return (x1+x2+x3)/3;
- }
- }
- assert.areEqual(Foo.Avg({x1:3}, [4], 5), 4, "Class's static function - identifiers from formal patterns are matched and initialized correctly");
- let obj = new Foo();
- obj.prop = {x1:1};
- assert.areEqual(obj.prop, 1, "Class's setter - identifier from the formal object pattern is matched and initialized correctly");
- obj.add([2]);
- assert.areEqual(obj.prop, 3, "Class's method - identifier from the formal array pattern is matched and initialized correctly");
- }
- }
- ];
- testRunner.runTests(tests, { verbose: WScript.Arguments[0] != "summary" });
|