blob: 0bcca1bb0f8ed67bfd89ec071bced07bcdcc48d7 [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.
//-------------------------------------------------------------------------------------------------------
/// <reference path="protolib.js" />
if (this.WScript && this.WScript.LoadScriptFile) {
WScript.LoadScriptFile("protolib.js");
}
// Test __proto__ (object literal) initializer in a new engine:
// Run "enabled" function, disable__proto__, then run "disabled" (or by default "enabled" again).
function test_init(enabled, /*optional*/disabled) {
var eng = make_engine();
eng.run(enabled);
eng.disable__proto__();
eng.run(disabled || enabled);
}
var tests = [
{
name: "init to an object",
body: function () {
test_init(
function () { // enabled: [[prototype]]
var p = { p: 123 };
var o = { __proto__: p };
assert.areEqual(p, Object.getPrototypeOf(o));
assert.isTrue(!o.hasOwnProperty("__proto__"));
assert.areEqual(123, o.p);
assert.areEqual(p, Object.getPrototypeOf(o));
});
}
},
{
name: "init to null",
body: function () {
test_init(
function () { // enabled: [[prototype]]
var o = { __proto__: null };
assert.areEqual(null, Object.getPrototypeOf(o));
assert.isFalse({}.hasOwnProperty.apply(o, ["__proto__"]));
assert.areEqual(undefined, o.__proto__); // o's [[prototype]] is null, so doesn't have a __proto__ property
});
}
},
{
name: "init to neither object nor null",
body: function () {
test_init(
function () { // enabled: throw
function test(value) {
var o = { __proto__: value };
assert.areEqual(Object.prototype, Object.getPrototypeOf(o));
assert.isFalse(o.hasOwnProperty("__proto__"));
}
[undefined, 0, 123, Infinity, true, false, "string value"].forEach(function (value) {
test(value);
});
});
}
},
{
name: "init to accessor",
body: function () {
test_init(
function () { // same for enabled/disabled: local property
var o = {
get __proto__() { return "proto"; },
set __proto__(value) { this.__proto__value = value; }
};
assert.areEqual(Object.prototype, Object.getPrototypeOf(o));
assert.isTrue(o.hasOwnProperty("__proto__"));
assert.areEqual("proto", o.__proto__);
o.__proto__ = "a value";
assert.areEqual("a value", o.__proto__value);
});
}
},
{
name: "verify no incorrectly shared type",
body: function () {
function foo(p) {
return {
a: 100,
__proto__: p,
};
}
// If we incorrectly shared Type, we'll have wrong [[prototype]].
var o1 = foo({ b: 1 });
var o2 = foo({ b: 2 });
var o3 = foo({ b: 3 });
assert.areEqual(1, o1.b);
assert.areEqual(2, o2.b);
assert.areEqual(3, o3.b);
}
},
{
name: "verify not accidentally enables it for function parameters",
body: function () {
function foo(a, b, __proto__) {
var o = arguments;
assert.areEqual(Object.prototype, Object.getPrototypeOf(o));
assert.areEqual(Object.prototype, o.__proto__);
assert.isTrue(!o.hasOwnProperty("__proto__"));
assert.areEqual(1, o[0]);
assert.areEqual(3, o[2].a);
assert.areEqual(4, __proto__.b);
}
foo(1, 2, { a: 3, b: 4, c: 5 });
}
},
{
name: "verify not accidentally enables it for JSON",
body: function () {
var o = JSON.parse('{ "a": 1, "b": 2, "__proto__": {"c": 3, "d": 4} }');
assert.areEqual(Object.prototype, Object.getPrototypeOf(o));
assert.isTrue(o.hasOwnProperty("__proto__"));
assert.areEqual(3, o.__proto__.c);
}
},
{
name: "Verify not accidentally share code with global InitFld",
body: function () {
// Check if we accidentally changed global's [[prototype]] to a function when declaring a global
// function with name __proto__ (see bottom of this file). If yes, we'd have "length" property.
assert.areEqual(undefined, this.length);
}
},
{
name: "Run the same initializer with __proto__ enabled, run it again with __proto__ disabled",
body: function () {
var eng = make_engine();
// inject global g_p and foo into eng
eng.eval("var g_p = { p: 123 }");
eng.eval("var foo = " + function() {
return { a: 0, __proto__: g_p, b: 1 };
});
var test = function () { // enabled: [[prototype]]
var o = foo();
assert.areEqual(g_p, Object.getPrototypeOf(o));
assert.areEqual("a,b", Object.keys(o).toString());
assert.areEqual(123, o.p);
};
eng.run(test);
eng.disable__proto__();
eng.run(test);
}
},
{
name: "Enumeration order should be unaffected",
body: function () {
test_init(
function () {
var o = {
a: 100,
__proto__: new Number(200),
b: 300,
};
assert.areEqual("a,b", Object.keys(o).toString());
});
test_init(
function () { // enabled: [[prototype]]
var o = {
a: 100,
__proto__: { c: "p0", d: "p1" },
b: 300,
};
var names = [];
for (var name in o) {
names.push(name);
}
assert.areEqual("a,b", Object.keys(o).toString());
assert.areEqual("a,b,c,d", names.toString());
});
}
},
{
name: "Verify bytecode serialization",
body: function () { // Test in current engine to use switch -ForceSerialized
var o = {
a: 100,
__proto__: { c: "p0", d: "p1" },
b: 300,
};
// Serialized bytecode should correctly mark if initializer has__proto__
assert.areEqual("a,b", Object.keys(o).toString());
}
},
];
testRunner.run(tests);
// Used by: Verify not accidentally share code with global InitFld
function __proto__() { }