import { assert } from 'chai'; import { create, assign } from '../../../../../../lib/core/object'; import { MetaContext } from '../../../../../../lib/experimental/meta/MetaContext'; import { $CLONE, withClone } from '../../../../../../lib/experimental/meta/operations/base/$clone'; import cloneBuiltins from '../../../../../../lib/experimental/meta/operations/builtins/$clone'; import constructBuiltins from '../../../../../../lib/experimental/meta/operations/builtins/$construct'; const clone = (function () { const context = new (withClone(MetaContext))(); context.registerAll(cloneBuiltins).registerAll(constructBuiltins); return function clone(obj: T) { return context[$CLONE](obj); }; })(); describe('experimental.meta.operations.builtins.$clone', () => { describe('string', () => { it('string', () => { const origin = 'abc'; const cloned = clone(origin); assert.strictEqual(typeof cloned, 'string'); assert.strictEqual(cloned, 'abc'); }); }); describe('String', () => { it('String', () => { const origin = new String('abc'); const cloned = clone(origin); assert.instanceOf(cloned, String); assert.notStrictEqual(cloned, origin); assert.strictEqual(cloned.valueOf(), 'abc'); }); }); describe('number', () => { it('number', () => { const origin = 123; const cloned = clone(origin); assert.strictEqual(typeof cloned, 'number'); assert.strictEqual(cloned, 123); }); }); describe('Number', () => { it('Number', () => { const origin = new Number(123); const cloned = clone(origin); assert.instanceOf(cloned, Number); assert.notStrictEqual(cloned, origin); assert.strictEqual(cloned.valueOf(), 123); }); }); describe('boolean', () => { it('boolean', () => { const origin = true; const cloned = clone(origin); assert.strictEqual(typeof cloned, 'boolean'); assert.strictEqual(cloned, true); }); }); describe('Boolean', () => { it('Boolean', () => { const origin = new Boolean(true); const cloned = clone(origin); assert.instanceOf(cloned, Boolean); assert.notStrictEqual(cloned, origin); assert.strictEqual(cloned.valueOf(), true); }); }); describe('undefined', () => { it('undefined', () => { const origin = undefined; const cloned = clone(origin); assert.strictEqual(typeof cloned, 'undefined'); assert.strictEqual(cloned, undefined); }); }); describe('null', () => { it('null', () => { const origin = null; const cloned = clone(origin); assert.strictEqual(typeof cloned, 'object'); assert.strictEqual(cloned, null); }); }); describe('function', () => { it('function', () => { function add(a: number, b: number) { return a + b; } const cloned = clone(add); assert.strictEqual(cloned, add); assert.strictEqual(typeof cloned, 'function'); }); }); describe('Date', () => { it('Date', () => { const now = Date.now(); const origin = new Date(now); const cloned = clone(origin); assert.instanceOf(cloned, Date); assert.notStrictEqual(cloned, origin); assert.strictEqual(cloned.getTime(), now); origin.setTime(now - 100); assert.strictEqual(cloned.getTime(), now); }); }); describe('Array', () => { test.each([ [ [], [], (array: any[]) => { array.push(1); } ], [ [1, 2, 3], [1, 2, 3], (array: any[]) => { array.splice(1, 1); } ], [ [1, { x: 1, y: 2 }, [1, 2, 3], 'foo'], [1, { x: 1, y: 2 }, [1, 2, 3], 'foo'], (array: any[]) => { array[1].x = -1; array[2][0] = -1; } ], ])('Array#%#', (origin: any[], result: any[], mutate: (array: any[]) => void) => { const cloned = clone(origin); assert.instanceOf(cloned, Array); assert.notStrictEqual(cloned, origin); assert.deepEqual(cloned, result); mutate(cloned); assert.deepEqual(origin, result); }); }); describe('Object', () => { test.each([ [ {}, {}, (obj: any) => { obj.foo = 'bar'; } ], [ { a: 1, b: 2, c: 3 }, { a: 1, b: 2, c: 3 }, (obj: any) => { delete obj.a; obj.b = -2; } ], [ { p: { x: 1, y: 2 }, foo: 'bar', a: [1, 'foo', { x: 2, y: 3 }] }, { p: { x: 1, y: 2 }, foo: 'bar', a: [1, 'foo', { x: 2, y: 3 }] }, (obj: any) => { obj.a[0] = -1; obj.p.x = -1; } ], ])('Object#%#', (origin: any, result: any, mutate: (obj: any) => void) => { const cloned = clone(origin); assert.instanceOf(cloned, Object); assert.notStrictEqual(cloned, origin); assert.deepEqual(cloned, result); mutate(cloned); assert.deepEqual(origin, result); }); }); describe('object', () => { test.each([ [ {}, {}, (obj: any) => { obj.foo = 'bar'; } ], [ { a: 1, b: 2, c: 3 }, { a: 1, b: 2, c: 3 }, (obj: any) => { delete obj.a; obj.b = -2; } ], [ { p: { x: 1, y: 2 }, foo: 'bar', a: [1, 'foo', { x: 2, y: 3 }] }, { p: { x: 1, y: 2 }, foo: 'bar', a: [1, 'foo', { x: 2, y: 3 }] }, (obj: any) => { obj.a[0] = -1; obj.p.x = -1; } ], ])('object#%#', (originData: any, resultData: any, mutate: (obj: any) => void) => { const origin = assign(create(), originData); const result = assign(create(), resultData); const cloned = clone(origin); assert.strictEqual(typeof cloned, 'object'); assert.isUndefined(cloned.constructor); assert.notStrictEqual(cloned, origin); assert.deepEqual(cloned, result); mutate(cloned); assert.deepEqual(origin, result); }); }); describe('Map', () => { test.each([ [ [], [], (map: Map) => { map.set('foo', 'bar'); } ], [ [['a', 1], ['b', 2], ['c', 3]], [['a', 1], ['b', 2], ['c', 3]], (map: Map) => { map.set('d', 4); map.delete('b'); map.set('a', -1); } ], [ [['p1', { x: 1, y: 2 }]], [['p1', { x: 1, y: 2 }]], (map: Map) => { const p1 = map.get('p1'); p1.x = 3; p1.y = 4; } ] ])('Map#%#', (originData: [any, any][], resultData: [any, any][], mutate: (map: Map) => void) => { const origin = new Map(originData); const result = new Map(resultData); const cloned = clone(origin); assert.instanceOf(cloned, Map); assert.notStrictEqual(cloned, origin); assert.deepEqual(cloned, result); mutate(origin); assert.deepEqual(cloned, result); }); it('Map#complexKey', () => { const p1 = { x: 1, y: 2 }; const origin = new Map([[p1, 3]]); const cloned = clone(origin); assert.instanceOf(cloned, Map); assert.notStrictEqual(cloned, origin); assert.deepEqual([...cloned], [[{ x: 1, y: 2 }, 3]]); origin.set(p1, 7); p1.x = 3; p1.y = 4; assert.deepEqual([...cloned], [[{ x: 1, y: 2 }, 3]]); }); }); describe('Set', () => { test.each([ [ [], [], (set: Set) => { set.add('foo'); } ], [ ['a', 'b', 'c'], ['a', 'b', 'c'], (set: Set) => { set.add('d'); set.delete('b'); } ], [ ['1', 1, '2'], ['1', 1, '2'], (set: Set) => { set.add(2); set.delete(1); } ] ])('Set#%#', (originData: any[], resultData: any[], mutate: (set: Set) => void) => { const origin = new Set(originData); const result = new Set(resultData); const cloned = clone(origin); assert.instanceOf(cloned, Set); assert.notStrictEqual(cloned, origin); assert.deepEqual(cloned, result); mutate(origin); assert.deepEqual(cloned, result); }); it('Set#complexKey', () => { const p1 = { x: 1, y: 2 }; const p2 = { x: 3, y: 4 }; const origin = new Set([p1]); const cloned = clone(origin); assert.instanceOf(cloned, Set); assert.notStrictEqual(cloned, origin); assert.deepEqual([...cloned], [{ x: 1, y: 2 }]); origin.add(p2); p1.x = 3; p1.y = 4; assert.deepEqual([...cloned], [{ x: 1, y: 2 }]); }); }); describe('TypedArrays', () => { describe('Uint8Array', () => { it('Uint8Array', () => { const origin = new Uint8Array([11, 21, 31]); const cloned = clone(origin); assert.instanceOf(cloned, Uint8Array); assert.notStrictEqual(cloned, origin); assert.deepEqual(cloned, new Uint8Array([11, 21, 31])); origin[0] = 41; assert.deepEqual(cloned, new Uint8Array([11, 21, 31])); }); }); }); });