blob: 4406755de11174850bc1461fb3fe27e9e8667356 [file] [log] [blame]
//-------------------------------------------------------------------------------------------------------
// 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 catch param",
body: function () {
assert.doesNotThrow(function () { eval("try {} catch({}) {}"); }, "Object destructuring pattern (empty) as a catch param is valid syntax");
assert.doesNotThrow(function () { eval("try {} catch([]) {}"); }, "Array destructuring pattern (empty) as a catch param is valid syntax");
assert.doesNotThrow(function () { eval("try {} catch({x:x}) {}"); }, "Object destructuring pattern as a catch param is valid syntax");
assert.doesNotThrow(function () { eval("try {} catch([e]) {}"); }, "Object destructuring pattern as a catch param is valid syntax");
assert.doesNotThrow(function () { eval("try {} catch({x}) {}"); }, "Object destructuring pattern (as short-hand) as a catch param is valid syntax");
assert.doesNotThrow(function () { eval("function foo() {try {} catch({x, y:[y]}) {} }"); }, "Object destructuring pattern as a catch param inside a function is valid syntax");
assert.doesNotThrow(function () { eval("function foo() {try {} catch([x, {y:[y]}]) {} }"); }, "Object destructuring pattern as a catch param inside a function is valid syntax");
}
},
{
name: "Destructuring syntax as catch param - invalid syntax",
body: function () {
assert.throws(function () { eval("function foo() {try {} catch({,}) {} }"); }, SyntaxError, "Object destructuring pattern as a catch param with empty names is not valid syntax", "Expected identifier, string or number");
assert.throws(function () { eval("function foo() {try {} catch(([])) {} }"); }, SyntaxError, "Object destructuring pattern as a catch param with empty names is not valid syntax", "Expected identifier");
assert.throws(function () { eval("function foo() {try {} catch({x:abc+1}) {} }"); }, SyntaxError, "Object destructuring pattern as a catch param with operator is not valid syntax", "Unexpected operator in destructuring expression");
assert.throws(function () { eval("function foo() {try {} catch([abc.d]) {} }"); }, SyntaxError, "Array destructuring pattern as a catch param with property reference is not valid syntax", "Syntax error");
assert.throws(function () { eval("function foo() {try {} catch([x], [y]) {} }"); }, SyntaxError, "More than one patterns/identifiers as catch params is not valid syntax", "Expected ')'");
assert.throws(function () { eval("function foo() {'use strict'; try {} catch([arguments]) {} }"); }, SyntaxError, "StrictMode - identifier under pattern named as 'arguments' is not valid syntax", "Invalid usage of 'arguments' in strict mode");
assert.throws(function () { eval("function foo() {'use strict'; try {} catch([eval]) {} }"); }, SyntaxError, "StrictMode - identifier under pattern named as 'eval' is not valid syntax", "Invalid usage of 'eval' in strict mode");
}
},
{
name: "Destructuring syntax as params - Initializer",
body: function () {
assert.doesNotThrow(function () { eval("function foo() {try {} catch({x:x = 20}) {} }"); }, "Catch param as object destructuring pattern with initializer is valid syntax");
assert.doesNotThrow(function () { eval("function foo() {try {} catch([x = 20]) {} }"); }, "Catch param as array destructuring pattern with initializer is valid syntax");
assert.doesNotThrow(function () { eval("function foo() {try {} catch({x1:x1 = 1, x2:x2 = 2, x3:x3 = 3}) {} }"); }, "Catch param as object destructuring pattern has three names with initializer is valid syntax");
assert.doesNotThrow(function () { eval("function foo() {try {} catch([x1 = 1, x2 = 2, x3 = 3]) {} }"); }, "Catch param as array destructuring pattern has three names with initializer is valid syntax");
assert.throws(function () { eval("function foo() {try {} catch({x:x} = {x:1}) {} }"); }, SyntaxError, "Catch param as pattern with default is not valid syntax", "Destructuring declarations cannot have an initializer");
}
},
{
name: "Destructuring syntax as params - redeclarations",
body: function () {
assert.throws(function () { eval("function foo() {try {} catch({x:x, x:x}) {} }"); }, SyntaxError, "Catch param as object pattern has duplicate binding identifiers is not valid syntax", "Let/Const redeclaration");
assert.throws(function () { eval("function foo() {try {} catch([x, x]) {} }"); }, SyntaxError, "Catch param as array pattern has duplicate binding identifiers is not valid syntax", "Let/Const redeclaration");
assert.throws(function () { eval("function foo() {try {} catch({z1, x:{z:[z1]}}) {} }"); }, SyntaxError, "Catch param has nesting pattern has has matching is not valid syntax", "Let/Const redeclaration");
assert.throws(function () { eval("function foo() {try {} catch([x]) { let x = 10;} }"); }, SyntaxError, "Catch param as a pattern and matching name with let/const variable in body is not valid syntax", "Let/Const redeclaration");
assert.throws(function () { eval("function foo() {try {} catch([x]) { function x() {} } }"); }, SyntaxError, "Catch param as a pattern and matching name with function name in body is not valid syntax", "Let/Const redeclaration");
assert.doesNotThrow(function () { eval("function foo() {try {} catch([x]) { var x = 10;} }"); }, "Catch param as a pattern and matching name with var declared name in body is valid syntax");
(function () {
try {
} catch ({x}) {
var x = 1;
}
assert.areEqual(x, undefined, "Assignment inside the catch block should assign the value to the catch param not the body var");
})();
(function () {
let y = 1;
try {
throw { y : 10 };
} catch ({y}) {
assert.areEqual(y, 10, "Catch block refers to the destructured param");
}
assert.areEqual(y, 1, "Function body refers to the let variable");
})();
(function () {
let x = 1;
try {
throw [{ x : 10 }];
} catch ([{
x
}]) {
assert.areEqual(x, 10, "Catch block with nested destructured param");
}
assert.areEqual(x, 1, "Let declaration in the function body is not affected by the destructured params");
})();
}
},
{
name: "Destructuring on catch param - basic functionality",
body: function () {
try {
throw [1];
}
catch ([e1]) {
assert.areEqual(e1, 1, "Array pattern as a catch param matches with actual exception and initializes the identifier correctly");
}
try {
throw {e2:2};
}
catch({e2}) {
assert.areEqual(e2, 2, "Object pattern as a catch param matches with actual exception and initializes the identifier correctly");
}
try {
throw [3, {e4:[4]}];
}
catch([e3, {e4:[e4]}]) {
assert.areEqual(e3, 3, "First identifier in catch param as pattern is matched and initialized correctly");
assert.areEqual(e4, 4, "Second identifier in catch param as pattern is matched and initialized correctly");
}
}
},
{
name: "Destructuring on catch param - initializer",
body: function () {
try {
throw [];
}
catch ([e1 = 11]) {
assert.areEqual(e1, 11, "Array pattern as a catch param has initializer and initializes with initializer value");
}
try {
throw {};
}
catch({e2:e2 = 22}) {
assert.areEqual(e2, 22, "Object pattern as a catch param has initializer and initializes with initializer value");
}
try {
throw [, {e4:[]}];
}
catch([e3 = 11, {e4:[e4 = 22]} = {e4:[]}]) {
assert.areEqual(e3, 11, "First identifier in catch params as a pattern is initialized with initializer value");
assert.areEqual(e4, 22, "Second identifier in catch params as a pattern is initialized with initializer value");
}
}
},
{
name: "Destructuring on catch param - captures",
body : function () {
(function () {
try {
throw {x1:'x1', x2:'x2', x3:'x3'};
}
catch ({x1, x2, x3}) {
(function () {
x1;x2;x3;
})();
let m = x1+x2+x3;
assert.areEqual(m, 'x1x2x3', "Inner Function - capturing all identifiers from object pattern in inner function is working correctly");
}
})();
(function () {
try {
throw ['y1', 'y2', 'y3'];
}
catch ([x1, x2, x3]) {
(function () {
x1;x2;x3;
})();
let m = x1+x2+x3;
assert.areEqual(m, 'y1y2y3', "Inner Function - capturing all identifiers from array pattern in inner function is working correctly");
}
})();
(function () {
try {
throw ['y1', 'y2', 'y3'];
}
catch ([x1, x2, x3]) {
(function () {
x2;
})();
let m = x1+x2+x3;
assert.areEqual(m, 'y1y2y3', "Inner Function - capturing only one identifier from pattern in inner function is working correctly");
}
})();
(function () {
try {
throw ['y1', 'y2', 'y3'];
}
catch ([x1, x2, x3]) {
eval('');
let m = x1+x2+x3;
assert.areEqual(m, 'y1y2y3', "Has eval - identifiers from catch params are initialized correctly");
}
})();
(function () {
try {
throw ['y1', 'y2', 'y3'];
}
catch ([x1, x2, x3]) {
(function () {
x1;x2;x3;
})();
eval('');
let m = x1+x2+x3;
assert.areEqual(m, 'y1y2y3', "Has eval and inner function - identifiers from catch params are initialized correctly");
}
})();
(function () {
try {
throw ['y1', 'y2', 'y3'];
}
catch ([x1, x2, x3]) {
(function () {
eval('');
x1;x2;x3;
})();
let m = x1+x2+x3;
assert.areEqual(m, 'y1y2y3', "Inner function has eval - identifiers from catch params are initialized correctly");
}
})();
}
},
{
name: "Function definitions in catch's parameter",
body: function () {
(function() {
try {
var c = 10;
throw ['inside'];
} catch ([x, y = function() { return c; }]) {
assert.areEqual(y(), 10, "Function should be able to capture symbols from try's body properly");
assert.areEqual(x, 'inside', "Function should be able to capture symbols from try's body properly");
}
})();
(function() {
try {
throw [];
} catch ([x = 10, y = function() { return x; }]) {
assert.areEqual(y(), 10, "Function should be able to capture symbols from catch's param");
}
})();
(function() {
try {
throw [];
} catch ([x = 10, y = function() { return x; }]) {
eval("");
assert.areEqual(y(), 10, "Function should be able to capture symbols from catch's param");
}
})();
(function() {
try {
throw {};
} catch ({x = 10, y = function() { return x; }}) {
assert.areEqual(y(), 10, "Function should be able to capture symbols from catch's param");
}
})();
(function() {
try {
throw ['inside', {}];
} catch ([x = 10, { y = function() { return x; } }]) {
eval("");
assert.areEqual(y(), 'inside', "Function should be able to capture symbols from catch's param");
}
})();
(function() {
try {
throw ['inside', {}];
} catch ([x, { y = () => arguments[0] }]) {
assert.areEqual(y(), 10, "Function should be able to capture the arguments symbol from the parent function");
assert.areEqual(x, 'inside', "Function should be able to capture symbols from try's body properly");
}
})(10);
(function(a = 1, b = () => a) {
try {
throw [];
} catch ([x = 10, y = function() { return b; }]) {
assert.areEqual(y()(), 1, "Function should be able to capture formals from a split scoped function");
}
})();
(function () {
var z = 100;
(function() {
try {
throw [];
} catch ([x = 10, y = () => x + z]) {
assert.areEqual(y(), 110, "Function should be able to capture symbols from outer functions");
}
})();
})();
(function () {
var z = 100;
(function() {
try {
throw [];
} catch ([x = z = 10, y = () => x]) {
assert.areEqual(y(), 10, "Function should be able to capture symbols from outer functions");
assert.areEqual(z, 10, "Variable from the outer function is updated during the param initialization");
}
})();
})();
(function () {
var a = 100;
(function() {
var b = 200;
try {
throw [];
} catch ([x = () => y, y = 10, z = () => a]) {
c = () => x() + z() + b;
assert.areEqual(c(), 310, "Variable from all three levels are accessible");
}
})();
})();
(function () {
var a = 100;
(function() {
var b = 200;
try {
throw [];
} catch ([x = () => y, y = 10, z = () => a]) {
c = () => x() + z() + b;
assert.areEqual(c(), 310, "Variable from all three levels are accessible with eval in catch's body");
eval("");
}
})();
})();
(function () {
try {
var c = 10;
throw [ ];
} catch ([x = 1, y = function() { eval(""); return c + x; }]) {
assert.areEqual(y(), 11, "Function should be able to capture symbols from outer functions even with eval in the body");
}
})();
(function () {
try {
eval("");
var c = 10;
throw [ ];
} catch ([x = 1, y = function() { return c + x; }]) {
assert.areEqual(y(), 11, "Function should be able to capture symbols from outer functions even with eval in the try block");
}
})();
(function () {
try {
var c = 10;
throw {x : 'inside', y: []};
} catch ({x, y: [y = function(a = 10, b = () => a) { return b; }]}) {
assert.areEqual(y()(), 10, "Function should be able to capture symbols from outer functions even if it has split scope");
}
})();
(function () {
var f = function foo(a) {
try {
if (!a) {
return foo(1);
}
var c = 10;
throw [ ];
} catch ([y = function() { return c + a; }]) {
assert.areEqual(y(), 11, "Function should be able to capture symbols from outer functions when inside a named function expression");
}
};
f();
})();
}
}
];
testRunner.runTests(tests, { verbose: WScript.Arguments[0] != "summary" });