import { assert } from 'chai'; import * as object from '../../../../../../lib/core/object'; import { MetaContext } from '../../../../../../lib/experimental/meta/MetaContext'; import { $ASSIGN, withAssign } from '../../../../../../lib/experimental/meta/operations/base/$assign'; import { withClone } from '../../../../../../lib/experimental/meta/operations/base/$clone'; import assignBuiltins from '../../../../../../lib/experimental/meta/operations/builtins/$assign'; import cloneBuiltins from '../../../../../../lib/experimental/meta/operations/builtins/$clone'; import constructBuiltins from '../../../../../../lib/experimental/meta/operations/builtins/$construct'; const assign = (function () { const context = new (withAssign(withClone(MetaContext)))(); context.registerAll(assignBuiltins).registerAll(cloneBuiltins).registerAll(constructBuiltins); return function assign(lhs: T, rhs: T) { return context[$ASSIGN](lhs, rhs); }; })(); describe('experimental.meta.operations.builtins.$clone', () => { describe('string', () => { it('string', () => { const lhs = 'foo'; const rhs = 'bar'; const result = assign(lhs, rhs); assert.strictEqual(lhs, 'foo'); assert.strictEqual(result, 'bar'); }); }); describe('String', () => { it('String', () => { const lhs = new String('foo'); const rhs = new String('bar'); const result = assign(lhs, rhs); assert.strictEqual(result, rhs); assert.strictEqual(lhs.valueOf(), 'foo'); assert.strictEqual(result.valueOf(), 'bar'); }); }); describe('number', () => { it('number', () => { const lhs = 1; const rhs = 2; const result = assign(lhs, rhs); assert.strictEqual(lhs, 1); assert.strictEqual(result, 2); }); }); describe('Number', () => { it('Number', () => { const lhs = new Number(1); const rhs = new Number(2); const result = assign(lhs, rhs); assert.strictEqual(result, rhs); assert.strictEqual(lhs.valueOf(), 1); assert.strictEqual(result.valueOf(), 2); }); }); describe('boolean', () => { it('boolean', () => { const lhs = true; const rhs = false; const result = assign(lhs, rhs); assert.strictEqual(lhs, true); assert.strictEqual(result, false); }); }); describe('Boolean', () => { it('Boolean', () => { const lhs = new Boolean(true); const rhs = new Boolean(false); const result = assign(lhs, rhs); assert.strictEqual(result, rhs); assert.strictEqual(lhs.valueOf(), true); assert.strictEqual(result.valueOf(), false); }); }); describe('undefined', () => { it('undefined', () => { assert.isUndefined(assign(undefined, undefined)); }); }); describe('null', () => { it('null', () => { assert.isNull(assign(null, null)); }); }); describe('Object', () => { test.each([ [ {}, {}, {}, (obj: any) => { obj.foo = 'bar' } ], [ { 'a': 1, 'b': 2, 'c': 3 }, {}, {}, (obj: any) => { obj.foo = 'bar' } ], [ {}, { 'a': 1, 'b': 2, 'c': 3 }, { 'a': 1, 'b': 2, 'c': 3 }, (obj: any) => { delete obj.b } ], [ { 'a': 1, 'c': 3 }, { 'a': -1, 'b': -2, 'd': -4 }, { 'a': -1, 'b': -2, 'd': -4 }, (obj: any) => { delete obj.b } ], [ { 1: 'a', 2: 'b' }, { 1: 'b' }, { '1': 'b' }, (obj: any) => { obj[1] = 'c' } ], [ { p: { x: 1, y: 2 }, x: 2, foo: 'bar', a: [1, 'foo', { x: 2, y: 3 }] }, { p: { x: 2, y: 2 }, x: 3, a: [2, 'bar', { x: 2, y: 3 }] }, { p: { x: 2, y: 2 }, x: 3, a: [2, 'bar', { x: 2, y: 3 }] }, (obj: any) => { obj.p.x = -1; obj.a[0] = -1 } ] ])('Object#%#', (lhs: any, rhs: any, result: any, mutate: (obj: any) => void) => { assert.isTrue(assign(lhs, rhs) === lhs); assert.deepEqual(lhs, result); mutate(rhs); assert.deepEqual(lhs, result); }); }); describe('object', () => { test.each([ [ {}, {}, {}, (obj: any) => { obj.foo = 'bar' } ], [ { 'a': 1, 'b': 2, 'c': 3 }, {}, {}, (obj: any) => { obj.foo = 'bar' } ], [ {}, { 'a': 1, 'b': 2, 'c': 3 }, { 'a': 1, 'b': 2, 'c': 3 }, (obj: any) => { delete obj.b } ], [ { 'a': 1, 'c': 3 }, { 'a': -1, 'b': -2, 'd': -4 }, { 'a': -1, 'b': -2, 'd': -4 }, (obj: any) => { delete obj.b } ], [ { 1: 'a', 2: 'b' }, { 1: 'b' }, { '1': 'b' }, (obj: any) => { obj[1] = 'c' } ], [ { p: { x: 1, y: 2 }, x: 2, foo: 'bar', a: [1, 'foo', { x: 2, y: 3 }] }, { p: { x: 2, y: 2 }, x: 3, a: [2, 'bar', { x: 2, y: 3 }] }, { p: { x: 2, y: 2 }, x: 3, a: [2, 'bar', { x: 2, y: 3 }] }, (obj: any) => { obj.p.x = -1; obj.a[0] = -1 } ] ])('object#%#', (lhsValue: any, rhsValue: any, resultValue: any, mutate: (obj: any) => void) => { const lhs = object.assign(object.create(), lhsValue); const rhs = object.assign(object.create(), rhsValue); const result = object.assign(object.create(), resultValue); assert.isTrue(assign(lhs, rhs) === lhs); assert.deepEqual(lhs, result); mutate(rhs); assert.deepEqual(lhs, result); }); }); describe('function', () => { it('function', () => { function add(a: number, b: number) { return a + b; } function mul(a: number, b: number) { return a * b; } function div(a: number, b: number) { return a / b; } assert.strictEqual(assign(add, mul), mul); assert.strictEqual(assign(mul, div), div); assert.strictEqual(assign(div, add), add); }); }); describe('Date', () => { it('Date', () => { const now = Date.now(); const lhs = new Date(now - 100); const rhs = new Date(now + 100); const result = assign(lhs, rhs); assert.strictEqual(result, lhs); assert.strictEqual(lhs.getTime(), now + 100); }); }); describe('Array', () => { test.each([ [ [], [], [], (arr: any[]) => { arr.push(-1) } ], [ [1, 2, 3], [4, 5, 6], [4, 5, 6], (arr: any[]) => { arr[0] = -1 } ], [ [1, 2, 3], [], [], (arr: any[]) => { arr.push(-1) } ], [ [], [4, 5, 6], [4, 5, 6], (arr: any[]) => { arr[0] = -1 } ], [ [1, 'foo', { x: 1, y: 2 }], [2, 'bar', { x: 3, y: 4 }], [2, 'bar', { x: 3, y: 4 }], (arr: any[]) => { arr[2].x = -3 } ], [ [1, 'foo', { x: 1, y: 2 }], ['bar', 2, { x: 3, y: 4 }], ['bar', 2, { x: 3, y: 4 }], (arr: any[]) => { arr[2].x = -3 } ], [ [1, [2, 3]], [[1, 2], [], 3], [[1, 2], [], 3], (arr: any[]) => { arr[0][0] = -1 } ], ])('Array#%#', (lhs: any[], rhs: any[], result: any[], mutate: (arr: any[]) => void) => { assert.isTrue(assign(lhs, rhs) === lhs); assert.deepEqual(lhs, result); mutate(rhs); assert.deepEqual(lhs, result); }); }); describe('Map', () => { test.each([ [ [], [], [], (map: Map) => { map.set('foo', 'bar') } ], [ [['a', 1], ['b', 2], ['c', 3]], [], [], (map: Map) => { map.set('foo', 'bar') } ], [ [], [['a', 1], ['b', 2], ['c', 3]], [['a', 1], ['b', 2], ['c', 3]], (map: Map) => { map.delete('b') } ], [ [['a', 1], ['c', 3]], [['a', -1], ['b', -2], ['d', -4]], [['a', -1], ['b', -2], ['d', -4]], (map: Map) => { map.set('b', 2) } ], [ [[1, 'a'], [2, 'b']], [[1, 'a'], ['1', 'b']], [[1, 'a'], ['1', 'b']], (map: Map) => { map.set(1, 'z'); map.delete('1') } ], ])('Map#%#', (lhsValue: [any, any][], rhsValue: [any, any][], resultValue: [any, any][], mutate: (map: Map) => void) => { const lhs = new Map(lhsValue); const rhs = new Map(rhsValue); const result = new Map(resultValue); assert.isTrue(assign(lhs, rhs) === lhs); assert.deepEqual(lhs, result); mutate(rhs); assert.deepEqual(lhs, result); }); }); describe('Set', () => { test.each([ [ [], [], [], (set: Set) => { set.add('foo') } ], [ ['a', 'b', 'c'], [], [], (set: Set) => { set.add('foo') } ], [ [], ['a', 'b', 'c'], ['a', 'b', 'c'], (set: Set) => { set.delete('b') } ], [ ['a', 'b', 'c'], ['b', 'd'], ['b', 'd'], (set: Set) => { set.add('a') } ], [ ['b', 'd'], ['a', 'b', 'c'], ['a', 'b', 'c'], (set: Set) => { set.delete('b') } ], [ [1, '1', 2], [2, '2'], [2, '2'], (set: Set) => { set.delete(2) } ], ])('Set#%#', (lhsValue: any[], rhsValue: any[], resultValue: any[], mutate: (set: Set) => void) => { const lhs = new Set(lhsValue); const rhs = new Set(rhsValue); const result = new Set(resultValue); assert.isTrue(assign(lhs, rhs) === lhs); assert.deepEqual(lhs, result); mutate(rhs); assert.deepEqual(lhs, result); }); }); describe('TypedArrays', () => { describe('Uint8Array', () => { it('Uint8Array@sameSize', () => { const lhs = new Uint8Array([11, 21, 31]); const rhs = new Uint8Array([41, 51, 61]); assert.isTrue(assign(lhs, rhs) === lhs); assert.deepEqual(lhs, new Uint8Array([41, 51, 61])); }); it('Uint8Array@differentSize', () => { const lhs = new Uint8Array([11, 21, 31]); const rhs = new Uint8Array([41, 51, 61, 71]); const result = assign(lhs, rhs); assert.notStrictEqual(result, lhs); assert.instanceOf(result, Uint8Array); assert.deepEqual(result, new Uint8Array([41, 51, 61, 71])); }); it('Uint8Array@differentConstructor', () => { const lhs = new Uint8Array([11, 21, 31]); const rhs = new Int8Array([-41, -51, -61, -71]); const result = assign(lhs, rhs); assert.notStrictEqual(result, lhs); assert.instanceOf(result, Int8Array); assert.deepEqual(result, new Int8Array([-41, -51, -61, -71])); }); }); }); });