import { assert } from 'chai'; import { create, assign } from '../../../../../../lib/core/object'; import { MetaContext, $CONSTRUCTOR, $NAME } from '../../../../../../lib/experimental/meta/MetaContext'; import { $DUMP, withDump } from '../../../../../../lib/experimental/meta/operations/base/$dump'; import { withRegisterClass } from '../../../../../../lib/experimental/meta/extensions/registerClass'; import { withRegisterFunction } from '../../../../../../lib/experimental/meta/extensions/registerFunction'; import builtins from '../../../../../../lib/experimental/meta/operations/builtins/$dump'; const dump = (function () { const context = new (withRegisterFunction(withRegisterClass(withDump(MetaContext))))(); context.registerAll(builtins); function dump(obj: T) { return context[$DUMP](obj); }; dump.registerClass = function (props: any) { return context.registerClass(props); }; dump.registerFunction = function (props: any) { return context.registerFunction(props); }; return dump; })(); describe('experimental.meta.operations.builtins.$dump', () => { describe('string', () => { it('string', () => { const value = 'abc'; const state = dump(value); assert.strictEqual(typeof state, 'string'); assert.strictEqual(state, 'abc'); }); }); describe('String', () => { it('String', () => { const value = new String('abc'); const state = dump(value); assert.deepEqual(state, 'abc'); }); }); describe('number', () => { it('number', () => { const value = 123; const state = dump(value); assert.strictEqual(typeof state, 'number'); assert.strictEqual(state, 123); }); }); describe('Number', () => { it('Number', () => { const value = new Number(123); const state = dump(value); assert.deepEqual(state, 123); }); }); describe('boolean', () => { it('boolean', () => { const value = true; const state = dump(value); assert.strictEqual(typeof state, 'boolean'); assert.strictEqual(state, true); }); }); describe('Boolean', () => { it('Boolean', () => { const value = new Boolean(true); const state = dump(value); assert.deepEqual(state, true); }); }); describe('undefined', () => { it('undefined', () => { const value = undefined; const state = dump(value); assert.deepEqual(state, {}); }); }); describe('null', () => { it('null', () => { const value = null; const state = dump(value); assert.strictEqual(typeof state, 'object'); assert.strictEqual(state, null); }); }); 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; } ], [ { 1: 'a' }, { '1': 'a' }, (obj: any) => { obj.foo = 'bar'; } ], [ { p: { x: 1, y: 2 }, foo: 'bar', a: [1, 2, 3] }, { p: { x: 1, y: 2 }, foo: 'bar', a: [1, 2, 3] }, (obj: any) => { obj.p.x = -1; obj.a[0] = -1; } ], ])('Object#%#', (obj: any, result: any, mutate: (obj: any) => void) => { const state = dump(obj); assert.deepEqual(state, result); mutate(obj); assert.deepEqual(state, 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; } ], [ { 1: 'a' }, { '1': 'a' }, (obj: any) => { obj.foo = 'bar'; } ], [ { p: { x: 1, y: 2 }, foo: 'bar', a: [1, 2, 3] }, { p: { x: 1, y: 2 }, foo: 'bar', a: [1, 2, 3] }, (obj: any) => { obj.p.x = -1; obj.a[0] = -1; } ], ])('object#%#', (objData: any, result: any, mutate: (obj: any) => void) => { const obj = assign(create(), objData); const state = dump(obj); assert.deepEqual(state, result); mutate(obj); assert.deepEqual(state, result); }); }); describe('function', () => { it('function', () => { function add(a: number, b: number) { return a + b; } function mul(a: number, b: number) { return a * b; } dump.registerFunction({ [$CONSTRUCTOR]: add, [$NAME]: 'add' }); assert.deepEqual(dump(mul), {}); assert.deepEqual(dump(add), {}); }); }); describe('Date', () => { it('Date', () => { const now = Date.now(); const date = new Date(now); const state = dump(date); assert.deepEqual(state, now); date.setTime(now - 100); assert.deepEqual(state, now); }); }); describe('Array', () => { test.each([ [ [], [], (array: any[]) => { array.push(1); } ], [ [1, 2, 3], [1, 2, 3], (array: any[]) => { array.splice(1, 1); } ], [ [1, '2', 3], [1, '2', 3], (array: any[]) => { array.splice(1, 1); } ], [ [1, 'foo', [1, 2, 3], { x: 1, y: 2 }], [1, 'foo', [1, 2, 3], { x: 1, y: 2 }], (array: any[]) => { array[2][0] = -1; array[3].x = -1; } ], ])('Array#%#', (array: any[], result: any, mutate: (array: any[]) => void) => { const state = dump(array); assert.deepEqual(state, result); mutate(array); assert.deepEqual(state, 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); } ], [ [[1, 'a'], ['1', 'b']], [[1, 'a'], ['1', 'b']], (map: Map) => { map.set('2', 'c'); map.delete(1); } ], [ [['p', { x: 1, y: 2 }], ['foo', 'bar'], ['v', [1, 2, 3]]], [['p', { x: 1, y: 2 }], ['foo', 'bar'], ['v', [1, 2, 3]]], (map: Map) => { const p1 = map.get('p'); p1.x = 3; p1.y = 4; } ], [ [[{ x: 1, y: 2 }, 3], [[1, 2, 3], 6]], [[{ x: 1, y: 2 }, 3], [[1, 2, 3], 6]], (map: Map) => { const keys = [...map.keys()]; keys[0].x = -3; keys[0].y = -2; } ], ])('Map#%#', (mapData: [any, any][], result: [any, any][], mutate: (map: Map) => void) => { const map = new Map(mapData); const state = dump(map); assert.deepEqual(state, result); mutate(map); assert.deepEqual(state, result); }); }); 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'); } ], [ [{ x: 1, y: 2 }, 'foo', [1, 2, 3]], [{ x: 1, y: 2 }, 'foo', [1, 2, 3]], (set: Set) => { const values = [...set.values()]; values[0].x = -1; values[0].y = -2; } ], ])('Set#%#', (setData: any[], result: any[], mutate: (set: Set) => void) => { const set = new Set(setData); const state = dump(set); assert.deepEqual(state, result); mutate(set); assert.deepEqual(state, result); }); }); describe('TypedArrays', () => { describe('Uint8Array', () => { test.each([ [ [], [], (_: Uint8Array) => { } ], [ [11, 21, 31], [11, 21, 31], (array: Uint8Array) => { array[0] = 41; } ] ])('Uint8Array#%#', (arrayData: number[], result: number[], mutate: (array: Uint8Array) => void) => { const array = new Uint8Array(arrayData); const state = dump(array); assert.deepEqual(state, result); mutate(array); assert.deepEqual(state, result); }); }); }); describe('class', () => { class Point { constructor(public x = 0, public y = 0) { } } class Polygon { constructor(public points: Point[] = []) { } } class Triangle extends Polygon { constructor(p1: Point, p2: Point, p3: Point, public color = 'black') { super([p1, p2, p3]); } } dump.registerClass({ [$CONSTRUCTOR]: Point, [$NAME]: 'Point' }); dump.registerClass({ [$CONSTRUCTOR]: Polygon, [$NAME]: 'Polygon' }); dump.registerClass({ [$CONSTRUCTOR]: Triangle, [$NAME]: 'Triangle' }); describe('Point', () => { test.each([ [ new Point(), { x: 0, y: 0 }, (_: Point) => { } ], [ new Point(1, 2), { x: 1, y: 2 }, (p: Point) => { p.x = -1; p.y = -2; } ] ])('Point#%#', (point: Point, result: any, mutate: (point: Point) => void) => { const state = dump(point); assert.deepEqual(state, result); mutate(point); assert.deepEqual(state, result); }); }); describe('Polygon', () => { test.each([ [ new Polygon(), { points: [] }, (_: Polygon) => { } ], [ new Polygon([new Point(1, 2), new Point(2, 3), new Point(3, 1)]), { points: [{ x: 1, y: 2 }, { x: 2, y: 3 }, { x: 3, y: 1 }] }, (p: Polygon) => { p.points[0].x = -1; p.points[0].y = -2; p.points.splice(1, 1); } ] ])('Polygon#%#', (poly: Polygon, result: any, mutate: (poly: Polygon) => void) => { const state = dump(poly); assert.deepEqual(state, result); mutate(poly); assert.deepEqual(state, result); }); }); describe('Triangle', () => { test.each([ [ new Triangle(new Point(1, 2), new Point(2, 3), new Point(3, 1), 'red'), { points: [{ x: 1, y: 2 }, { x: 2, y: 3 }, { x: 3, y: 1 }], color: 'red' }, (p: Triangle) => { p.points[0].x = -1; p.points[0].y = -2; p.points.splice(1, 1); } ] ])('Triangle#%#', (tri: Triangle, result: any, mutate: (tri: Triangle) => void) => { const state = dump(tri); assert.deepEqual(state, result); mutate(tri); assert.deepEqual(state, result); }); }); }); });