| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692 |
- //-------------------------------------------------------------------------------------------------------
- // Copyright (C) Microsoft Corporation and contributors. All rights reserved.
- // Copyright (c) 2021 ChakraCore Project Contributors. 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: "Check if Symbol.unscopables is defined",
- body: function ()
- {
- assert.isTrue(Array.prototype.hasOwnProperty(Symbol.unscopables), "Array should have Array.prototype[@@unscopables] property");
- }
- },
- {
- name: "Check if all excepted properties exist in Array.prototype[@@unscopables] and have corresponding values",
- body: function ()
- {
-
- const unscopables = Array.prototype[Symbol.unscopables];
- const list = ["at", "copyWithin", "entries", "fill", "find", "findIndex", "flat", "flatMap", "includes", "keys", "values"];
- const length = list.length;
- for (let index = 0; index < length; index++)
- {
- const propName = list[index];
- assert.areEqual(unscopables[propName], true, `Array.prototype[@@unscopables].${ propName } should equal true`);
- }
- }
- },
- {
- name: "Global scope test on Arrays",
- body: function ()
- {
- var globalScope = -1;
- var at = globalScope;
- var find = globalScope;
- var findIndex = globalScope;
- var fill = globalScope;
- var copyWithin = globalScope;
- var entries = globalScope;
- var includes = globalScope;
- var keys = globalScope;
- var values = globalScope;
- var flat = globalScope;
- var flatMap = globalScope;
- with([])
- {
- assert.areEqual(globalScope, at, "at property is not brought into scope by the with statement");
- assert.areEqual(globalScope, find, "find property is not brought into scope by the with statement");
- assert.areEqual(globalScope, findIndex, "findIndex property is not brought into scope by the with statement");
- assert.areEqual(globalScope, fill, "fill property is not brought into scope by the with statement");
- assert.areEqual(globalScope, copyWithin, "copyWithin property is not brought into scope by the with statement");
- assert.areEqual(globalScope, entries, "entries property is not brought into scope by the with statement");
- assert.areEqual(globalScope, includes, "includes property is not brought into scope by the with statement");
- assert.areEqual(globalScope, keys, "keys property is not brought into scope by the with statement");
- assert.areEqual(globalScope, values, "values property is not brought into scope by the with statement");
- assert.areEqual(globalScope, flat, "flat property is not brought into scope by the with statement");
- assert.areEqual(globalScope, flatMap, "flatMap property is not brought into scope by the with statement");
- }
- }
- },
- {
- name: "Add to Array.prototype[@@unscopables]",
- body: function ()
- {
- var globalScope = -1;
- var at = globalScope;
- var find = globalScope;
- var findIndex = globalScope;
- var fill = globalScope;
- var copyWithin = globalScope;
- var entries = globalScope;
- var includes = globalScope;
- var keys = globalScope;
- var values = globalScope;
- var slice = globalScope;
- var flat = globalScope;
- var flatMap = globalScope;
- var a = [];
- a[Symbol.unscopables]["slice"] = true;
- with(a)
- {
- assert.areEqual(globalScope, at, "at property is not brought into scope by the with statement");
- assert.areEqual(globalScope, find, "find property is not brought into scope by the with statement");
- assert.areEqual(globalScope, findIndex, "findIndex property is not brought into scope by the with statement");
- assert.areEqual(globalScope, fill, "fill property is not brought into scope by the with statement");
- assert.areEqual(globalScope, copyWithin, "copyWithin property is not brought into scope by the with statement");
- assert.areEqual(globalScope, entries, "entries property is not brought into scope by the with statement");
- assert.areEqual(globalScope, includes, "includes property is not brought into scope by the with statement");
- assert.areEqual(globalScope, keys, "keys property is not brought into scope by the with statement");
- assert.areEqual(globalScope, values, "values property is not brought into scope by the with statement");
- assert.areEqual(globalScope, slice, "slice property is not brought into scope by the with statement");
- assert.areEqual(globalScope, flat, "flat property is not brought into scope by the with statement");
- assert.areEqual(globalScope, flatMap, "flatMap property is not brought into scope by the with statement");
- }
- }
- },
- {
- name: "Overwrite @@unscopables",
- body: function ()
- {
- var globalScope = -1;
- var c =
- {
- find : function () {},
- slice: function () {},
- [Symbol.unscopables]: {find : true }
- };
- var find = globalScope;
- var slice = globalScope;
- with(c)
- {
- assert.isTrue(globalScope != slice, "slice should be on Array scope");
- assert.areEqual(globalScope, find, "find should not be on Array scope");
- }
- var props = {"slice" : true};
- c[Symbol.unscopables] = props;
- with(c)
- {
- assert.isTrue(globalScope != find, "find should be on Array scope");
- assert.areEqual(globalScope, slice, "slice should not be on Array scope");
- }
- }
- },
- {
- name: "Adding to @@unscopables in a with statement",
- body: function ()
- {
- var globalScope = -1;
- var find = globalScope;
- var slice = globalScope;
- var c =
- {
- find : function () {},
- slice: function () {},
- [Symbol.unscopables]: {"find" : true}
- };
- with(c)
- {
- assert.areEqual(globalScope, find, "find property is not brought into scope by the with statement");
- c[Symbol.unscopables]["slice"] = true;
- assert.areEqual(globalScope, slice, "slice property is not brought into scope by the with statement");
- }
- }
- },
- {
- name: "Make sure we did not break with Scope",
- body: function ()
- {
- var b =1;
- var c =
- {
- get : function ()
- {
- return 4;
- },
- valueOf: function ()
- {
- WScript.Echo("valueOf");
- return {}; // not a primitive
- },
- toString: function ()
- {
- WScript.Echo("toString");
- return {}; // not a primitive
- }
- }
- with ({a: 1 , e: { l : 1, w:2}})
- {
- function f()
- {
- a = 2; //Set test
- b = a; //Get test
- }
- f();
- assert.areEqual(3, Object.keys(c).length, "There are three properties on c");
- assert.areEqual(2, Object.keys(e).length, "There are two properties on e");
- delete e;
- assert.throws(function() {e.l}, ReferenceError, "e should no longer exist");
- assert.areEqual(2, a, "a should be 2");
- assert.areEqual(2, b, "b should be 2");
- }
- with(c)
- {
- assert.areEqual(4, get(), "get is "+get()+" c.get() should be 4");
- }
- }
- },
- {
- name: "Make sure we do not expose the with Object",
- body: function ()
- {
- var o = {f: function(){ return this; }, x : 2, [Symbol.unscopables]: {"x" : true}};
- var x = -1;
- var testValue = o.f();
- with (o)
- {
- eval("var b = f();");
- assert.areEqual(testValue, b, "This should be handled by the ScopedLdInst unwrapping, which should mean testValue and b are equivalent");
- var a = f();
- // if this is broken We will get an Assert in the WithScopeObject on chk builds before the areEqual call but I'll leave this for fre builds
- assert.areEqual(testValue, a, "This test checks testValue and a are equivalent");
- assert.areEqual(-1, x, "x is not brought into scope by the with statement");
- assert.areEqual(o.x, b.x, "x is not brought into scope by the with statement");
- assert.areEqual(o.x, a.x, "x is not brought into scope by the with statement");
- }
- }
- },
- {
- name: "Lambda expressions",
- body: function ()
- {
- var adder = function (x)
- {
- return function (y)
- {
- return x + y;
- };
- };
- var find = -1;
- var findArray = [].find;
- with([])
- {
- find = adder(5);
- assert.areEqual(6, find(1), "This should equal 6");
- }
- assert.isTrue(-1 != find, "This should now be equal to a lambda");
- find = findArray;
- }
- },
- {
- name: "Operator precedence test",
- body: function ()
- {
- var obj = { a : 1 };
- var a = false;
- with(obj)
- {
- obj[Symbol.unscopables] = {};
- a = obj[Symbol.unscopables]["a"] = true;
- }
- assert.areEqual(1, obj.a, " should still be 1");
- assert.areEqual(true, a, "a.root should be set to true RHS evaluated before assignment");
- }
- },
- {
- name: "Nested functions in with",
- body: function ()
- {
- var globalScope = -1;
- var at = globalScope;
- var find = globalScope;
- var findIndex = globalScope;
- var fill = globalScope;
- var copyWithin = globalScope;
- var entries = globalScope;
- var includes = globalScope;
- var keys = globalScope;
- var values = globalScope;
- var flat = globalScope;
- var flatMap = globalScope;
- with([])
- {
- function foo()
- {
- function bar()
- {
- function f00()
- {
- function bat()
- {
- assert.areEqual(globalScope, at, "at property is not brought into scope by the with statement");
- assert.areEqual(globalScope, find, "find property is not brought into scope by the with statement");
- assert.areEqual(globalScope, findIndex, "findIndex property is not brought into scope by the with statement");
- assert.areEqual(globalScope, fill, "fill property is not brought into scope by the with statement");
- assert.areEqual(globalScope, copyWithin, "copyWithin property is not brought into scope by the with statement");
- assert.areEqual(globalScope, entries, "entries property is not brought into scope by the with statement");
- assert.areEqual(globalScope, includes, "includes property is not brought into scope by the with statement");
- assert.areEqual(globalScope, keys, "keys property is not brought into scope by the with statement");
- assert.areEqual(globalScope, values, "values property is not brought into scope by the with statement");
- assert.areEqual(globalScope, flat, "flat property is not brought into scope by the with statement");
- assert.areEqual(globalScope, flatMap, "flatMap property is not brought into scope by the with statement");
- }
- }
- }
- }
- }
- }
- },
- {
- name: "Nested with statements",
- body: function ()
- {
- var str =
- {
- search: function () {},
- split: function () {},
- concat: function () {},
- reduce: function () {},
- [Symbol.unscopables]: {"search" : true, "split": true, "concat" : true, "reduce" : true}
- };
- var arr =
- {
- find: function () {},
- keys: function () {},
- concat: function () {},
- reduce: function () {},
- [Symbol.unscopables]: {"find" : true, "keys" : true}
- };
- var globalScope = -1;
- var find = globalScope;
- var keys = globalScope;
- var search = globalScope;
- var split = globalScope;
- var reduce = globalScope;
- var concat = globalScope;
- var arrConcat = arr.concat;
- var arrReduce = arr.reduce;
- with(arr)
- {
- with(str)
- {
- assert.areEqual(globalScope, search, "search property is not brought into scope by the with statement");
- assert.areEqual(globalScope, split, "split property is not brought into scope by the with statement");
- assert.areEqual(arrConcat, concat, "concat should be on the array scope");
- assert.areEqual(arrReduce, reduce, "toString should be on the array scope");
- assert.areEqual(globalScope, find, "find property is not brought into scope by the with statement");
- assert.areEqual(globalScope, keys, "keys property is not brought into scope by the with statement");
- }
- }
- arr[Symbol.unscopables]["concat"] = true;
- arr[Symbol.unscopables]["reduce"] = true;
- with(arr)
- {
- with(str)
- {
- assert.areEqual(globalScope, search, "search property is not brought into scope by the with statement");
- assert.areEqual(globalScope, split, "split property is not brought into scope by the with statement");
- assert.areEqual(globalScope, concat, "concat property is not brought into scope by the with statement");
- assert.areEqual(globalScope, reduce, "toString property is not brought into scope by the with statement");
- assert.areEqual(globalScope, find, "find property is not brought into scope by the with statement");
- assert.areEqual(globalScope, keys, "keys property is not brought into scope by the with statement");
- }
- }
- }
- },
- {
- name: "Inheritance test",
- body: function ()
- {
- function foo ()
- {
- var p = {a: 1};
- var obj = {__proto__: p, [Symbol.unscopables]: {'a' : true}};
- var a = 2;
- with (obj)
- {
- assert.areEqual(2, a, ""); //Spec change we no longer inherit
- }
- }
- foo();
- let p = {a: 1};
- let obj = {__proto__: p, [Symbol.unscopables]: {'a' : true}};
- let a = 2;
- with (obj)
- {
- assert.areEqual(2, a, "");
- }
- }
- },
- {
- name: "Per object unscopables check",
- body: function ()
- {
- var globalScope = -1;
- var proto = { a: 1, b: 2, c: 3, [Symbol.unscopables]: {'a' : true} };
- var child = {__proto__: proto, [Symbol.unscopables]: {'b' : true} };
- var child2 = {__proto__: proto, b: 21, c: 31, [Symbol.unscopables]: {'b' : true} };
- var a = globalScope;
- var b = globalScope;
- with(child)
- {
- assert.areEqual(1, a, "Get @@unscopables finds {'b' : true} on child fist so a is not unscoped");
- assert.areEqual(globalScope, b, "b is unscopable in child and we don't property walk to find b on proto");
- assert.areEqual(3, c, "c is only on the proto");
- a = 3;
- b = 4;
- assert.areEqual(2, proto.b, "proto.b is never set because child b is unscopable");
- }
- assert.areEqual(4, b, "root.b is set to 4 because child b is unscopable");
- b = globalScope;
- assert.areEqual(3, child.a, "child.a should be set to 3");
- assert.areEqual(1, proto.a, "proto.a should be set to 1");
- var a = globalScope;
- proto[Symbol.unscopables]["c"] = true;
- with(child2)
- {
- assert.areEqual(1, a, "Get @@unscopables finds {'b' : true} on child fist so a is not unscoped");
- assert.areEqual(globalScope, b, "b is unscopable in child2 and we don't property walk to find b on proto");
- assert.areEqual(31, c, "c is unscopable in proto but not child2");
- delete c;
- assert.areEqual(3, proto.c, "No delete should have happened");
- assert.areEqual(3, child2.c, "delete should have happened to 31 should now be 3");
- delete c;
- assert.areEqual(3, proto.c, "No delete should have happened");
- assert.areEqual(3, child2.c, "child2 is still 3");
- }
- }
- },
- {
- name: "@@unscopables overwritten as something other than an object",
- body: function ()
- {
- var globalScope = -1;
- var find = globalScope;
- var values = globalScope;
- var c =
- {
- find : function () {},
- values: function () {},
- [Symbol.unscopables]: {"find" : true, "values" : true }
- };
- c[Symbol.unscopables] = 5;
- with(c)
- {
- assert.isTrue(globalScope != find, "find should be on Array scope");
- assert.isTrue(globalScope != values, "values should be on Array scope");
- }
- }
- },
- {
- name: "Eval tests",
- body: function ()
- {
- var globalScope = -1;
- var find = globalScope;
- var c =
- {
- find : function () {},
- [Symbol.unscopables]: {"find" : true }
- };
- with (c)
- {
- assert.areEqual(globalScope, eval("find"), "This property is not brought into scope by the with statement");
- eval("find = 2");
- assert.areEqual(2, eval("find"), "This property is not brought into scope by the with statement");
- assert.areEqual(false, eval("delete find"), "You can only delete properties");
- }
- }
- },
- {
- name: "Mutation test (like the redefinition test just in the with statement)",
- body: function ()
- {
- var o = {a: 1};
- var a = 2;
- with (o)
- {
- o[Symbol.unscopables] = {'a' : true }
- assert.areEqual(2, a, "root.a should have been set");
- }
- }
- },
- {
- name: "Compound assignment",
- body: function ()
- {
- var o = {a: 1};
- var a = 2;
- with (o)
- {
- a += (o[Symbol.unscopables] = {'a' : true }, 2);
- // This is a modification of Brian's Operator precedence test above
- // This is a tricky one a is originally not unscopable so the a we use is o.a
- // then the assignment happens after it is made unscopable
- assert.areEqual(3, a, "should be 1+2");
- }
- assert.areEqual(1, o.a, "root.a should not have changed");
- assert.areEqual(3, a, "should be 1+2");
- }
- },
- {
- name: "Global Object affect",
- body: function ()
- {
- var a = 1
- this[Symbol.unscopables] = {"a" : true }
- assert.areEqual(1, a, "No with statement so @@unscopables should never hit");
- var b;
- this[Symbol.unscopables]["b"] = true;
- b = 1;
- assert.areEqual(1, b, "No with statement so @@unscopables should never hit");
- this[Symbol.unscopables]["c"] = true;
- var c = 1;
- assert.areEqual(1, b, "No with statement so @@unscopables should never hit");
- }
- },
- {
- name: "Set test",
- body: function ()
- {
- with ([])
- {
- find = 2;
- assert.areEqual(2, find, "find property is not brought into scope by the with statement");
- }
- assert.areEqual(2, find, "find property is not brought into scope by the with statement");
- // strict mode
- with ([])
- {
- function test()
- {
- "use strict";
- assert.throws( function () {findIndex = 2;}, ReferenceError, "In strict mode the variable is undefined");
- }
- test();
- }
- // assignment test with let
- let o = {[Symbol.unscopables]: {'b' : true }};
- let b = -1;
- with (o)
- {
- b = 1;
- }
- // assignment test with evals
- assert.areEqual(undefined, o.b, "o.b should never have been set");
- assert.areEqual(1, b, "root.a should have been set");
- with(o)
- {
- eval("b =2;");
- }
- assert.areEqual(undefined, o.b, "o.b should never have been set");
- assert.areEqual(2, b, "root.a should have been set");
- }
- },
- {
- name: "Define unscopables for RegExp and then check Global Scope",
- body: function ()
- {
- var globalScope = -1;
- var input = globalScope;
- var lastMatch = globalScope;
- var lastParen = globalScope;
- var leftContext = globalScope;
- var props = {"input" : true, "lastMatch" : true , "lastParen" : true , "leftContext" : true};
- RegExp[Symbol.unscopables] = props;
- for( i in RegExp[Symbol.unscopables])
- {
- assert.areEqual(props[i], RegExp[Symbol.unscopables][i]);
- }
- assert.isTrue(RegExp.hasOwnProperty(Symbol.unscopables), "RegExp should have RegExp.prototype[@@unscopables] property after definition");
- with(RegExp)
- {
- assert.areEqual(globalScope, input, "input property is not brought into scope by the with statement");
- assert.areEqual(globalScope, lastMatch, "lastMatch property is not brought into scope by the with statement");
- assert.areEqual(globalScope, lastParen, "lastParen property is not brought into scope by the with statement");
- assert.areEqual(globalScope, leftContext, "leftContext property is not brought into scope by the with statement");
- }
- }
- },
- {
- name: "Confirm a call to @@unscopables happens if the environment record property is called",
- body: function ()
- {
- var env = {x : 1};
- var callCount = 0;
- Object.defineProperty(env, Symbol.unscopables, {
- get: function() {
- callCount += 1;
- }
- });
- with (env) {
- void x;
- }
- assert.areEqual(1, callCount, "The environment record has the requested property confirm a call happens");
- }
- },
- {
- name: "Spec Bug Fix for OS 4892049",
- body: function ()
- {
- var x = 0;
- var env = {};
- var callCount = 0;
- Object.defineProperty(env, Symbol.unscopables, {
- get: function() {
- callCount += 1;
- }
- });
- with (env) {
- void x;
- }
- assert.areEqual(0, callCount, "If the environment record does not have requested property don't look up unscopables");
- var x = 0;
- var env = { x: 1 };
- env[Symbol.unscopables] = {};
- env[Symbol.unscopables].x = false;
- with (env) {
- assert.areEqual(1, x, "8.1.1.2.1 step 9a return ToBoolean on the getProperty, if false property is not unscopable");
- }
- }
- },
- {
- name: "Let unscopables be Get(bindings, @@unscopables) should do prototype chain lookups on unscopables",
- body: function ()
- {
- var unscopables = { x : true };
- Object.setPrototypeOf(unscopables, { y: true });
- var env = { x : 1, y : 2, [Symbol.unscopables] : unscopables};
- var x = -1;
- var y = -2;
- with(env)
- {
- assert.areEqual(-1, x, "x is on the @@unscopables object");
- assert.areEqual(-2, y, "y is on the @@unscopables prototype");
- }
- }
- },
- {
- name: "Array.prototype[@@unscopables] [[prototype]] slot is null",
- body: function ()
- {
- assert.areEqual(null, Object.getPrototypeOf(Array.prototype[Symbol.unscopables]), "Array.prototype[@@unscopables].__proto__ === null");
- }
- },
- {
- name: "Array.prototype[@@unscopables] property descriptor",
- body: function ()
- {
- var p = Object.getOwnPropertyDescriptor(Array.prototype, Symbol.unscopables);
- assert.isFalse(p.writable, "Object.getOwnPropertyDescriptor(Array.prototype, Symbol.unscopables).writable === false");
- assert.isFalse(p.enumerable, "Object.getOwnPropertyDescriptor(Array.prototype, Symbol.unscopables).enumerable === false");
- assert.isTrue(p.configurable, "Object.getOwnPropertyDescriptor(Array.prototype, Symbol.unscopables).configurable === true");
- }
- },
- {
- name: "__proto__ on a WithScopeObject",
- body: function () {
- var originalProto = Object.__proto__;
- var o = {};
- with (Object) {
- assert.areEqual(Object.__proto__, __proto__, "With scoped load of Object.__proto__ matches explicit Object.__proto__");
- __proto__ = o;
- assert.areEqual(o, __proto__, "Object.__proto__ change in scoped 'with' matches new __proto object");
- }
- Object.__proto__ = originalProto;
- with (Object) {
- assert.areEqual(Object.__proto__, __proto__, "With scoped load of Object.__proto__ matches explicit Object.__proto__");
- assert.areEqual(Object.__proto__, eval('__proto__'), "Eval with scoped load of Object.__proto__ matches explicit Object.__proto__");
- eval('__proto__ = o');
- assert.areEqual(o, __proto__, "With scoped load of Object.__proto__ has changed after eval Object.__proto__ override");
- assert.areEqual(o, eval('__proto__'), "Eval with scoped load of Object.__proto__ has changed after eval Object.__proto__ override");
- }
- Object.__proto__ = originalProto;
- }
- },
- ];
- testRunner.runTests(tests, { verbose: WScript.Arguments[0] != "summary" });
|