rubico
Version:
[a]synchronous functional programming
238 lines (211 loc) • 8.84 kB
JavaScript
const assert = require('assert')
const Struct = require('./Struct')
describe('Struct', () => {
describe('new Struct(x Array|Object|Set|Map) -> Struct', () => {
it('x Array; Struct', async () => {
assert.equal(new Struct([1, 2, 3]).constructor, Struct)
})
it('x Object; Struct', async () => {
assert.equal(new Struct({ a: 1, b: 2, c: 3 }).constructor, Struct)
})
it('x Set; Struct', async () => {
assert.equal(new Struct(new Set([1, 2, 3])).constructor, Struct)
})
it('x Map; Struct', async () => {
assert.equal(new Struct(new Map([['a', 1], ['b', 2], ['c', 3]])).constructor, Struct)
})
it('x string; TypeError', async () => {
assert.throws(
() => new Struct('hey'),
new TypeError('cannot convert hey to Struct')
)
})
it('x null; TypeError', async () => {
assert.throws(
() => new Struct(null),
new TypeError('cannot convert null to Struct')
)
})
it('x undefined; TypeError', async () => {
assert.throws(
() => new Struct(undefined),
new TypeError('cannot convert undefined to Struct')
)
})
})
describe('Struct.isStruct(x any) -> boolean', () => {
it('x Array; true', async () => {
assert.equal(Struct.isStruct([]), true)
})
it('x Object; true', async () => {
assert.equal(Struct.isStruct({}), true)
})
it('x Set; true', async () => {
assert.equal(Struct.isStruct(new Set()), true)
})
it('x Map; true', async () => {
assert.equal(Struct.isStruct(new Map()), true)
})
it('x ArrayBuffer; false', async () => {
assert.equal(Struct.isStruct(new ArrayBuffer()), false)
})
it('x Number; false', async () => {
assert.equal(Struct.isStruct(1), false)
})
it('x String; false', async () => {
assert.equal(Struct.isStruct('hey'), false)
})
})
const nativeObjectToString = Object.prototype.toString
const objectToString = x => nativeObjectToString.call(x)
it('<T any>Struct.entries(x Array<T>) -> Iterator<[index number, T]>', async () => {
assert.equal(objectToString(Struct.entries([1, 2, 3])), '[object Array Iterator]')
assert.deepEqual([...Struct.entries([1, 2, 3])], [[0, 1], [1, 2], [2, 3]])
})
it('<T any>Struct.entries(x Object<T>) -> Iterator<[key string, T]>', async () => {
assert.equal(objectToString(Struct.entries({ a: 1, b: 2, c: 3 })), '[object Generator]')
assert.deepEqual([...Struct.entries({ a: 1, b: 2, c: 3 })], [['a', 1], ['b', 2], ['c', 3]])
})
it('<T any>Struct.entries(x Set<T>) -> Iterator<[T, T]>', async () => {
assert.equal(objectToString(Struct.entries(new Set([1, 2, 3]))), '[object Set Iterator]')
assert.deepEqual([...Struct.entries(new Set([1, 2, 3]))], [[1, 1], [2, 2], [3, 3]])
})
it('<A any, B any>Struct.entries(x Map<A, B>) -> Iterator<[A, B]>', async () => {
assert.equal(objectToString(Struct.entries(new Map([[1, 'a'], [2, 'b'], [3, 'c']]))), '[object Map Iterator]')
assert.deepEqual([...Struct.entries(new Map([[1, 'a'], [2, 'b'], [3, 'c']]))], [[1, 'a'], [2, 'b'], [3, 'c']])
})
describe('<T any>Struct.values(x Array<T>|Object<T>|Set<T>|Map<any, T>) -> Iterator<T>', () => {
it('x Array<T>; Iterator<T>', async () => {
assert.equal(objectToString(Struct.values([1, 2, 3])), '[object Array Iterator]')
assert.deepEqual([...Struct.values([1, 2, 3])], [1, 2, 3])
})
it('x Object<T>; Iterator<T>', async () => {
assert.equal(objectToString(Struct.values({ a: 1, b: 2, c: 3 })), '[object Generator]')
assert.deepEqual([...Struct.values({ a: 1, b: 2, c: 3 })], [1, 2, 3])
})
it('x Set<T>; Iterator<T>', async () => {
assert.equal(objectToString(Struct.values(new Set([1, 2, 3]))), '[object Set Iterator]')
assert.deepEqual([...Struct.values(new Set([1, 2, 3]))], [1, 2, 3])
})
it('x Map<T>; Iterator<T>', async () => {
assert.equal(objectToString(Struct.values(new Map([[1, 'a'], [2, 'b'], [3, 'c']]))), '[object Map Iterator]')
assert.deepEqual([...Struct.values(new Map([[1, 'a'], [2, 'b'], [3, 'c']]))], ['a', 'b', 'c'])
})
})
it('<T any>Struct.get(x Array<T>, index number) -> T|undefined', async () => {
assert.equal(Struct.get([1, 2, 3], 0), 1)
assert.strictEqual(Struct.get([1, 2, 3], 4), undefined)
})
it('<T any>Struct.get(x Object<T>, index string) -> T|undefined', async () => {
assert.equal(Struct.get({ a: 1, b: 2, c: 3 }, 'a'), 1)
assert.strictEqual(Struct.get({ a: 1, b: 2, c: 3 }, 'e'), undefined)
})
it('<T any>Struct.get(x Set<T>, index T) -> T|undefined', async () => {
assert.equal(Struct.get(new Set([1, 2, 3]), 1), 1)
assert.strictEqual(Struct.get(new Set([1, 2, 3]), 5), undefined)
})
it('<A any, B any>Struct.get(x Map<A, B>, index A) -> B|undefined', async () => {
const m = new Map([[1, 'a'], [2, 'b'], [3, 'c']])
assert.equal(Struct.get(m, 1), 'a')
assert.strictEqual(Struct.get(m, 5), undefined)
})
it('Struct.set(x Array, value any, index number) -> mutated Array', async () => {
const arr = [1, 2]
assert.deepEqual(Struct.set(arr, 3, 2), [1, 2, 3])
})
it('Struct.set(x Object, value any, index string) -> mutated Object', async () => {
const obj = { a: 1, b: 2 }
assert.deepEqual(Struct.set(obj, 3, 'c'), { a: 1, b: 2, c: 3 })
})
it('Struct.set(x Set, value any) -> mutated Set', async () => {
const set = new Set([1, 2])
assert.deepEqual(Struct.set(set, 3), new Set([1, 2, 3]))
})
it('Struct.set(x Map, value any, index any) -> mutated Map', async () => {
const map = new Map([['a', 1], ['b', 2]])
assert.deepEqual(Struct.set(map, 3, 'c'), new Map([['a', 1], ['b', 2], ['c', 3]]))
})
describe('Struct.size(x Array|Object|Set|Map) -> y number', () => {
it('x [1, 2, 3]; y 3', async () => {
assert.strictEqual(Struct.size([1, 2, 3]), 3)
})
it('x []; y 0', async () => {
assert.strictEqual(Struct.size([]), 0)
})
it('x { a: 1, b: 2, c: 3 }; y 3', async () => {
assert.strictEqual(Struct.size({ a: 1, b: 2, c: 3 }), 3)
})
it('x {}; y 0', async () => {
assert.strictEqual(Struct.size({}), 0)
})
it('x Set<[1, 2, 3]>; y 3', async () => {
assert.strictEqual(Struct.size(new Set([1, 2, 3])), 3)
})
it('x Set<[]>; y 0', async () => {
assert.strictEqual(Struct.size(new Set()), 0)
})
it('x Map<[[\'a\', 1], [\'b\', 2], [\'c\', 3]]>; y 3', async () => {
assert.strictEqual(Struct.size(new Map([['a', 1], ['b', 2], ['c', 3]])), 3)
})
it('x Map<[]>; y 0', async () => {
assert.strictEqual(Struct.size(new Map()), 0)
})
})
it('Struct.copy(x Array) -> copied Array', async () => {
const arr = [1, 2, 3]
const copied = Struct.copy(arr)
assert(copied !== arr)
assert.deepEqual(arr, copied)
})
it('Struct.copy(x Object) -> copied Object', async () => {
const obj = { a: 1, b: 2, c: 3 }
const copied = Struct.copy(obj)
assert(copied !== obj)
assert.deepEqual(obj, copied)
})
it('Struct.copy(x Set) -> copied Set', async () => {
const set = new Set([1, 2, 3])
const copied = Struct.copy(set)
assert(copied !== set)
assert.deepEqual(set, copied)
})
it('Struct.copy(x Map) -> copied Map', async () => {
const map = new Map([['a', 1], ['b', 2], ['c', 3]])
const copied = Struct.copy(map)
assert(copied !== map)
assert.deepEqual(map, copied)
})
it('Struct.copyDeep(x Array) -> deeplyCopied Array', async () => {
const arr = [1, [2], [[3], 'hey', new Uint8Array([1, 2, 3])]]
const copied = Struct.copyDeep(arr)
assert(copied !== arr)
assert.deepEqual(arr, copied)
})
it('Struct.copyDeep(x Object) -> deeplyCopied Object', async () => {
const obj = { a: 1, b: [2], c: [[3]], d: new Set([NaN, 'hey', { a: null }]) }
const copied = Struct.copy(obj)
assert(copied !== obj)
assert.deepEqual(obj, copied)
})
it('Struct.copyDeep(x Set) -> deeplyCopied Set', async () => {
const set = new Set([1, [2], [[[[3]]]], {}, [], undefined])
const copied = Struct.copy(set)
assert(copied !== set)
assert.deepEqual(set, copied)
})
it('Struct.copyDeep(x Map) -> deeplyCopied Map', async () => {
const map = new Map([
['a', 1], ['b', 2], ['c', 3],
[Symbol.for('ayo'), {}], ['hey', {
a: [1, [2], [[3]]],
b: new Set([undefined, null, {}, [], new RegExp()]),
c: { d: { e: new BigInt64Array([1n, 2n, 3n]) } },
}],
])
const copied = Struct.copy(map)
assert(copied !== map)
assert.deepEqual(map, copied)
assert.strictEqual(map.get('hey').c.d.e, copied.get('hey').c.d.e)
// anything not a struct is a reference. This is good for performance but could be dangerous
})
})