import { assert } from 'chai'; import { create, assign } from '../../../../../../lib/core/object'; import { hashString, hashNumber } from '../../../../../../lib/functional/hash/murmurhash'; import { MetaContext, $CONSTRUCTOR, $NAME } from '../../../../../../lib/experimental/meta/MetaContext'; import { $HASH, withHash } from '../../../../../../lib/experimental/meta/operations/base/$hash'; import { withRegisterFunction } from '../../../../../../lib/experimental/meta/extensions/registerFunction'; import builtins from '../../../../../../lib/experimental/meta/operations/builtins/$hash'; const hash = (function () { const context = new (withRegisterFunction(withHash(class extends MetaContext { hashString(str: string, seed?: number) { return hashString(str, seed); } hashNumber(num: number, seed?: number) { return hashNumber(num, seed); } })))(); context.registerAll(builtins); function hash(obj: T, seed?: number) { return context[$HASH](obj, seed); } hash.registerFunction = function (props: any) { return context.registerFunction(props); }; return hash; })(); describe('experimental.meta.operations.builtins.$hash', () => { describe('string', () => { test.each([ ['', 0, undefined], ['bar', 4052775749, undefined], ['', 2235285516, 123, undefined], ['bar', 3111968405, 11], ['привет', 3528813053, undefined], ['привет', 3497499214, 11], ])('string#%#', (str: string, result: number, seed?: number) => { assert.strictEqual(hash(str, seed), result); }); }); describe('String', () => { test.each([ ['', 0, undefined], ['bar', 4052775749, undefined], ['bar', 3111968405, 11], ])('String#%#', (str: string, result: number, seed?: number) => { const strObject = new String(str); assert.strictEqual(hash(strObject, seed), result); }); }); describe('number', () => { test.each([ [0, 593689054, undefined], [0, 4187786506, 11], [10000000, 443691621, undefined], [10000000, 2904093579, 11], [3.14159, 3628459545, undefined], ])('number#%#', (num: number, result: number, seed: number) => { assert.strictEqual(hash(num, seed), result); }); }); describe('Number', () => { test.each([ [0, 593689054, undefined], [0, 4187786506, 11], [10000000, 443691621, undefined], [10000000, 2904093579, 11], [3.14159, 3628459545, undefined], ['10000000', 443691621, undefined], ])('Number#%#', (num: number, result: number, seed: number) => { const numObject = new Number(num); assert.strictEqual(hash(numObject, seed), result); }); }); describe('boolean', () => { test.each([ [false, 593689054, undefined], [false, 4187786506, 11], [true, 4226891818, undefined], [true, 3314192471, 11], ])('boolean#%#', (bool: boolean, result: number, seed: number) => { assert.strictEqual(hash(bool, seed), result); }); }); describe('Boolean', () => { test.each([ [false, 593689054, undefined], [false, 4187786506, 11], [true, 4226891818, undefined], [true, 3314192471, 11], ])('Boolean#%#', (bool: boolean, result: number, seed: number) => { const boolObject = new Boolean(bool); assert.strictEqual(hash(boolObject, seed), result); }); }); describe('undefined', () => { it('undefined', () => { assert.strictEqual(hash(undefined), hashNumber(NaN, hashNumber(hashString('undefined')))); assert.strictEqual(hash(undefined, 11), hashNumber(NaN, hashNumber(hashString('undefined'), 11))); }); }); describe('null', () => { it('null', () => { assert.strictEqual(hash(null), hashNumber(0, hashNumber(hashString('null')))); assert.strictEqual(hash(null, 11), hashNumber(0, hashNumber(hashString('null'), 11))); }); }); describe('Object', () => { test.each([ [{}, 0, undefined], [{}, 17, 17], [{ 'foo': 9999999 }, 4119663905, undefined], [{ 'foo': 9999999 }, 4119663922, 17], [{ 'bar': 'buzz', 'foo': 9999999 }, 2552052805, undefined], [{ 'bar': 'buzz', 'foo': 9999999 }, 2552052822, 17], [{ 'foo': 9999999, 'bar': 'buzz' }, 2552052805, undefined], [{ 1: 'a', 2: 'b', 3: 'c' }, 3575257542, undefined], [{ '1': 'a', '2': 'b', '3': 'c' }, 3575257542, undefined], [{ 'foo': {} }, 2085578581, undefined], [{ 'foo': { 'bar': [1, 2, 3] } }, 4231115123, undefined], [{ 'foo': { 'foo': 9999999 } }, 1910275190, undefined], [{ x: 1, y: 2 }, 2914345399, undefined], ])('Object#%#', (obj: any, result: number, seed: number) => { assert.strictEqual(hash(obj, seed), result); }); }); describe('object', () => { test.each([ [{}, 0, undefined], [{}, 17, 17], [{ 'foo': 9999999 }, 4119663905, undefined], [{ 'foo': 9999999 }, 4119663922, 17], [{ 'bar': 'buzz', 'foo': 9999999 }, 2552052805, undefined], [{ 'bar': 'buzz', 'foo': 9999999 }, 2552052822, 17], [{ 'foo': 9999999, 'bar': 'buzz' }, 2552052805, undefined], [{ 1: 'a', 2: 'b', 3: 'c' }, 3575257542, undefined], [{ '1': 'a', '2': 'b', '3': 'c' }, 3575257542, undefined], [{ 'foo': {} }, 2085578581, undefined], [{ 'foo': { 'bar': [1, 2, 3] } }, 4231115123, undefined], [{ 'foo': { 'foo': 9999999 } }, 1910275190, undefined], [{ x: 1, y: 2 }, 2914345399, undefined], ])('object#%#', (obj: any, result: number, seed: number) => { const objLike = assign(create(), obj); assert.strictEqual(hash(objLike, seed), result); }); }); describe('function', () => { it('function', () => { function add(a: number, b: number) { return a + b; } function mul(a: number, b: number) { return a * b; } hash.registerFunction({ [$CONSTRUCTOR]: add, [$NAME]: 'add' }); assert.throws(() => { hash(mul); }); assert.strictEqual(hash(add), hashNumber(hashString('add'))); assert.strictEqual(hash(add, 11), hashNumber(hashString('add'), 11)); }); }); describe('Date', () => { function hashDate(value: number, seed?: number) { return hashNumber(value, seed); } const now = Date.now(); [ [new Date(now), hashDate(now)], [new Date(now), hashDate(now, 11), 11], [new Date(2014, 1, 1), hashDate(new Date(2014, 1, 1).getTime())], [new Date(2014, 1, 1), hashDate(new Date(2014, 1, 1).getTime(), 11), 11], ].forEach((data, index) => { it('Date#%#', () => { const date = data[0] as Date; const result = data[1] as number; const seed = data[2] as number; assert.strictEqual(hash(date, seed), result); }); }); }); describe('Array', () => { test.each([ [[], 0, undefined], [[], 17, 17], [[[]], 0, undefined], [[[], []], 0, undefined], [[[]], 17, 17], [[[], []], 17, 17], [[0], 593689054, undefined], [[0, 0], 4055028242, undefined], [[1, 2], 1685970547, undefined], [[1, 2], 914414596, 17], [[2, 1], 1539031307, undefined], [[9999999, 3.14159], 1643123411, undefined], [[0, '0'], 112781474, undefined], [[9999999, 3.14159], 856280047, 17], [['foo', 9999999], 4119663905, undefined], [['foo', 4119663905], 2961722703, undefined], [[['foo', 9999999]], 4119663905, undefined], [[['bar', 'buzz'], ['foo', 9999999]], 3401676449, undefined], [[['bar', 'buzz'], ['foo', 9999999]], 3440063179, 17], [[{}], 0, undefined], [[{ x: 1, y: 2 }], 2914345399, undefined], [[{ y: 2, x: 1 }], 2914345399, undefined], [[[1, 2]], 1685970547, undefined], [[['x', 1], ['y', 2]], 125941314, undefined], [[['y', 2], ['x', 1]], 2835642552, undefined], [['b', 'a', 'r'], 1494586500, undefined], [['bar'], 4052775749, undefined], ])('Array#%#', (array: any[], result: number, seed: number) => { assert.strictEqual(hash(array, seed), result); }); }); describe('Map', () => { test.each([ [[], 0, undefined], [[], 17, 17], [[['foo', 9999999]], 4119663905, undefined], [[['foo', 9999999]], 4119663922, 17], [[['bar', 'buzz'], ['foo', 9999999]], 2552052805, undefined], [[['bar', 'buzz'], ['foo', 9999999]], 2552052822, 17], [[['foo', 9999999], ['bar', 'buzz']], 2552052805, undefined], [[[1, 'a'], [2, 'b'], [3, 'c']], 1484802550, undefined], [[['1', 'a'], ['2', 'b'], ['3', 'c']], 3575257542, undefined], [[['foo', {}]], 2085578581, undefined], [[['foo', { 'foo': 9999999 }]], 1910275190, undefined], [[[{ x: 1, y: 2 }, 3], [{ x: 3, y: 4 }, 7]], 4026855232, undefined], [[[{ x: 3, y: 4 }, 7], [{ x: 1, y: 2 }, 3]], 4026855232, undefined], ])('Map#%#', (entries: [any, any][], result: number, seed?: number) => { const map = new Map(entries); assert.strictEqual(hash(map, seed), result); }); }); describe('Set', () => { test.each([ [[], 0, undefined], [[], 17, 17], [[1, 2], 1017346985, undefined], [[2, 1], 1017346985, undefined], [[1, 2], 1017347002, 17], [[2, 1], 1017347002, 17], [['1', '2'], 3864804486, undefined], [['2', '1'], 3864804486, undefined], [['1', 2], 959186866, undefined], [[2, '1'], 959186866, undefined], [[1, '2'], 3922964605, undefined], [['2', 1], 3922964605, undefined], [['foo', 'bar', 'buzz'], 3478197631, undefined], [['buzz', 'foo', 'bar'], 3478197631, undefined], [['bar', 'buzz', 'foo'], 3478197631, undefined], [[{}], 0, undefined], [[{ x: 1, y: 2 }], 2914345399, undefined], [[{ x: 1, y: 2 }, [1, 2, 3]], 3402286478, undefined], ])('Set#%#', (entries: any[], result: number, seed?: number) => { const set = new Set(entries); assert.strictEqual(hash(set, seed), result); }); }); describe('TypedArray', () => { describe('Uint8Array', () => { test.each([ [[], 0, undefined], [[], 11, 11], [[11, 21, 31], 143615334, undefined], [[11, 21, 31], 542101056, 11], ])('Uint8Array#%#', (values: number[], result: number, seed?: number) => { const arr = new Uint8Array(values); assert.strictEqual(hash(arr, seed), result); }); }); }); });