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) }) })