| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494 |
- //-------------------------------------------------------------------------------------------------------
- // 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: "Identifier = value shorthand",
- body: function() {
- var str = "prop";
- assert.areEqual({ str : str }, { str } );
- assert.areEqual({"b" : 123, str : str, "foo" : "bar"}, {"b" : 123, str, "foo" : "bar"});
- }
- },
- {
- name: "Shorthand names `get` and `set` parse without error (they are not keywords in these cases)",
- body: function () {
- var a = 0;
- var get = 1;
- var set = 2;
- var z = 3;
- var o = { get };
- var p = { set };
- var q = { get, set };
- var r = { set, get };
- var s = { get, z };
- var t = { a, set };
- var u = { a, get, z };
- assert.areEqual(1, o.get, "o.get = 1");
- assert.areEqual(2, p.set, "p.set = 2");
- assert.areEqual(1, q.get, "q.get = 1");
- assert.areEqual(2, q.set, "q.set = 2");
- assert.areEqual(2, r.set, "r.set = 2");
- assert.areEqual(1, r.get, "r.get = 1");
- assert.areEqual(1, s.get, "s.get = 1");
- assert.areEqual(3, s.z, "s.z = 3");
- assert.areEqual(0, t.a, "t.a = 0");
- assert.areEqual(2, t.set, "t.set = 2");
- assert.areEqual(0, u.a, "u.a = 0");
- assert.areEqual(1, u.get, "u.get = 1");
- assert.areEqual(3, u.z, "u.z = 3");
- }
- },
- {
- name: "Concise method shorthand",
- body: function() {
- var obj = {
- foo() { return "foo"; }
- };
- assert.areEqual("foo", obj.foo());
- assert.areEqual("foo", ({ foo: function() { }, foo() { return "foo"; } }).foo());
- assert.areEqual("foo", ({ foo(x) { }, foo() { return "foo"; } }).foo());
- }
- },
- {
- name: "Concise method shorthand with `get` and `set` names",
- body: function () {
- var o = {
- get() { return "g"; },
- set() { return "s"; }
- };
- assert.areEqual('g', o.get(), "o.get returns 'g'");
- assert.areEqual('s', o.set(), "o.set returns 's'");
- }
- },
- {
- name: "Computed property names",
- body: function() {
- var x;
- var obj = {
- ["foo" + "bar"] : 1,
- [1 * 10 * 10] : 2,
- [x = "notfoobar"] : 3,
- // computed function name
- ["bar" + "foo"] () { return 4 },
- [2 * 10 * 10] () { return 5 },
- [x = "notbarfoo"] () { return 6 },
- // computed get/set method name
- set ["boo" + "far" ] (a) { this.x = a * 2 },
- get ["boo" + "far" ] () { return this.x },
- set [3 * 10 * 10] (a) { this.y = a * a },
- get [3 * 10 * 10] () { return this.y },
- set [x = "notboofar"] (a) { this.z = a / 3 },
- get [x = "notboofar"] () { return this.z }
- };
- assert.areEqual(1, obj.foobar, "String concat expr as property name");
- assert.areEqual(2, obj[100], "Math expr as property name");
- assert.areEqual(3, obj.notfoobar, "Element list as property name");
- assert.areEqual(4, obj.barfoo(), "String concat expr as method name");
- assert.areEqual(5, obj[200] (), "Math expr as method name");
- assert.areEqual(6, obj.notbarfoo(), "Element list as method name");
- obj.boofar=7;
- assert.areEqual(14, obj.boofar, "String concat expr as setter/getter method names");
- obj[300]=8;
- assert.areEqual(64, obj[300], "Math expr as setter/getter method names");
- obj.notboofar=9;
- assert.areEqual(3, obj.notboofar, "Element list as setter/getter method names");
- var protoObj = {
- ["__proto__"] : { abc : 123 }
- };
- assert.areEqual(protoObj.abc, undefined, "__proto__ does not get assigned as the intrinsic proto when used as a computed property name");
- var nestedProtoObj = {
- ["__proto__"] : {
- ["__" + "proto" + "__"] : {
- abc : 123
- }
- }
- };
- assert.areEqual(nestedProtoObj.abc, undefined, "Nested dynamic __proto__ literals");
- protoObj = {
- "__proto__" : { abc : 123 }
- };
- assert.areEqual(protoObj.abc, 123, "__proto__ get assigned when used as a normal production");
- assert.throws(function () { eval("var b = { ['str'] }"); }, SyntaxError, "Invalid computed identifier shorthand", "Expected ':'");
- assert.throws(function () { eval("var b = { [1, 2]: 3 }"); }, SyntaxError, "Disallow 'Expression' inside 'ComputedPropertyName'", "Expected ']'");
- }
- },
- {
- name: "Duplicate property handling",
- body: function () {
- // Valid overwrite cases: old style definitions and computed property names
- var obj = {
- foobar : 1,
- "foobar" : 2,
- ["foo" + "bar"] : 3,
- ["foo" + "bar"] : 4
- }
- assert.areEqual(obj.foobar, 4, "Opt-in duplicate property handling");
- var obj2 = {
- ["foo" + "bar"] : 1,
- ["foo" + "bar"] : 2
- }
- assert.areEqual(obj2.foobar, 2, "Duplicate computed property names are allowed");
- // Valid cases
- var a = "str";
- assert.areEqual("str", ({ a, a }).a, "Duplicate identifier references");
- assert.areEqual("str", ({ 'foo' : '1', foo() { return "str"; } }).foo(), "Duplicate data property and method definition");
- assert.areEqual("str", ({ set foo(x) { }, foo : "str" }).foo, "Duplicate accessors and data property");
- assert.areEqual("str", ({ get foo() {}, set foo(x) { }, foo(x) { return "str"; } }).foo(), "Duplicate accessors and method definition");
- assert.areEqual("a", ({ get foo() { return "str"; }, set foo(x) { }, ["foo"] : "a" }).foo, "Duplicate accessors and computed property");
- }
- },
- {
- name: "BLUE 552728: Object Literal: Use of keywords is not throwing syntax error",
- body: function () {
- // The following definitions ignore 'yield'
- var keywords = ["break", "case", "catch", "class", "const", "continue", "debugger", "default", "delete", "do",
- "else", "export", "extends", "finally", "for", "function", "if", "import", "in", "instanceof",
- "new", "return", "super", "switch", "this", "throw", "try", "typeof", "var", "void", "while",
- "with"];
- var futureStrict = ["implements", "let", "private", "public", "interface", "package", "protected", "static"];
- // Strict mode rules
- for (var keyword in futureStrict) {
- assert.throws(function () { eval("use strict; var " + keyword + " = 1; var o = { " + keyword + " };"); }, SyntaxError, keyword + " is a forbidden identifier reference");
- }
- // TODO (tcare): When generators are implemented, add a test case where the yield operator is used.
- assert.throws(function () { eval("use strict; var yield = 1; var o = { yield }; "); }, SyntaxError);
- // Non-strict mode rules
- for (var keyword in keywords) {
- assert.throws(function () { eval("var " + keyword + " = 1; var o = { " + keyword + " };"); }, SyntaxError, keyword + " is a forbidden identifier reference");
- }
- var yield = 1;
- var yieldObj = { yield }; // No error
- }
- },
- {
- name: "BLUE 551475: Duplicate property definition not throwing syntax error",
- body: function () {
- assert.areEqual(3, ({ set b(v) { }, b : 3 }).b, "Duplicate set accessor and data property");
- assert.areEqual(3, ({ get b() { }, b : 3 }).b, "Duplicate get accessor and data property");
- assert.areEqual(4, ({ b : 3, get b() { return 4; } }).b, "Duplicate data property and set accessor");
- }
- },
- {
- name: "BLUE 594468: Computed properties in nested object and function return statements cause assertion",
- body: function () {
- () => {
- return {
- ["a"]: null
- }
- }
- }
- },
- {
- name: "BLUE 563637: Computed property ordering causes crash",
- body: function () {
- var a = {
- ["a"] : 10,
- b() {
- return this.a;
- }
- };
- // The implementation of computed properties causes object literals to
- // be constructed (InitFld) up to the first computed property, then StElem
- // for each computed property and StFld for any other non-computed properties.
- // The following test cases test these transitions.
- var original = {
- a : 1,
- b : 2,
- c : 3,
- d : 4,
- e : 5
- };
- var orderOne = {
- a : 1,
- b : 2,
- ["c"] : 3,
- d : 4,
- e : 5
- };
- var orderTwo = {
- a : 1,
- b : 2,
- c : 3,
- d : 4,
- ["e"] : 5
- };
- var orderThree = {
- ["a"] : 1,
- b : 2,
- c : 3,
- d : 4,
- e : 5
- };
- var orderFour = {
- ["a"] : 1,
- b : 2,
- ["c"] : 3,
- d : 4,
- ["e"] : 5
- };
- assert.areEqual(original, orderOne);
- assert.areEqual(original, orderTwo);
- assert.areEqual(original, orderThree);
- assert.areEqual(original, orderFour);
- }
- },
- {
- name: "BLUE 603997: Method formals redeclaration error",
- body: function() {
- assert.doesNotThrow(function() { eval("var obj = { method(a) { var a; } };"); }, "Object literal method with a var redeclaration does not throw");
- assert.throws(function() { eval("var obj = { method(a) { let a; } };"); }, SyntaxError, "Object literal method with a let redeclaration throws", "Let/Const redeclaration");
- assert.throws(function() { eval("var obj = { method(a) { const a; } };"); }, SyntaxError, "Object literal method with a const redeclaration throws", "Let/Const redeclaration");
- assert.doesNotThrow(function() { eval("var obj = { method(a,b,c) { var b; } };"); }, "Object literal method with a var redeclaration does not throw");
- assert.throws(function() { eval("var obj = { method(a,b,c) { let b; } };"); }, SyntaxError, "Object literal method with a let redeclaration throws", "Let/Const redeclaration");
- assert.throws(function() { eval("var obj = { method(a,b,c) { const b; } };"); }, SyntaxError, "Object literal method with a const redeclaration throws", "Let/Const redeclaration");
- assert.doesNotThrow(function() { eval("var obj = { set method(a) { var a; } };"); }, "Object literal set method with a var redeclaration does not throw");
- assert.throws(function() { eval("var obj = { set method(a) { let a; } };"); }, SyntaxError, "Object literal set method with a let redeclaration throws", "Let/Const redeclaration");
- assert.throws(function() { eval("var obj = { set method(a) { const a; } };"); }, SyntaxError, "Object literal set method with a const redeclaration throws", "Let/Const redeclaration");
- }
- },
- {
- name: "BLUE 618132: __proto__ after a computed property",
- body: function () {
- var p = { p: 123 };
- var o = {
- ['someprop'] : 'someprop',
- __proto__: p
- };
- assert.areEqual(p, Object.getPrototypeOf(o));
- assert.isTrue(!o.hasOwnProperty("__proto__"));
- assert.areEqual(123, o.p);
- assert.areEqual('someprop', o.someprop);
- assert.areEqual(p, Object.getPrototypeOf(o));
- }
- },
- {
- name: "BLUE 617446: Arguments identifier syntax",
- body: function () {
- function foo() {
- var args = { arguments };
- return [args.arguments[0], args.arguments[1], args.arguments.length];
- }
- assert.areEqual([undefined, undefined, 0], foo(), "Arguments object correctly works with identifier syntax");
- assert.areEqual([-1, 1, 2], foo(-1, 1), "Arguments object correctly works with identifier syntax");
- assert.areEqual([-1, 1, 3], foo(-1, 1, 0), "Arguments object correctly works with identifier syntax");
- }
- },
- {
- name: "__proto__ productions",
- body: function() {
- assert.throws(function() { eval("{ __proto__ : Function.prototype, __proto__ : Array.prototype }"); }, SyntaxError, "More than one regular productions can't define __proto__");
- var __proto__ = {};
- assert.throws(function() { eval("var o = { __proto__ : Function.prototype, __proto__, __proto__ : Array.prototype };"); }, SyntaxError, "More than one regular productions can't define __proto__ even if there are other productions present");
- assert.isTrue({ __proto__, __proto__ : [], __proto__() {}, __proto__ } instanceof Array, "Regular production model should win over all other");
- assert.isTrue({ ['__proto__'] : Object.prototype, __proto__ : [], ['__proto__'] : {} } instanceof Array, "Computed property definition of __proto__ shouldn't override the regular production");
- assert.isTrue({ __proto__ : [] } instanceof Array, "Regular production for __proto__ should set the internal prototype");
- assert.areEqual(Object.getPrototypeOf({ __proto__ : null }), null, "Null should be set as the prototype when specified using normal production");
- assert.areEqual(Object.getPrototypeOf({ __proto__ : undefined }), Object.prototype, "Undefined should not be set as the internal prototype for object literal");
- assert.areEqual(Object.getPrototypeOf({ __proto__ : "a" }), Object.prototype, "Non-object type string shouldn't be set as the internal prototype for object literal");
- assert.areEqual(Object.getPrototypeOf({ __proto__ : 10 }), Object.prototype, "Non-object type number shouldn't be set as the internal prototype for object literal");
- assert.areEqual(Object.getPrototypeOf({ __proto__ : true }), Object.prototype, "Non-object type boolean shouldn't be set as the internal prototype for object literal");
- var str = "__proto__";
- assert.isFalse({ [str] : [] } instanceof Array, "Computed property shouldn't set the internal prototype");
- __proto__ = [];
- assert.isFalse({ __proto__ } instanceof Array, "Identifier reference shouldn't set the internal prototype");
- assert.isFalse({__proto__() {}} instanceof Function, "Method definition shouldn't set the internal prototype");
- function f() {}
- var obj = { "__proto__" : [], ["__proto__"] : f.prototype };
- Array.prototype.x = 1;
- f.prototype.x = 10;
- assert.areEqual(obj.x, 1, "Regular production should assign the internal prototype");
- assert.areEqual(obj.__proto__.x, 10, "Computed property definition of __proto__ is added as a data member");
- }
- },
- {
- name: "computed property getters can call super methods",
- body: function () {
- function ID(x) { return x; }
- var proto = {
- m() { return ' proto m'; }
- };
- var object = {
- get ['a']() { return 'a' + super.m(); },
- get [ID('b')]() { return 'b' + super.m(); },
- get [0]() { return '0' + super.m(); },
- get [ID(1)]() { return '1' + super.m(); },
- };
- Object.setPrototypeOf(object, proto);
- assert.areEqual('a proto m', object.a, "The value of `object.a` is `'a proto m'`. Defined as `get ['a']() { return 'a' + super.m(); }`");
- assert.areEqual('b proto m', object.b, "The value of `object.a` is `'b proto m'`. Defined as `get [ID('b')]() { return 'b' + super.m(); }`");
- assert.areEqual('0 proto m', object[0], "The value of `object[0]` is `'0 proto m'`. Defined as `get [0]() { return '0' + super.m(); }`");
- assert.areEqual('1 proto m', object[1], "The value of `object[1]` is `'1 proto m'`. Defined as `get [ID(1)]() { return '1' + super.m(); }`");
- }
- },
- {
- name: "computed property setters can call super methods",
- body: function () {
- function ID(x) {
- return x;
- }
- var value;
- var proto = {
- m(name, v) { value = name + ' ' + v; }
- };
- var object = {
- set ['a'](v) { super.m('a', v); },
- set [ID('b')](v) { super.m('b', v); },
- set [0](v) { super.m('0', v); },
- set [ID(1)](v) { super.m('1', v); },
- };
- Object.setPrototypeOf(object, proto);
- object.a = 2;
- assert.areEqual('a 2', value, "The value of `value` is `'a 2'`, after executing `object.a = 2;`");
- object.b = 3;
- assert.areEqual('b 3', value, "The value of `value` is `'b 3'`, after executing `object.b = 3;`");
- object[0] = 4;
- assert.areEqual('0 4', value, "The value of `value` is `'0 4'`, after executing `object[0] = 4;`");
- object[1] = 5;
- assert.areEqual('1 5', value, "The value of `value` is `'1 5'`, after executing `object[1] = 5;`");
- }
- },
- {
- name: "computed property methods can call super methods",
- body: function () {
- function ID(x) { return x; }
- var proto = {
- m() { return ' proto m'; }
- };
- var object = {
- ['a']() { return 'a' + super.m(); },
- [ID('b')]() { return 'b' + super.m(); },
- [0]() { return '0' + super.m(); },
- [ID(1)]() { return '1' + super.m(); },
- };
- Object.setPrototypeOf(object, proto);
- assert.areEqual('a proto m', object.a(), "`object.a()` returns `'a proto m'`, after executing `Object.setPrototypeOf(object, proto);`");
- assert.areEqual('b proto m', object.b(), "`object.b()` returns `'b proto m'`, after executing `Object.setPrototypeOf(object, proto);`");
- assert.areEqual('0 proto m', object[0](), "`object[0]()` returns `'0 proto m'`, after executing `Object.setPrototypeOf(object, proto);`");
- assert.areEqual('1 proto m', object[1](), "`object[1]()` returns `'1 proto m'`, after executing `Object.setPrototypeOf(object, proto);`");
- }
- },
- {
- name: "super method calls in object literal method",
- body: function () {
- var proto = {
- method(x) { return 'proto' + x; }
- };
- var object = {
- method(x) { return super.method(x); }
- };
- Object.setPrototypeOf(object, proto);
- assert.areEqual('proto42', object.method(42), "`object.method(42)` returns `'proto42'`, after executing `Object.setPrototypeOf(object, proto);`");
- assert.areEqual('proto42', proto.method(42), "`proto.method(42)` returns `'proto42'`, after executing `Object.setPrototypeOf(object, proto);`");
- assert.areEqual('proto42', Object.getPrototypeOf(object).method(42), "`Object.getPrototypeOf(object).method(42)` returns `'proto42'`");
- }
- },
- {
- name: "super method calls in object literal getter",
- body: function () {
- var proto = {
- _x: 42,
- get x() { return 'proto' + this._x; }
- };
- var object = {
- get x() { return super.x; }
- };
- Object.setPrototypeOf(object, proto);
- assert.areEqual('proto42', object.x, "The value of `object.x` is `'proto42'`, after executing `Object.setPrototypeOf(object, proto);`");
- assert.areEqual(42, object._x, "The value of `object._x` is `42`, after executing `Object.setPrototypeOf(object, proto);`");
- assert.areEqual(42, Object.getPrototypeOf(object)._x, "The value of `Object.getPrototypeOf(object)._x` is `42`");
- }
- },
- {
- name: "super method calls in object literal setter",
- body: function () {
- var proto = {
- _x: 0,
- set x(v) { return this._x = v; }
- };
- var object = {
- set x(v) { super.x = v; }
- };
- Object.setPrototypeOf(object, proto);
- assert.areEqual(1, object.x = 1, "`object.x = 1` is `1`, after executing `Object.setPrototypeOf(object, proto);`");
- assert.areEqual(1, object._x, "The value of `object._x` is `1`, after executing `Object.setPrototypeOf(object, proto);`");
- assert.areEqual(0, Object.getPrototypeOf(object)._x, "The value of `Object.getPrototypeOf(object)._x` is `0`");
- }
- },
- {
- name: "The HomeObject of Functions declared as methods is the Object prototype.",
- body: function () {
- var obj = {
- method() { return super.toString; }
- };
- obj.toString = null;
- assert.areEqual(Object.prototype.toString, obj.method());
- }
- },
- {
- name: "The HomeObject accessed through default argument of Functions declared as methods is the Object prototype.",
- body: function () {
- var obj = {
- method(x = super.toString) { return x; }
- };
- obj.toString = null;
- assert.areEqual(Object.prototype.toString, obj.method());
- }
- },
- ];
- testRunner.runTests(tests, { verbose: WScript.Arguments[0] != "summary" });
|