import { assert } from 'chai'; import { isIterable } from '../../../../lib/core/traits'; import { has } from '../../../../lib/core/object'; import { FastMap } from '../../../../lib/experimental/containers/FastMap'; describe('experimental.containers.FastMap', () => { describe('constructor', () => { it('null data', () => { assert.doesNotThrow(() => { const map = new FastMap(null); }); }); it('undefined data', () => { assert.doesNotThrow(() => { const map = new FastMap(undefined); }); }); it('empty data', () => { assert.doesNotThrow(() => { const map = new FastMap([]); }); }); it('iterable', () => { const map = new FastMap([[1, 'a'], [2, 'b'], [3, 'c']]); assert.deepEqual([...map.entries()], [['1', 'a'], ['2', 'b'], ['3', 'c']]); }); it('array-like', () => { const map = new FastMap({ 0: [1, 'a'], 1: [2, 'b'], 2: [3, 'c'], length: 3 }); assert.deepEqual([...map.entries()], [['1', 'a'], ['2', 'b'], ['3', 'c']]); }); }); describe('clear', () => { it('empty map', () => { const map = new FastMap(); assert.doesNotThrow(() => { map.clear(); }); }); it('non-empty map', () => { const map = new FastMap([ [3, 'abc'] ]); map.clear(); assert.isFalse(map.has(3)); assert.strictEqual(map.size, 0); }); }); describe('delete', () => { let map: FastMap; beforeEach(() => { map = new FastMap([ [3, 'abc'], [4, 'def'] ]); }); it('key found', () => { assert.isTrue(map.delete(3)); assert.isUndefined(map.get(3)); assert.strictEqual(map.size, 1); assert.strictEqual(map.get(4), 'def', 'Remaining key should not be affected by delete'); }) it('key not found', () => { assert.isFalse(map.delete('foo')); }); }); it('entries', () => { function foo() { } const array: any[] = []; const object = Object.create(null); const mapArgs: [number, any][] = [ [0, 0], [1, '1'], [2, object], [3, array], [4, foo], [5, undefined] ]; const map = new FastMap(mapArgs); const entries = map.entries(); assert.isTrue(isIterable(entries), 'Returns an iterable.'); let i = 0; for (const value of entries) { assert.equal(value[0], mapArgs[i][0]); assert.equal(value[1], mapArgs[i][1]); i++; } }); it('Symbol.iterator', () => { function foo() { } const array: any[] = []; const object = Object.create(null); const mapArgs: [number, any][] = [ [0, 0], [1, '1'], [2, object], [3, array], [4, foo], [5, undefined] ]; const map = new FastMap(mapArgs); const iterator = map[Symbol.iterator](); assert.isTrue(isIterable(iterator), 'Returns an iterable.'); let i = 0; for (let next = iterator.next(); !next.done; next = iterator.next()) { const value = next.value; assert.equal(value[0], mapArgs[i][0]); assert.equal(value[1], mapArgs[i][1]); i++; } }); describe('forEach', () => { let mapArgs: any[]; let map: FastMap; beforeEach(() => { function foo() { } const object = Object.create(null); const array: any[] = []; mapArgs = [ [0, 0], [1, '1'], [2, object], [3, array], [4, foo], [5, undefined] ]; map = new FastMap(mapArgs); }); it('callback arguments', () => { map.forEach(function (value, key, mapInstance) { assert.lengthOf(arguments, 3); assert.strictEqual(map.get(key), value); assert.strictEqual(map, mapInstance); }); }); it('times executed', () => { let counter = 0; map.forEach(function () { counter++; }); assert.strictEqual(counter, mapArgs.length); }); }); describe('get', () => { let map: FastMap; beforeEach(() => { map = new FastMap([ [0, 'a'], [8, 'b'], [NaN, 'c'] ]); }); it('key found', () => { assert.strictEqual(map.get(0), 'a'); assert.strictEqual(map.get(8), 'b'); assert.strictEqual(map.get(NaN), 'c', 'Map should successfully retrieve an item with a key of NaN'); }); it('key not found', () => { assert.isUndefined(map.get(3)); }); }); describe('has', () => { let map: FastMap; beforeEach(() => { map = new FastMap([ [3, 'abc'] ]); }); it('key found', () => { assert.isTrue(map.has(3)); }); it('key not found', () => { assert.isFalse(map.has(0)); }); }); it('keys', () => { const mapArgs = '012345'.split('').map((value: string) => { const numeric = Number(value); return [numeric, numeric] as [number, number]; }); const map = new FastMap(mapArgs); const keys: IterableIterator = map.keys(); assert.isTrue(isIterable(keys), 'Returns an iterable.'); let i = 0; for (const value of keys) { assert.equal(value, mapArgs[i][0]); i++; } }); describe('set', () => { it('number key', () => { const map = new FastMap(); map.set(1, 'abc'); assert.strictEqual(map.get(1), 'abc'); }); it('string key', () => { const map = new FastMap(); map.set('foo', 'bar'); assert.strictEqual(map.get('foo'), 'bar'); }); it('returns instance', () => { const map = new FastMap(); assert.instanceOf(map.set('foo', 'bar'), FastMap); assert.strictEqual(map.set('foo', 'bar'), map); }); it('key exists', () => { const map = new FastMap([[3, 'abc']]); map.set(3, 'def'); assert.strictEqual(map.get(3), 'def'); }); it('size updates', () => { const map = new FastMap(); assert.strictEqual(map.size, 0); map.set('foo', 'bar'); assert.strictEqual(map.size, 1, 'size should increase after setting a new key'); map.set('foo', 'baz'); assert.strictEqual(map.size, 1, 'size should remain the same after setting an existing key'); }); }); it('values', () => { function foo() { } const array: any[] = []; const object = Object.create(null); const mapArgs: [number, any][] = [ [0, 0], [1, '1'], [2, object], [3, array], [4, foo], [5, undefined] ]; const map = new FastMap(mapArgs); const values: IterableIterator = map.values(); assert.isTrue(isIterable(values), 'Returns an iterable.'); let i = 0; for (const value of values) { assert.strictEqual(value, mapArgs[i][1]); i++; } }); it('reset', () => { const map = new FastMap(); const objectLike = Object.create({ foo: 'bar' }); objectLike[1] = 'a'; objectLike[2] = 'b'; map.reset(objectLike); assert.strictEqual(map.size, 2); for (const key in objectLike) { if (has(objectLike, key)) { assert.isTrue(map.has(key)); assert.strictEqual(map.get(key), (objectLike)[key]); } } map.reset(); assert.strictEqual(map.size, 0); for (const key in objectLike) { assert.isFalse(map.has(key)); assert.isUndefined(map.get(key)); } }); });