206 lines
10 KiB
JavaScript
206 lines
10 KiB
JavaScript
description("basic tests for object literal duplicate properties");
|
|
|
|
// Ensure basic properties get eliminated by getters.
|
|
x = 0;
|
|
o = {
|
|
foo: x++,
|
|
get foo() {return "getter"},
|
|
};
|
|
shouldBe("x", "1");
|
|
shouldBe("o.foo", "'getter'");
|
|
|
|
// Ensure getters/setters get eliminated by basic properties.
|
|
x = 0;
|
|
o = {
|
|
get foo() {return "getter"},
|
|
foo: x++,
|
|
};
|
|
shouldBe("x", "1");
|
|
shouldBe("o.foo", "0");
|
|
|
|
// Ensure computed properties are eliminated by getters/setters.
|
|
x = 0;
|
|
o = {
|
|
['foo']: x++,
|
|
get foo() {return "getter"},
|
|
};
|
|
shouldBe("x", "1");
|
|
shouldBe("o.foo", "'getter'");
|
|
|
|
// Ensure getters/setters properties are eliminated by computed properties.
|
|
x = 0;
|
|
o = {
|
|
get foo() {return "getter"},
|
|
set foo(x) {},
|
|
['foo']: x++,
|
|
};
|
|
shouldBe("x", "1");
|
|
shouldBe("o.foo", "0");
|
|
|
|
// Multiple types and multiple properties.
|
|
x = 0;
|
|
o = {
|
|
get foo() { return "NO"; },
|
|
foo: x++,
|
|
set test1(x) {},
|
|
bar: x++,
|
|
get test2() {},
|
|
['test3']: x++,
|
|
get foo() {return "getter"},
|
|
['foo']: x++,
|
|
set bar(x) {},
|
|
nest: {foo:1, get foo(){}, bar:1, set foo(x){}},
|
|
};
|
|
shouldBe("x", "4");
|
|
shouldBe("o.foo", "3");
|
|
shouldBe("o.bar", "undefined");
|
|
shouldBe("Object.keys(o).join()", "'foo,test1,bar,test2,test3,nest'");
|
|
|
|
|
|
|
|
function descriptionString(o, property) {
|
|
var descriptor = Object.getOwnPropertyDescriptor(o, property);
|
|
if (!descriptor)
|
|
return "PROPERTY NOT FOUND";
|
|
|
|
var string = "";
|
|
if (descriptor.value)
|
|
string += "value:" + String(descriptor.value) + " ";
|
|
if (descriptor.get)
|
|
string += "getter:" + typeof descriptor.get + " value:(" + o[property] + ") ";
|
|
if (descriptor.set)
|
|
string += "setter:" + typeof descriptor.set + " ";
|
|
|
|
string += "keys:" + Object.keys(o).length + " ";
|
|
|
|
string += "[";
|
|
if (descriptor.enumerable)
|
|
string += "E";
|
|
if (descriptor.configurable)
|
|
string += "C";
|
|
if (descriptor.writable)
|
|
string += "W";
|
|
string += "]";
|
|
|
|
if (Object.isSealed(o))
|
|
string += "[Sealed]";
|
|
if (Object.isFrozen(o))
|
|
string += "[Frozen]";
|
|
if (Object.isExtensible(o))
|
|
string += "[Extensible]";
|
|
|
|
return string;
|
|
}
|
|
|
|
function runTest(test, expected) {
|
|
test = test + "; descriptionString(o, 'foo');";
|
|
if (expected) {
|
|
shouldBe(test, expected);
|
|
shouldBe("'use strict';" + test, expected);
|
|
shouldNotThrow("(function(){" + test + "})()");
|
|
} else {
|
|
shouldThrow(test);
|
|
shouldThrow("'use strict';" + test);
|
|
shouldThrow("(function(){" + test + "})()");
|
|
}
|
|
}
|
|
|
|
// Basic properties.
|
|
debug(""); debug("Basic");
|
|
runTest("o = {foo:1}", "'value:1 keys:1 [ECW][Extensible]'");
|
|
runTest("o = {foo:1}; o.foo = 2", "'value:2 keys:1 [ECW][Extensible]'");
|
|
runTest("o = {foo:1, foo:3}", "'value:3 keys:1 [ECW][Extensible]'");
|
|
runTest("o = {foo:1, fooo:2, foo:3}", "'value:3 keys:2 [ECW][Extensible]'");
|
|
runTest("o = {foo:1, fooo:2, foo:3}; o.foo = 4", "'value:4 keys:2 [ECW][Extensible]'");
|
|
runTest("o = {foo:1, fooo:2, foo:3, bar: 9}", "'value:3 keys:3 [ECW][Extensible]'");
|
|
runTest("o = {foo:1, foo:3}; Object.defineProperty(o, 'foo', {value:5})", "'value:5 keys:1 [ECW][Extensible]'");
|
|
runTest("o = {foo:1, foo:3}; Object.defineProperty(o, 'foo', {get(){return 5}})", "'getter:function value:(5) keys:1 [EC][Extensible]'");
|
|
runTest("o = {foo:1, foo:3}; o.__defineGetter__('foo', function(){return 5})", "'getter:function value:(5) keys:1 [EC][Extensible]'");
|
|
runTest("o = {foo:1, foo:3}; Object.seal(o);", "'value:3 keys:1 [EW][Sealed]'");
|
|
runTest("o = {foo:1, foo:3}; Object.seal(o); o.foo = 5", "'value:5 keys:1 [EW][Sealed]'");
|
|
runTest("o = {foo:1, foo:3}; Object.seal(o); Object.defineProperty(o, 'foo', {value:5})", "'value:5 keys:1 [EW][Sealed]'");
|
|
runTest("o = {foo:1, foo:3}; Object.seal(o); Object.defineProperty(o, 'foo', {get(){return 5}})", null);
|
|
runTest("o = {foo:1, foo:3}; Object.seal(o); o.__defineGetter__('foo', function(){return 5})");
|
|
|
|
// Basic properties with Computed properties.
|
|
debug(""); debug("Basic + Computed");
|
|
runTest("o = {['foo']:1}", "'value:1 keys:1 [ECW][Extensible]'");
|
|
runTest("o = {foo:1, ['foo']:2}", "'value:2 keys:1 [ECW][Extensible]'");
|
|
runTest("o = {['foo']:1, foo:2}", "'value:2 keys:1 [ECW][Extensible]'");
|
|
runTest("o = {foo:1, ['foo']:2, foo:3}", "'value:3 keys:1 [ECW][Extensible]'");
|
|
runTest("o = {['foo']:1, foo:2, ['foo']:3}", "'value:3 keys:1 [ECW][Extensible]'");
|
|
runTest("o = {['foo']:1, ['foo']:2}", "'value:2 keys:1 [ECW][Extensible]'");
|
|
runTest("o = {foo:1, ['foo']:2}; o.foo = 3", "'value:3 keys:1 [ECW][Extensible]'");
|
|
runTest("o = {['foo']:1, ['bar']:2}", "'value:1 keys:2 [ECW][Extensible]'");
|
|
runTest("o = {['foo']:1, ['bar']:2, foo:3}", "'value:3 keys:2 [ECW][Extensible]'");
|
|
|
|
// Basic properties with Accessor properties.
|
|
debug(""); debug("Basic + Accessor");
|
|
runTest("o = {get foo(){return 2}}", "'getter:function value:(2) keys:1 [EC][Extensible]'");
|
|
runTest("o = {set foo(x){}}", "'setter:function keys:1 [EC][Extensible]'");
|
|
runTest("o = {get foo(){return 1}, get foo(){return 2}}", "'getter:function value:(2) keys:1 [EC][Extensible]'");
|
|
runTest("o = {get foo(){return 2}, set foo(x){}}", "'getter:function value:(2) setter:function keys:1 [EC][Extensible]'");
|
|
runTest("o = {get foo(){return 2}, set foo(x){}, get foo(){return 3}}", "'getter:function value:(3) setter:function keys:1 [EC][Extensible]'");
|
|
runTest("o = {bar:1, get foo(){return 2}, set foo(x){}, baz:1}", "'getter:function value:(2) setter:function keys:3 [EC][Extensible]'");
|
|
runTest("o = {foo:1, get foo(){return 2}}", "'getter:function value:(2) keys:1 [EC][Extensible]'");
|
|
runTest("o = {foo:1, get foo(){return 2}, set foo(x){}}", "'getter:function value:(2) setter:function keys:1 [EC][Extensible]'");
|
|
runTest("o = {get foo(){return 2}, foo:1}", "'value:1 keys:1 [ECW][Extensible]'");
|
|
runTest("o = {get foo(){return 2}, set foo(x){}, foo:1}", "'value:1 keys:1 [ECW][Extensible]'");
|
|
runTest("o = {foo:1, get foo(){return -1}, foo:2}", "'value:2 keys:1 [ECW][Extensible]'");
|
|
runTest("o = {foo:1, get foo(){return 2}, bar:3}", "'getter:function value:(2) keys:2 [EC][Extensible]'");
|
|
runTest("o = {foo:1, get foo(){return -1}, foo:-1, get foo() {return 2}}", "'getter:function value:(2) keys:1 [EC][Extensible]'");
|
|
runTest("o = {foo:1, get foo(){return 3}}; Object.defineProperty(o, 'foo', {value:5})", "'value:5 keys:1 [EC][Extensible]'");
|
|
runTest("o = {foo:1, get foo(){return 3}}; Object.defineProperty(o, 'foo', {get(){return 5}})", "'getter:function value:(5) keys:1 [EC][Extensible]'");
|
|
runTest("o = {foo:1, get foo(){return 3}}; o.__defineGetter__('foo', function(){return 5})", "'getter:function value:(5) keys:1 [EC][Extensible]'");
|
|
runTest("o = {foo:1, get foo(){return 3}, set foo(x){}}; Object.seal(o); o.foo = 5", "'getter:function value:(3) setter:function keys:1 [E][Sealed][Frozen]'");
|
|
runTest("o = {foo:1, get foo(){return 3}}; Object.seal(o);", "'getter:function value:(3) keys:1 [E][Sealed][Frozen]'");
|
|
runTest("o = {foo:1, get foo(){return 3}}; Object.seal(o); Object.defineProperty(o, 'foo', {get(){return 5}})", null);
|
|
runTest("o = {foo:1, get foo(){return 3}}; Object.seal(o); Object.defineProperty(o, 'foo', {value:5})", null);
|
|
runTest("o = {foo:1, get foo(){return 3}}; Object.seal(o); o.__defineGetter__('foo', function(){return 5})");
|
|
|
|
// Computed properties with Accessor properties.
|
|
debug(""); debug("Computed + Accessor");
|
|
runTest("o = {['foo']:1, get foo(){return 2}}", "'getter:function value:(2) keys:1 [EC][Extensible]'");
|
|
runTest("o = {['foo']:1, get foo(){return 2}, set foo(x){}}", "'getter:function value:(2) setter:function keys:1 [EC][Extensible]'");
|
|
runTest("o = {get foo(){return 2}, ['foo']:1}", "'value:1 keys:1 [ECW][Extensible]'");
|
|
runTest("o = {get foo(){return 2}, set foo(x){}, ['foo']:1}", "'value:1 keys:1 [ECW][Extensible]'");
|
|
runTest("o = {['foo']:1, get foo(){return -1}, ['foo']:2}", "'value:2 keys:1 [ECW][Extensible]'");
|
|
runTest("o = {['foo']:1, get foo(){return 2}, ['bar']:3}", "'getter:function value:(2) keys:2 [EC][Extensible]'");
|
|
runTest("o = {['foo']:1, get foo(){return -1}, ['foo']:-1, get foo() {return 2}}", "'getter:function value:(2) keys:1 [EC][Extensible]'");
|
|
|
|
// Basic properties, Computed properties, and Accessor properties.
|
|
debug(""); debug("Basic + Computed + Accessor");
|
|
runTest("o = {foo:1, get foo(){return 2}, ['foo']:3}", "'value:3 keys:1 [ECW][Extensible]'");
|
|
runTest("o = {foo:1, ['foo']:3, get foo(){return 2}}", "'getter:function value:(2) keys:1 [EC][Extensible]'");
|
|
runTest("o = {foo:1, ['foo']:3, get foo(){return 2}, set foo(x){}}", "'getter:function value:(2) setter:function keys:1 [EC][Extensible]'");
|
|
runTest("o = {['foo']:3, get foo(){return 2}, foo:1}", "'value:1 keys:1 [ECW][Extensible]'");
|
|
runTest("o = {get foo(){return 2}, ['foo']:3, foo:1}", "'value:1 keys:1 [ECW][Extensible]'");
|
|
runTest("o = {get foo(){return 2}, ['foo']:3, get foo(){return 2}, foo:1}", "'value:1 keys:1 [ECW][Extensible]'");
|
|
runTest("o = {set foo(x){}, ['foo']:3, set foo(x){}, foo:1}", "'value:1 keys:1 [ECW][Extensible]'");
|
|
runTest("o = {set foo(x){}, foo:1, get foo(){return 2}, ['foo']:3}", "'value:3 keys:1 [ECW][Extensible]'");
|
|
runTest("o = {get foo(){return 2}, get foo(){return 2}, ['foo']:3, foo:1}", "'value:1 keys:1 [ECW][Extensible]'");
|
|
|
|
// __proto__ duplicates are not allowed.
|
|
function runProtoTestShouldThrow(test) {
|
|
shouldThrow(test);
|
|
shouldThrow("'use strict';" + test);
|
|
shouldThrow("(function(){" + test + "})()");
|
|
}
|
|
function runProtoTestShouldNotThrow(test) {
|
|
shouldNotThrow(test);
|
|
shouldNotThrow("'use strict';" + test);
|
|
shouldNotThrow("(function(){" + test + "})()");
|
|
}
|
|
|
|
debug(""); debug("Duplicate simple __proto__ attributes are not allowed");
|
|
runProtoTestShouldNotThrow("o = {__proto__:null}");
|
|
runProtoTestShouldNotThrow("({__proto__:null, ['__proto__']:{}})");
|
|
runProtoTestShouldNotThrow("o = {__proto__:null, ['__proto__']:{}}");
|
|
runProtoTestShouldNotThrow("o = {__proto__:null, get __proto__(){}}");
|
|
runProtoTestShouldNotThrow("var __proto__ = null; o = {__proto__:null, __proto__}");
|
|
runProtoTestShouldThrow("({__proto__:[], __proto__:{}})");
|
|
runProtoTestShouldThrow("o = {__proto__:null, '__proto__':{}}");
|
|
runProtoTestShouldThrow("o = {__proto__:[], __proto__:{}}");
|
|
runProtoTestShouldThrow("o = {'__proto__':{}, '__proto__':{}}");
|
|
runProtoTestShouldThrow("o = {a:1, __proto__:{}, b:2, ['c']:3, __proto__:{}, d:3}");
|