blob: 453d336bc0dfdd7147618166dd4845c0eb81cd3b [file] [log] [blame]
let assert = (a) => {
if (!a)
throw new Error("Bad Assertion");
}
assert.sameValue = (a, b) => {
assert(a === b);
}
function shouldBe(actual, expected) {
if (actual !== expected)
throw new Error(`Bad value: ${actual}!`);
}
function assertDataProperty(target, prop, value) {
shouldBe(target[prop], value);
let desc = Object.getOwnPropertyDescriptor(target, prop);
shouldBe(desc.value, value);
assert(desc.enumerable);
assert(desc.writable);
assert(desc.configurable);
}
// Base cases
(() => {
let obj = {a: 1, b: 2, ...{c: 3, d: 4}};
assert.sameValue(obj.a, 1);
assert(obj.b, 2);
assertDataProperty(obj, "c", 3);
assertDataProperty(obj, "d", 4);
assert(Object.keys(obj), 2);
})();
(() => {
let o = {c: 3, d: 4};
let obj = {a: 1, b: 2, ...o};
assertDataProperty(obj, "a", 1);
assertDataProperty(obj, "b", 2);
assertDataProperty(obj, "c", 3);
assertDataProperty(obj, "d", 4);
assert.sameValue(Object.keys(obj).length, 4);
})();
(() => {
let o = {a: 2, b: 3};
let o2 = {c: 4, d: 5};
let obj = {...o, ...o2};
assert.sameValue(obj.a, 2);
assert.sameValue(obj.b, 3);
assert.sameValue(obj.c, 4);
assert.sameValue(obj.d, 5);
assert.sameValue(Object.keys(obj).length, 4);
})();
// Empty case
(() => {
let obj = {a: 1, b: 2, ...{}};
assert.sameValue(obj.a, 1);
assert.sameValue(obj.b, 2);
assert.sameValue(Object.keys(obj).length, 2);
})();
// Ignoring cases
(() => {
let obj = {a: 1, ...null, b: 2, ...undefined, c: 3, ...{}, ...{...{}}, d: 4};
assert.sameValue(obj.a, 1);
assert.sameValue(obj.b, 2);
assert.sameValue(obj.c, 3);
assert.sameValue(obj.d, 4);
let keys = Object.keys(obj);
assert.sameValue(keys[0], "a");
assert.sameValue(keys[1], "b");
assert.sameValue(keys[2], "c");
assert.sameValue(keys[3], "d");
})();
// Null case
(() => {
let obj = {a: 1, b: 2, ...null};
assert.sameValue(obj.a, 1);
assert.sameValue(obj.b, 2);
assert.sameValue(Object.keys(obj).length, 2);
})();
(() => {
let obj = {...null};
assert.sameValue(Object.keys(obj).length, 0);
})();
// Undefined case
(() => {
let obj = {a: 1, b: 2, ...undefined};
assert.sameValue(obj.a, 1);
assert.sameValue(obj.b, 2);
assert.sameValue(Object.keys(obj).length, 2);
})();
(() => {
let obj = {...undefined};
assert.sameValue(Object.keys(obj).length, 0);
})();
// Getter case
(() => {
let o = {
get a() {
return 42;
}
};
let obj = {...o, c: 4, d: 5};
assertDataProperty(obj, "a", 42);
assert.sameValue(obj.c, 4);
assert.sameValue(obj.d, 5);
assert.sameValue(Object.keys(obj).length, 3);
})();
(() => {
let o = {a: 2, b: 3}
let executedGetter = false;
let obj = {...o, get c() { executedGetter = true; }};
assert.sameValue(obj.a, 2);
assert.sameValue(obj.b, 3);
assert.sameValue(executedGetter, false)
assert.sameValue(Object.keys(obj).length, 3);
})();
(() => {
let getterCallCount = 0;
let o = {
get a() {
return ++getterCallCount;
}
};
let obj = {...o, c: 4, d: 5, a: 42, ...o};
assert.sameValue(obj.a, 2);
assert.sameValue(obj.c, 4);
assert.sameValue(obj.d, 5);
assert.sameValue(Object.keys(obj).length, 3);
})();
// Manipulate Object case
(() => {
var o = { a: 0, b: 1 };
var cthulhu = { get x() {
delete o.a;
o.b = 42;
o.c = "ni";
}};
let obj = {...cthulhu, ...o};
assert.sameValue(obj.hasOwnProperty("a"), false);
assert.sameValue(obj.b, 42);
assert.sameValue(obj.c, "ni");
assert(obj.hasOwnProperty("x"));
assert.sameValue(Object.keys(obj).length, 3);
})();
// Override
(() => {
let o = {a: 2, b: 3};
let obj = {a: 1, b: 7, ...o};
assert.sameValue(obj.a, 2);
assert.sameValue(obj.b, 3);
assert.sameValue(Object.keys(obj).length, 2);
assert.sameValue(o.a, 2);
assert.sameValue(o.b, 3);
})();
(() => {
let o = {a: 2, b: 3, c: 4, e: undefined, f: null, g: false};
let obj = {...o, a: 1, b: 7, d: 5, h: -0, i: Symbol("foo"), j: o};
assert.sameValue(obj.a, 1);
assert.sameValue(obj.b, 7);
assert.sameValue(obj.c, 4);
assert.sameValue(obj.d, 5);
assert(obj.hasOwnProperty("e"));
assert.sameValue(obj.f, null);
assert.sameValue(obj.g, false);
assert.sameValue(obj.h, -0);
assert.sameValue(obj.i.toString(), "Symbol(foo)");
assert(Object.is(obj.j, o));
assert.sameValue(Object.keys(obj).length, 10);
})();
// Override Immutable
(() => {
let o = {b: 2};
Object.defineProperty(o, "a", {value: 1, enumerable: true, writable: false, configurable: true});
let obj = {...o, a: 3};
assertDataProperty(obj, "a", 3);
assertDataProperty(obj, "b", 2);
})();
// Setter
(() => {
let executedSetter = false;
let obj = {set c(v) { executedSetter = true; }, ...{c: 1}};
assert.sameValue(obj.c, 1);
assert.sameValue(executedSetter, false);
assert.sameValue(Object.keys(obj).length, 1);
})();
// Skip non-enumerble
(() => {
let o = {};
Object.defineProperty(o, "b", {value: 3, enumerable: false});
let obj = {...o};
assert.sameValue(obj.hasOwnProperty("b"), false)
assert.sameValue(Object.keys(obj).length, 0);
})();
// Spread order
(() => {
var calls = []
var o = { get z() { calls.push('z') }, get a() { calls.push('a') } };
Object.defineProperty(o, 1, { get: () => { calls.push(1) }, enumerable: true });
Object.defineProperty(o, Symbol('foo'), { get: () => { calls.push("Symbol(foo)") }, enumerable: true });
let obj = {...o};
assert.sameValue(calls[0], 1);
assert.sameValue(calls[1], "z");
assert.sameValue(calls[2], "a");
assert.sameValue(calls[3], "Symbol(foo)");
assert.sameValue(Object.keys(obj).length, 3);
})();
// Symbol property
(() => {
let symbol = Symbol('foo');
let o = {};
o[symbol] = 1;
let obj = {...o, c: 4, d: 5};
assert.sameValue(obj[symbol], 1);
assert.sameValue(obj.c, 4);
assert.sameValue(obj.d, 5);
assert.sameValue(Object.keys(obj).length, 2);
})();
// Getter throw
(() => {
try {
let obj = {...{ get foo() { throw new Error("Getter Exception"); } }};
assert(false);
} catch(e) {
assert.sameValue(e.message, "Getter Exception");
}
})();
// Spread overrides properties
(() => {
var calls = []
var o = { a: 1, b: 2 };
let executedGetter = false;
let executedSetter = false
let obj = {get a() {executedGetter = true; return this_a;}, ...o, set a(v) { executedSetter = true; this._a = v}};
obj.a = 3
assert.sameValue(obj.a, undefined);
assert(!executedGetter);
assert(executedSetter);
})();
(function nonEnumerableSymbol() {
var __s0 = Symbol("s0");
var source = {};
Object.defineProperties(source, {
[__s0]: {value: 0, enumerable: false},
});
var target = {[__s0]: 1, ...target};
assertDataProperty(target, __s0, 1);
})();
(function dunderProto() {
var source = {};
var protoValue = {};
Object.defineProperty(source, "__proto__", {value: protoValue, enumerable: true});
var target = {...source};
assertDataProperty(target, "__proto__", protoValue);
shouldBe(Object.getPrototypeOf(target), Object.prototype);
})();
(function stringPrimitive() {
var source = "012";
var target = {get 0() {}, ["2"]: 22, ...source};
assertDataProperty(target, 0, "0");
assertDataProperty(target, 1, "1");
assertDataProperty(target, 2, "2");
shouldBe(Object.keys(target).join(), "0,1,2");
})();
(function ProxyObject() {
var __s0 = Symbol("s0");
var __s1 = Symbol("s1");
var ownKeysCalls = 0;
var gopdCalls = [];
var getCalls = [];
var source = new Proxy({
[__s0]: "s0", [__s1]: "s1",
a: 0, b: 1, c: 2, d: 3,
}, {
ownKeys: (t) => {
++ownKeysCalls;
return Reflect.ownKeys(t);
},
getOwnPropertyDescriptor: (t, key) => {
gopdCalls.push(key);
var desc = Reflect.getOwnPropertyDescriptor(t, key);
if (key === "b" || key === __s0)
desc.enumerable = false;
return desc;
},
get: (t, key, receiver) => {
getCalls.push(key);
return Reflect.get(t, key, receiver);
},
});
var target = {a() {}, b: 11, [__s1]: "foo", ...source, ["d"]: 33};
shouldBe(ownKeysCalls, 1);
shouldBe(gopdCalls.map(String).join(), "a,b,c,d,Symbol(s0),Symbol(s1)");
shouldBe(getCalls.map(String).join(), "a,c,d,Symbol(s1)");
assertDataProperty(target, "a", 0);
assertDataProperty(target, "b", 11);
assertDataProperty(target, "c", 2);
assertDataProperty(target, "d", 33);
shouldBe(Reflect.ownKeys(target).map(String).join(), "a,b,c,d,Symbol(s1)");
})();
(function indexedProperties() {
var source = [0, 1, 2];
Object.defineProperty(source, "1", {enumerable: false});
var target = {set ["2"](_v) {}, ...source};
assertDataProperty(target, "0", 0);
assertDataProperty(target, "2", 2);
shouldBe(Object.keys(target).join(), "0,2");
})();
(function CustomAccessor() {
var source = $vm.createCustomTestGetterSetter();
var target = {...source};
assertDataProperty(target, "customValue", source);
shouldBe(target.customValueGlobalObject, target.customAccessorGlobalObject);
shouldBe(target.customValueGlobalObject[Symbol.toStringTag], "global");
assertDataProperty(target, "customAccessor", source);
})();
(function CustomAccessorInNonReifiedPropertyTable() {
// make sure we reifyAllStaticProperties() before deciding on the fast/slow path
var source = $vm.createStaticCustomAccessor();
source.testField = 42;
var target = {...source};
assertDataProperty(target, "testField", 42);
assertDataProperty(target, "testStaticAccessor", 42);
})();
(function uncacheableDictionary() {
var source = {a: 0, b: 1, c: 2};
Object.defineProperty(source, "c", {enumerable: false});
$vm.toUncacheableDictionary(source);
var b = 11;
var target = {get a() {}, b, ...source};
assertDataProperty(target, "a", 0);
assertDataProperty(target, "b", 1);
shouldBe(Object.keys(target).join(), "a,b");
})();