276 lines
6.4 KiB
JavaScript
276 lines
6.4 KiB
JavaScript
import { Result, Ok, Err } from '../src/result.js'
|
|
import { UnwrapError } from '../src/error.js'
|
|
import { Option } from '../src/option.js'
|
|
import { describe, it, mock } from 'node:test'
|
|
import assert from 'node:assert/strict'
|
|
|
|
const ok = v => new Ok(v)
|
|
const err = e => new Err(e)
|
|
const eq = assert.deepStrictEqual.bind(assert)
|
|
|
|
describe('Result', () => {
|
|
it('Result.ok should return an Ok value', async () => {
|
|
eq(Result.ok(1), new Ok(1))
|
|
|
|
// fantasy-land/of
|
|
eq(Result['fantasy-land/of'](1), new Ok(1))
|
|
})
|
|
|
|
it('Ok.bind(fn) should call fn', async () => {
|
|
const a = ok(1)
|
|
const fn = x => ok(x * 2)
|
|
let res = a.bind(fn)
|
|
eq(res, ok(2))
|
|
|
|
// fantasy-land/chain
|
|
res = a['fantasy-land/chain'](fn)
|
|
eq(res, ok(2))
|
|
|
|
// static-land chain
|
|
res = Result.chain(fn, a)
|
|
eq(res, ok(2))
|
|
})
|
|
|
|
it('Err.bind(fn) should not execute fn', async () => {
|
|
const fn = mock.fn(v => ok(v * 2))
|
|
const e = err(new Error('failed'))
|
|
let res = e.bind(fn)
|
|
eq(res, err(new Error('failed')))
|
|
eq(fn.mock.callCount(), 0)
|
|
|
|
// fantasy-land/chain
|
|
res = e['fantasy-land/chain'](fn)
|
|
eq(res, err(new Error('failed')))
|
|
eq(fn.mock.callCount(), 0)
|
|
|
|
// static-land chain
|
|
res = Result.chain(fn, e)
|
|
eq(res, err(new Error('failed')))
|
|
eq(fn.mock.callCount(), 0)
|
|
})
|
|
|
|
it('Ok.map(fn) should transform the inner value', () => {
|
|
const a = ok(1)
|
|
const fn = x => x + 1
|
|
let res = a.map(fn)
|
|
eq(res, ok(2))
|
|
|
|
// fantasy-land/map
|
|
res = a['fantasy-land/map'](fn)
|
|
eq(res, ok(2))
|
|
|
|
// static-land map
|
|
res = Result.map(fn, a)
|
|
eq(res, ok(2))
|
|
})
|
|
|
|
it('Err.map(fn) should not execute fn', async () => {
|
|
const fn = mock.fn(v => Result.ok(v * 2))
|
|
const e = err(new Error('failed'))
|
|
let res = e.map(fn)
|
|
eq(res, err(new Error('failed')))
|
|
eq(fn.mock.callCount(), 0)
|
|
|
|
// fantasy-land/chain
|
|
res = e['fantasy-land/map'](fn)
|
|
eq(res, err(new Error('failed')))
|
|
eq(fn.mock.callCount(), 0)
|
|
|
|
// static-land chain
|
|
res = Result.map(fn, e)
|
|
eq(res, err(new Error('failed')))
|
|
eq(fn.mock.callCount(), 0)
|
|
})
|
|
|
|
it('Ok.and(other)', () => {
|
|
const a = ok(1)
|
|
const b = ok(2)
|
|
assert.strictEqual(a.and(b), b)
|
|
})
|
|
|
|
it('Err.and(other)', () => {
|
|
const a = err(1)
|
|
const b = ok(2)
|
|
assert.strictEqual(a.and(b), a)
|
|
})
|
|
|
|
it('Ok.alt(other) should return itself', () => {
|
|
const self = ok(1)
|
|
const other = ok(2)
|
|
let res = self.alt(other)
|
|
assert.strictEqual(res, self)
|
|
|
|
// fantasy-land/alt
|
|
res = self['fantasy-land/alt'](other)
|
|
assert.strictEqual(res, self)
|
|
|
|
// static-land alt
|
|
res = Result.alt(other, self)
|
|
assert.strictEqual(res, self)
|
|
})
|
|
|
|
it('Err.alt(other) should return other', () => {
|
|
const self = err(new Error('failure'))
|
|
const other = ok(2)
|
|
let res = self.alt(other)
|
|
assert.strictEqual(res, other)
|
|
|
|
// fantasy-land/alt
|
|
res = self['fantasy-land/alt'](other)
|
|
assert.strictEqual(res, other)
|
|
|
|
// static-land alt
|
|
res = Result.alt(other, self)
|
|
assert.strictEqual(res, other)
|
|
})
|
|
|
|
it('Result.orElse(fn)', () => {
|
|
const sq = x => ok(x * x)
|
|
eq(ok(2).orElse(sq).orElse(sq), ok(2))
|
|
eq(ok(2).orElse(err).orElse(sq), ok(2))
|
|
eq(err(3).orElse(sq).orElse(err), ok(9))
|
|
eq(err(3).orElse(err).orElse(err), err(3))
|
|
})
|
|
|
|
it('Ok.ok()', () => {
|
|
eq(ok(1).ok(), Option.some(1))
|
|
})
|
|
|
|
it('Err.ok()', () => {
|
|
eq(err(1).ok(), Option.none())
|
|
})
|
|
|
|
it('Ok.err()', () => {
|
|
eq(ok(1).err(), Option.none())
|
|
})
|
|
|
|
it('Err.err()', () => {
|
|
eq(err(1).err(), Option.some(1))
|
|
})
|
|
|
|
it('Ok.equals(other)', () => {
|
|
const a = ok(1)
|
|
|
|
assert.ok(a.equals(ok(1)))
|
|
assert(!a.equals(ok(2)))
|
|
assert(!a.equals(err(1)))
|
|
|
|
// fantasy-land/equals
|
|
assert.ok(a['fantasy-land/equals'](ok(1)))
|
|
|
|
// static-land equals
|
|
assert.ok(Result.equals(ok(1), a))
|
|
})
|
|
|
|
it('Err.equals(other)', () => {
|
|
const a = err(1)
|
|
|
|
assert.ok(a.equals(err(1)))
|
|
assert(!a.equals(err(2)))
|
|
assert(!a.equals(ok(1)))
|
|
|
|
// fantasy-land/equals
|
|
assert.ok(a['fantasy-land/equals'](err(1)))
|
|
|
|
// static-land equals
|
|
assert.ok(Result.equals(err(1), a))
|
|
})
|
|
|
|
it('Ok.lte(other)', () => {
|
|
const a = ok(1)
|
|
|
|
assert.ok(a.lte(ok(1)))
|
|
assert.ok(a.lte(ok(2)))
|
|
assert.ok(!a.lte(ok(0)))
|
|
assert(!a.lte(err(1)))
|
|
|
|
// fantasy-land/lte
|
|
assert.ok(a['fantasy-land/lte'](ok(1)))
|
|
|
|
// static-land lte
|
|
assert.ok(Result.lte(ok(1), a))
|
|
})
|
|
|
|
it('Err.lte(other)', () => {
|
|
const a = err(1)
|
|
|
|
assert.ok(a.lte(err(1)))
|
|
assert.ok(a.lte(err(2)))
|
|
assert.ok(!a.lte(err(0)))
|
|
assert(!a.lte(ok(1)))
|
|
|
|
// fantasy-land/lte
|
|
assert.ok(a['fantasy-land/lte'](err(1)))
|
|
|
|
// static-land lte
|
|
assert.ok(Result.lte(err(1), a))
|
|
})
|
|
|
|
it('Ok.flatten()', async () => {
|
|
eq(ok(1).flatten(), ok(1))
|
|
eq(ok(ok(1)).flatten(), ok(1))
|
|
eq(ok(ok(ok(1))).flatten(), ok(ok(1)))
|
|
eq(ok(err(1)).flatten(), err(1))
|
|
})
|
|
|
|
it('Err.flatten()', async () => {
|
|
eq(err(1).flatten(), err(1))
|
|
eq(err(err(1)).flatten(), err(1))
|
|
})
|
|
|
|
it('Ok.inspect(fn) should call fn', async () => {
|
|
const fn = mock.fn(_x => { })
|
|
ok(1).inspect(fn)
|
|
eq(fn.mock.callCount(), 1)
|
|
})
|
|
|
|
it('Err.inspect(fn) should not call fn', async () => {
|
|
const fn = mock.fn(_x => { })
|
|
err(1).inspect(fn)
|
|
eq(fn.mock.callCount(), 0)
|
|
})
|
|
|
|
it('Ok.unwrap() returns inner value', async () => {
|
|
const a = ok(1)
|
|
assert.doesNotThrow(a.unwrap.bind(a), UnwrapError)
|
|
eq(a.unwrap(), 1)
|
|
})
|
|
|
|
it('Err.unwrap() throws UnwrapError', async () => {
|
|
assert.throws(err(1).unwrap, UnwrapError)
|
|
})
|
|
|
|
it('Ok.unwrapErr() throws UnwrapError', async () => {
|
|
const a = ok(1)
|
|
assert.throws(a.unwrapErr, UnwrapError)
|
|
})
|
|
|
|
it('Err.unwrapErr() returns inner error', async () => {
|
|
const a = err(1)
|
|
assert.doesNotThrow(a.unwrapErr.bind(a), UnwrapError)
|
|
eq(a.unwrapErr(), 1)
|
|
})
|
|
|
|
it('Ok.unwrapOr(value) returns inner value', async () => {
|
|
eq(ok(1).unwrapOr(2), 1)
|
|
})
|
|
|
|
it('Err.unwrapOr(value) returns value', async () => {
|
|
eq(err(1).unwrapOr(2), 2)
|
|
})
|
|
|
|
it('Ok.unwrapOrElse(fn) returns inner value', async () => {
|
|
const fn = mock.fn(() => 2)
|
|
const a = ok(1)
|
|
eq(a.unwrapOrElse(fn), 1)
|
|
eq(fn.mock.callCount(), 0)
|
|
})
|
|
|
|
it('Err.unwrapOrElse(fn) returns result of fn', async () => {
|
|
const fn = mock.fn(() => 2)
|
|
const a = err(1)
|
|
eq(a.unwrapOrElse(fn), 2)
|
|
eq(fn.mock.callCount(), 1)
|
|
})
|
|
})
|
|
|