| let assert = (a) => { |
| if (!a) |
| throw new Error("Bad Assertion"); |
| } |
| |
| assert.sameValue = (a, b) => { |
| assert(a === b); |
| } |
| |
| function validatePropertyDescriptor(o, p) { |
| let desc = Object.getOwnPropertyDescriptor(o, p); |
| |
| assert(desc.enumerable); |
| assert(desc.configurable); |
| assert(desc.writable); |
| } |
| |
| // Base cases |
| |
| (() => { |
| let obj = {a: 1, b: 2, ...{c: 3, d: 4}}; |
| |
| assert.sameValue(obj.a, 1); |
| assert(obj.b, 2); |
| assert(obj.c, 3); |
| assert(obj.d, 4); |
| validatePropertyDescriptor(obj, "c"); |
| validatePropertyDescriptor(obj, "d"); |
| assert(Object.keys(obj), 2); |
| })(); |
| |
| (() => { |
| let o = {c: 3, d: 4}; |
| let obj = {a: 1, b: 2, ...o}; |
| |
| assert.sameValue(obj.a, 1); |
| assert.sameValue(obj.b, 2); |
| assert.sameValue(obj.c, 3); |
| assert.sameValue(obj.d, 4); |
| assert.sameValue(Object.keys(obj).length, 4); |
| |
| validatePropertyDescriptor(obj, "a"); |
| validatePropertyDescriptor(obj, "b"); |
| validatePropertyDescriptor(obj, "c"); |
| validatePropertyDescriptor(obj, "d"); |
| })(); |
| |
| (() => { |
| 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}; |
| |
| assert.sameValue(Object.getOwnPropertyDescriptor(obj, "a").value, 42); |
| assert.sameValue(obj.c, 4); |
| assert.sameValue(obj.d, 5); |
| assert.sameValue(Object.keys(obj).length, 3); |
| |
| validatePropertyDescriptor(obj, "a"); |
| })(); |
| |
| (() => { |
| 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}; |
| |
| assert.sameValue(obj.a, 3) |
| assert.sameValue(obj.b, 2); |
| validatePropertyDescriptor(obj, "a"); |
| validatePropertyDescriptor(obj, "b"); |
| })(); |
| |
| // 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); |
| })(); |
| |