| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353 |
- //-------------------------------------------------------------------------------------------------------
- // Copyright (C) Microsoft. All rights reserved.
- // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
- //-------------------------------------------------------------------------------------------------------
- // ES6 new.target tests
- WScript.LoadScriptFile("..\\UnitTestFramework\\UnitTestFramework.js");
- var tests = [
- {
- name: "Test new.target parsing path doesn't confuse 'new target'",
- body: function() {
- function target() { return { name: 'something' }; }
- var t = new target; // implicitly 'new target()'
- assert.areEqual('something', t.name, "new target() returned our new object instead of new.target");
- }
- },
- {
- name: "Test new.target in various block scopes'",
- body: function() {
- assert.doesNotThrow(function(){{new.target;}}, "new.target one level block do not throw in a function");
- assert.doesNotThrow(function(){{{new.target;}}}, "new.target two level block do not throw in a function");
- assert.doesNotThrow(function(){with({}) {new.target;}}, "new.target with scope body call does not throw");
- assert.doesNotThrow(function() { function parent(x) { new x();}; function child(){ with(new.target) {toString();}}; parent(child); }, "new.target with scope parameter does not throw");
- assert.doesNotThrow(function(){{if(true){new.target;}}}, "new.target condition block in nested block do not throw in a function");
- assert.doesNotThrow(function(){try { throw Error;} catch(e){new.target;}}, "new.target catch block do not throw in a function");
- assert.doesNotThrow(function(){ var a = b = c = 1; try {} catch([a,b,c]) { new.target;}}, "new.target in CatchParamPattern block do not throw in a function");
- assert.doesNotThrow(function(){ var x = function() {new.target;}; x();}, "new.target in function expression do not throw in a function");
- assert.doesNotThrow(function(){ var o = { "foo" : function () { new.target}}; o.foo();}, "new.target in named function expression do not throw in a function");
- }
- },
- {
- name: "Test new.target parsing path with badly-formed meta-property references",
- body: function() {
- assert.throws(function() { return new['target']; }, TypeError, "Meta-property new.target is not a real property lookup", "Object doesn't support this action");
- assert.throws(function() { return eval('new.'); }, SyntaxError, "Something like 'new.' should fall out of the meta-property parser path", "'new.' is only valid if followed by 'target'");
- assert.throws(function() { return eval('new.target2'); }, SyntaxError, "No other keywords should produce meta-properties", "'new.' is only valid if followed by 'target'");
- assert.throws(function() { return eval('new.something'); }, SyntaxError, "No other keywords should produce meta-properties", "'new.' is only valid if followed by 'target'");
- assert.throws(function() { return eval('new.eval'); }, SyntaxError, "No other keywords should produce meta-properties", "'new.' is only valid if followed by 'target'");
- }
- },
- {
- name: "There is now a well-known PID for 'target' - ensure it doesn't break",
- body: function() {
- var obj = { target: 'something' };
- assert.areEqual('something', obj.target, "The name 'target' can be used as an identifier");
- }
- },
- {
- name: "new.target is not valid for assignment",
- body: function() {
- assert.throws(function() { eval("new.target = 'something';"); }, ReferenceError, "new.target cannot be a lhs in an assignment expression - this is an early reference error", "Invalid left-hand side in assignment");
- assert.throws(function() { eval("((new.target)) = 'something';"); }, ReferenceError, "new.target cannot be a lhs in an assignment expression - this is an early reference error", "Invalid left-hand side in assignment");
- }
- },
- {
- name: "Simple base class gets new.target correctly",
- body: function() {
- var called = false;
- class SimpleBaseClass {
- constructor() {
- assert.isTrue(new.target === SimpleBaseClass, "new.target === SimpleBaseClass");
- called = true;
- }
- }
- var myObj = new SimpleBaseClass();
- assert.isTrue(called, "The constructor was called.");
- }
- },
- {
- name: "Simple derived and base class passes new.target correctly",
- body: function() {
- var called = false;
- class BaseClassForB {
- constructor() {
- assert.isTrue(new.target === DerivedClassForB, "new.target === DerivedClassForB");
- called = true;
- }
- }
- class DerivedClassForB extends BaseClassForB {
- constructor() {
- assert.isTrue(new.target === DerivedClassForB, "new.target === DerivedClassForB");
- super();
- }
- }
- var myB = new DerivedClassForB();
- assert.isTrue(called, "The super-chain was called.");
- }
- },
- {
- name: "Simple base class with arrow function using new.target correctly",
- body: function() {
- var called = false;
- class SimpleBaseClass {
- constructor() {
- var arrow = () => {
- assert.isTrue(new.target === SimpleBaseClass, "new.target === SimpleBaseClass");
- called = true;
- }
- arrow();
- }
- }
- var myObj = new SimpleBaseClass();
- assert.isTrue(called, "The constructor was called.");
- }
- },
- {
- name: "new.target behavior in arrow function inside derived class",
- body: function() {
- let constructed = false;
- class C {
- constructor() {
- let arrow = () => {
- assert.isTrue(D === new.target, "Class constructor implicitly invoked via super call has new.target set to derived constructor (also in arrow)");
- constructed = true;
- };
- arrow();
- }
- }
- class D extends C {
- constructor() {
- let arrow = () => {
- assert.isTrue(D === new.target, "Class constructor explicitly invoked via new keyword has new.target set to that constructor (also in arrow)");
- };
- arrow();
- super();
- }
- }
- let myD = new D();
- assert.isTrue(constructed, "We actually ran the constructor code");
- }
- },
- {
- name: "new.target behavior in a normal function",
- body: function() {
- function foo() {
- assert.isTrue(undefined === new.target, "Normal function call has new.target set to undefined in the function body");
- return new.target;
- }
- assert.isTrue(undefined === foo(), "Normal function returning new.target returns undefined");
- }
- },
- {
- name: "new.target behavior in a normal function in a new expression",
- body: function() {
- function foo() {
- assert.isTrue(foo === new.target, "Function called as new expression has new.target set to the function in the function body");
- return new.target;
- }
- assert.isTrue(foo === new foo(), "Function called-as-constructor has new.target set to that function");
- }
- },
- {
- name: "new.target behavior in an arrow in a normal function",
- body: function() {
- function foo() {
- let arrow = () => {
- assert.isTrue(undefined === new.target, "Normal function call has new.target set to undefined in the function body");
- return new.target;
- };
- return arrow();
- }
- assert.isTrue(undefined === foo(), "Normal function returning new.target returns undefined");
- }
- },
- {
- name: "new.target behaviour in an arrow in a normal function in a new expression",
- body: function() {
- function foo() {
- let arrow = () => {
- assert.isTrue(foo === new.target, "Function called as new expression has new.target set to the function in the function body");
- return new.target;
- };
- return arrow();
- }
- assert.isTrue(foo === new foo(), "Function called-as-constructor has new.target set to that function");
- }
- },
- {
- name: "new.target captured from class constructor via arrow",
- body: function() {
- class base {
- constructor() {
- let arrow = () => {
- assert.isTrue(derived === new.target, "Function called as new expression has new.target set to the function in the function body");
- return new.target;
- };
- return arrow;
- }
- }
- class derived extends base {
- constructor() {
- return super();
- }
- }
- let arrow = new derived();
- assert.isTrue(derived === arrow(), "Arrow capturing new.target returns correct value");
- }
- },
- {
- name: "new.target inline constructor case",
- body: function() {
- function foo()
- {
- return new.target;
- }
- function bar()
- {
- return new foo(); //foo will be inlined here
- }
- assert.isTrue(bar() == foo, "Function called as new expression has new.target set to the function in the function body when the constructor is inlined");
- }
- },
- {
- name: "new.target inline case",
- body: function() {
- function foo()
- {
- return new.target;
- }
- function bar()
- {
- return foo(); //foo will be inlined here
- }
- assert.isTrue(bar() == undefined, "Normal inlined function has new.target set to undefined in the function body");
- }
- },
- {
- name: "new.target generator case",
- body: function() {
- function *foo()
- {
- yield new.target;
- }
- assert.isTrue((foo()).next().value == undefined, "Generator function has new.target set to undefined in the function body");
- }
- },
- {
- name: "new.target inside eval() in function",
- body: function() {
- function func() {
- var g = ()=>eval('new.target;');
- return g();
- }
- assert.areEqual(undefined, func(), "plain function call");
- assert.areEqual(undefined, eval("func()"), "function call inside eval");
- assert.areEqual(undefined, eval("eval('func()')"), "function call inside nested evals");
- assert.areEqual(undefined, (()=>func())(), "function call inside arrow function");
- assert.areEqual(undefined, (()=>(()=>func())())(), "function call inside nested arrow functions");
- assert.areEqual(undefined, eval("(()=>func())()"), "function call inside arrow function inside eval");
- assert.areEqual(undefined, (()=>eval("func()"))(), "function call inside eval inside arrow function");
- assert.areEqual(undefined, eval("(()=>eval('func()'))()"), "function call inside eval inside arrow function inside eval");
- assert.areEqual(func, new func(), "plain constructor call");
- assert.areEqual(func, eval("new func()"), "constructor call inside eval");
- assert.areEqual(func, eval("eval('new func()')"), "constructor call inside nested evals");
- assert.areEqual(func, (()=>new func())(), "constructor call inside arrow function");
- assert.areEqual(func, (()=>(()=>new func())())(), "constructor call inside nested arrow functions");
- assert.areEqual(func, eval("(()=>new func())()"), "constructor call inside arrow function inside eval");
- assert.areEqual(func, (()=>eval("new func()"))(), "constructor call inside eval inside arrow function");
- assert.areEqual(func, eval("(()=>eval('new func()'))()"), "constructor call inside eval inside arrow function inside eval");
- }
- },
- {
- name: "new.target inside netsted eval, arrow function, and function defintion through eval",
- body: function() {
- eval("function func() {var f = ()=>{function g() {}; return eval('new.target')}; return f(); }" );
- assert.areEqual(undefined, func(), "plain function call");
- assert.areEqual(undefined, eval("func()"), "function call inside eval");
- assert.areEqual(undefined, eval("eval('func()')"), "function call inside nested evals");
- assert.areEqual(undefined, (()=>func())(), "function call inside arrow function");
- assert.areEqual(undefined, (()=>(()=>func())())(), "function call inside nested arrow functions");
- assert.areEqual(undefined, eval("(()=>func())()"), "function call inside arrow function inside eval");
- assert.areEqual(undefined, (()=>eval("func()"))(), "function call inside eval inside arrow function");
- assert.areEqual(undefined, eval("(()=>eval('func()'))()"), "function call inside eval inside arrow function inside eval");
- assert.areEqual(func, new func(), "plain constructor call");
- assert.areEqual(func, eval("new func()"), "constructor call inside eval");
- assert.areEqual(func, eval("eval('new func()')"), "constructor call inside nested evals");
- assert.areEqual(func, (()=>new func())(), "constructor call inside arrow function");
- assert.areEqual(func, (()=>(()=>new func())())(), "constructor call inside nested arrow functions");
- assert.areEqual(func, eval("(()=>new func())()"), "constructor call inside arrow function inside eval");
- assert.areEqual(func, (()=>eval("new func()"))(), "constructor call inside eval inside arrow function");
- assert.areEqual(func, eval("(()=>eval('new func()'))()"), "constructor call inside eval inside arrow function inside eval");
- }
- },
- {
- name: "direct and indirect eval with new.target",
- body: function() {
- function scriptThrows(func, errType, info, errMsg) {
- try {
- func();
- throw Error("No exception thrown");
- } catch (err) {
- assert.areEqual(errType.name + ':' + errMsg, err.name + ':' + err.message, info);
- }
- }
- scriptThrows(()=>{ WScript.LoadScript("eval('new.target')", "samethread"); }, SyntaxError, "direct eval in global function", "Invalid use of the 'new.target' keyword");
- scriptThrows(()=>{ WScript.LoadScript("(()=>eval('new.target'))();", "samethread"); }, SyntaxError, "direct eval in lambda in global function", "Invalid use of the 'new.target' keyword");
- scriptThrows(()=>{ WScript.LoadScript("var f=()=>eval('new.target'); (function() { return f(); })();", "samethread"); }, SyntaxError, "direct eval in lambda in global function called by a function", "Invalid use of the 'new.target' keyword");
- assert.doesNotThrow(()=>{ WScript.LoadScript("(function() { eval('new.target;') })()", "samethread"); }, "direct eval in function");
- assert.doesNotThrow(()=>{ WScript.LoadScript("var f =(function() { return ()=>eval('new.target;') })(); f();", "samethread"); }, "direct eval in lambda defined in function and called by global function");
- scriptThrows(()=>{ WScript.LoadScript("(0, eval)('new.target;')", "samethread"); }, SyntaxError, "indirect eval in global function", "Invalid use of the 'new.target' keyword");
- scriptThrows(()=>{ WScript.LoadScript("(()=>(0, eval)('new.target'))();", "samethread"); }, SyntaxError, "indirect eval in lambda in global function", "Invalid use of the 'new.target' keyword");
- scriptThrows(()=>{ WScript.LoadScript("var f=()=>(0, eval)('new.target'); (function() { return f(); })();", "samethread"); }, SyntaxError, "indirect eval in lambda in global function called by a function", "Invalid use of the 'new.target' keyword");
- scriptThrows(()=>{ WScript.LoadScript("(function() { (0, eval)('new.target;') })()", "samethread")}, SyntaxError, "indirect eval in function", "Invalid use of the 'new.target' keyword");
- scriptThrows(()=>{ WScript.LoadScript("var f =(function() { return ()=>(0, eval)('new.target;') })(); f();", "samethread"); }, SyntaxError, "indirect eval in lambda defined in function and called by global function", "Invalid use of the 'new.target' keyword");
- }
- },
- ];
- testRunner.runTests(tests, { verbose: WScript.Arguments[0] != "summary" });
|