Last active
March 7, 2016 05:44
-
-
Save tetsuharuohzeki/431dcf07df7b8dbbdf38 to your computer and use it in GitHub Desktop.
Result<T, E> in TypeScript
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* This type is based on https://doc.rust-lang.org/std/result/enum.Result.html | |
*/ | |
import {Option, Some, None} from 'option-t'; | |
type mapFn<T, U> = (v: T) => U; | |
type flatmapOkFn<T, U, E> = (v: T) => Result<U, E>; | |
type flatmapErrFn<T, E, F> = (e: E) => Result<T, F>; | |
type recoveryFn<E, T> = (e: E) => T; | |
export type Result<T, E> = Ok<T, E> | Err<T, E>; | |
interface ResultMethods<T, E> { | |
/** | |
* Returns true if the result is `Ok`. | |
*/ | |
isOk(): this is Ok<T, E>; | |
/** | |
* Returns true if the result is `Err`. | |
*/ | |
isErr(): this is Err<T, E>; | |
/** | |
* Converts from `Result<T, E>` to `Option<T>`. | |
* If the self is `Ok`, returns `Some<T>`. | |
* Otherwise, returns `None<T>`. | |
*/ | |
ok(): Option<T>; | |
/** | |
* Converts from `Result<T, E>` to `Option<E>`. | |
* If the self is `Err`, returns `Some<E>`. | |
* Otherwise, returns `None<E>`. | |
*/ | |
err(): Option<E>; | |
/** | |
* Maps a `Result<T, E>` to `Result<U, E>` by applying a function `mapFn<T, U>` | |
* to an contained `Ok` value, leaving an `Err` value untouched. | |
* | |
* This function can be used to compose the results of two functions. | |
*/ | |
map<U>(op: mapFn<T, U>): Result<U, E>; | |
/** | |
* Maps a `Result<T, E>` to `Result<T, F>` by applying a function `mapFn<E, F>` | |
* to an contained `Err` value, leaving an `Ok` value untouched. | |
* | |
* This function can be used to pass through a successful result while handling an error. | |
*/ | |
mapErr<F>(op: mapFn<E, F>): Result<T, F>; | |
/** | |
* Returns `res` if the result is `Ok`, otherwise returns the `Err` value of self. | |
*/ | |
and<U>(res: Result<U, E>): Result<U, E>; | |
/** | |
* Calls `op` if the result is `Ok`, otherwise returns the `Err` value of self. | |
* This function can be used for control flow based on result values. | |
*/ | |
andThen<U>(op: flatmapOkFn<T, U, E>): Result<U, E>; | |
/** | |
* Returns `res` if the result is `Err`, otherwise returns the `Ok` value of self. | |
*/ | |
or<F>(res: Result<T, F>): Result<T, F>; | |
/** | |
* Calls `op` if the result is `Err`, otherwise returns the `Ok` value of self. | |
* This function can be used for control flow based on result values. | |
*/ | |
orElse<F>(op: flatmapErrFn<T, E, F>): Result<T, F>; | |
/** | |
* Unwraps a result, return the content of an `Ok`. Else it returns `optb`. | |
*/ | |
unwrapOr(optb: T): T; | |
/** | |
* Unwraps a result, returns the content of an `Ok`. | |
* If the value is an `Err` then it calls `op` with its value. | |
*/ | |
unwrapOrElse(op: recoveryFn<E, T>): T; | |
/** | |
* Return the inner `T` of a `Ok(T)`. | |
* | |
* @throws {Error} | |
* Throws if the self is a `Err`. | |
*/ | |
unwrap(): T; | |
/** | |
* Return the inner `E` of a `Err(E)`. | |
* | |
* @throws {Error} | |
* Throws if the self is a `Ok`. | |
*/ | |
unwrapErr(): E; | |
/** | |
* Return the inner `T` of a `Ok(T)`. | |
* | |
* @throws {Error} | |
* Throws the passed `message` if the self is a `Err`. | |
*/ | |
expect(message: string): T; | |
/** | |
* The destructor method inspired by Rust's `Drop` trait. | |
* We don't define the object's behavior after calling this. | |
*/ | |
drop(): void; | |
} | |
// XXX: | |
// 主に`React.PropType.instanceOf()`のような, runtime checkを | |
// `instanceof`で判別する用途に使う. それ以外では絶対に使ってはいけない. | |
export abstract class ResultBase { | |
constructor() {} | |
} | |
export class Ok<T, E> extends ResultBase implements ResultMethods<T, E> { | |
private _v: T; | |
constructor(v: T) { | |
super(); | |
this._v = v; | |
Object.seal(this); | |
} | |
isOk(): this is Ok<T, E> { | |
return true; | |
} | |
isErr(): this is Err<T, E> { | |
return false; | |
} | |
ok(): Option<T> { | |
return new Some<T>(this._v); | |
} | |
err(): Option<E> { | |
return new None<E>(); | |
} | |
map<U>(op: mapFn<T, U>): Result<U, E> { | |
const mapped: U = op(this._v); | |
const result: Result<U, E> = new Ok<U, E>(mapped); | |
return result; | |
} | |
mapErr<F>(op: mapFn<E, F>): Result<T, F> { | |
// XXX: this any cast is the allocation cheat to avoid creating a needless object. | |
const result: Result<T, F> = <any>this; | |
return result; | |
} | |
and<U>(res: Result<U, E>): Result<U, E> { | |
return res; | |
} | |
andThen<U>(op: flatmapOkFn<T, U, E>): Result<U, E> { | |
const result: Result<U, E> = op(this._v); | |
return result; | |
} | |
or<F>(res: Result<T, F>): Result<T, F> { | |
// XXX: this any cast is the allocation cheat to avoid creating a needless object. | |
const result: Result<T, F> = <any>this; | |
return result; | |
} | |
orElse<F>(op: flatmapErrFn<T, E, F>): Result<T, F> { | |
// XXX: this any cast is the allocation cheat to avoid creating a needless object. | |
const result: Result<T, F> = <any>this; | |
return result; | |
} | |
unwrapOr(optb: T): T { | |
return this._v; | |
} | |
unwrapOrElse(op: recoveryFn<E, T>): T { | |
return this._v; | |
} | |
unwrap(): T { | |
return this._v; | |
} | |
unwrapErr(): E { | |
throw new Error('called `unwrapErr()` on a `Ok` value'); | |
} | |
expect(message: string): T { | |
return this._v; | |
} | |
drop(): void { | |
this._v = null; | |
Object.freeze(this); | |
} | |
} | |
// XXX: | |
// あくまでも任意のエラー情報`E`を格納するコンテナとしての役割であるため, | |
// `Error`のsubclassとはしないし, `E`のupper boundが`Error`であるという制約もしない. | |
export class Err<T, E> extends ResultBase implements ResultMethods<T, E> { | |
private _e: E; | |
constructor(e: E) { | |
super(); | |
this._e = e; | |
Object.seal(this); | |
} | |
isOk(): this is Ok<T, E> { | |
return false; | |
} | |
isErr(): this is Err<T, E> { | |
return true; | |
} | |
ok(): Option<T> { | |
return new None<T>(); | |
} | |
err(): Option<E> { | |
return new Some<E>(this._e); | |
} | |
map<U>(op: mapFn<T, U>): Result<U, E> { | |
// XXX: this any cast is the allocation cheat to avoid creating a needless object. | |
const result: Result<U, E> = <any>this; | |
return result; | |
} | |
mapErr<F>(op: mapFn<E, F>): Result<T, F> { | |
const mapped: F = op(this._e); | |
const result: Result<T, F> = new Err<T, F>(mapped); | |
return result; | |
} | |
and<U>(res: Result<U, E>): Result<U, E> { | |
// XXX: this any cast is the allocation cheat to avoid creating a needless object. | |
const result: Result<U, E> = <any>this; | |
return result; | |
} | |
andThen<U>(op: flatmapOkFn<T, U, E>): Result<U, E> { | |
// XXX: this any cast is the allocation cheat to avoid creating a needless object. | |
const result: Result<U, E> = <any>this; | |
return result; | |
} | |
or<F>(res: Result<T, F>): Result<T, F> { | |
return res; | |
} | |
orElse<F>(op: flatmapErrFn<T, E, F>): Result<T, F> { | |
const result: Result<T, F> = op(this._e); | |
return result; | |
} | |
unwrapOr(optb: T): T { | |
return optb; | |
} | |
unwrapOrElse(op: recoveryFn<E, T>): T { | |
const recovered: T = op(this._e); | |
return recovered; | |
} | |
unwrap(): T { | |
return this.expect('called `unwrap()` on a `Err` value'); | |
} | |
unwrapErr(): E { | |
return this._e; | |
} | |
expect(message: string): T { | |
throw new Error(message); | |
} | |
drop(): void { | |
this._e = null; | |
Object.freeze(this); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/// <reference path="../../../../../typings/third_party/mocha/mocha.d.ts"/> | |
/// <reference path="../../../../../typings/third_party/power-assert/power-assert.d.ts"/> | |
/*eslint-env mocha*/ | |
import assert from 'power-assert'; | |
import {ResultBase, Ok, Err} from '../Result.js'; | |
const EXPECTED_OK = 'expected_ok'; | |
const EXPECTED_ERR = 'expected_err'; | |
describe('Result<T, E>', function () { | |
describe('Ok<T, E>', function () { | |
describe('object characteristic', function () { | |
it('the object is sealed', function () { | |
const ok = new Ok(EXPECTED_OK); | |
assert.ok( Object.isSealed(ok) ); | |
}); | |
}); | |
describe('instanceof', function () { | |
let ok = null; | |
before(function(){ | |
ok = new Ok(EXPECTED_OK); | |
}); | |
it('Ok', function () { | |
assert.ok(ok instanceof Ok); | |
}); | |
it('ResultBase', function () { | |
assert.ok(ok instanceof ResultBase); | |
}); | |
it('not instanceof Err', function () { | |
assert.ok( !(ok instanceof Err) ); | |
}); | |
}); | |
describe('implementations of Result<T, E>', function () { | |
describe('isOk()', function () { | |
it('isOk()', function () { | |
const ok = new Ok(EXPECTED_OK); | |
assert.strictEqual(ok.isOk(), true); | |
}); | |
}); | |
describe('isErr()', function () { | |
it('isErr()', function () { | |
const ok = new Ok(EXPECTED_OK); | |
assert.strictEqual(ok.isErr(), false); | |
}); | |
}); | |
describe('ok()', function () { | |
let ok = null; | |
before(function(){ | |
ok = new Ok(EXPECTED_OK); | |
}); | |
it('return `Some<T>`', function () { | |
assert.ok(ok.ok().isSome); | |
}); | |
it('the inner value is expected', function () { | |
assert.strictEqual(ok.ok().unwrap(), EXPECTED_OK); | |
}); | |
}); | |
describe('err()', function () { | |
it('return `None<E>`', function () { | |
const ok = new Ok(EXPECTED_OK); | |
assert.ok(ok.err().isNone); | |
}); | |
}); | |
describe('map()', function () { | |
const ORIGIN = 0; | |
const EXPECTED = 1; | |
let argument = null; | |
let result = null; | |
const op = function (v) { | |
argument = v; | |
return EXPECTED; | |
}; | |
before(function(){ | |
assert.notStrictEqual(argument, ORIGIN); | |
assert.notStrictEqual(result, EXPECTED); | |
assert.notStrictEqual(ORIGIN, EXPECTED); | |
const original = new Ok(ORIGIN); | |
result = original.map(op); | |
}); | |
it('the returned value should be `Ok<U, E>', function () { | |
assert.ok(result.isOk()); | |
}); | |
it('the argument of `op` should be the expected value', function () { | |
assert.strictEqual(argument, ORIGIN); | |
}); | |
it('the returned value should wrap the expected value', function () { | |
assert.strictEqual(result.unwrap(), EXPECTED); | |
}); | |
}); | |
describe('mapErr()', function () { | |
const ORIGIN = 0; | |
const NOT_EXPECTED = 1; | |
let opIsCalled = false; | |
let result = null; | |
const op = function () { | |
opIsCalled = true; | |
return NOT_EXPECTED; | |
}; | |
before(function(){ | |
assert.notStrictEqual(opIsCalled, true); | |
assert.notStrictEqual(ORIGIN, NOT_EXPECTED); | |
const original = new Ok(ORIGIN); | |
result = original.mapErr(op); | |
}); | |
it('the returned value should be `Ok<T, F>', function () { | |
assert.ok(result.isOk()); | |
}); | |
it('the `op` callback should not be called', function () { | |
assert.strictEqual(opIsCalled, false); | |
}); | |
it('the returned value should wrap the expected value', function () { | |
assert.strictEqual(result.unwrap(), ORIGIN); | |
}); | |
}); | |
describe('and()', function () { | |
describe('with Ok', function () { | |
const ORIGIN = 0; | |
const EXPECTED = 1; | |
let result = null; | |
before(function(){ | |
assert.notStrictEqual(ORIGIN, EXPECTED); | |
const left = new Ok(ORIGIN); | |
const right = new Ok(EXPECTED); | |
result = left.and(right); | |
}); | |
it('the returned value should be `Ok', function () { | |
assert.ok(result.isOk()); | |
}); | |
it('the returned value should wrap the expected value', function () { | |
assert.strictEqual(result.unwrap(), EXPECTED); | |
}); | |
}); | |
describe('with Err', function () { | |
const ORIGIN = 0; | |
const EXPECTED = 1; | |
let result = null; | |
before(function(){ | |
assert.notStrictEqual(ORIGIN, EXPECTED); | |
const left = new Ok(ORIGIN); | |
const right = new Err(EXPECTED); | |
result = left.and(right); | |
}); | |
it('the returned value should be `Err', function () { | |
assert.ok(result.isErr()); | |
}); | |
it('the returned value should wrap the expected value', function () { | |
assert.strictEqual(result.unwrapErr(), EXPECTED); | |
}); | |
}); | |
}); | |
describe('andThen()', function () { | |
describe('return Ok', function () { | |
const ORIGIN = 0; | |
const EXPECTED = 1; | |
let argument = null; | |
let result = null; | |
const op = function (v) { | |
argument = v; | |
return new Ok(EXPECTED); | |
}; | |
before(function(){ | |
assert.notStrictEqual(argument, ORIGIN); | |
assert.notStrictEqual(result, EXPECTED); | |
assert.notStrictEqual(ORIGIN, EXPECTED); | |
const original = new Ok(ORIGIN); | |
result = original.andThen(op); | |
}); | |
it('the returned value should be `Ok', function () { | |
assert.ok(result.isOk()); | |
}); | |
it('the argument of `op` should be the expected value', function () { | |
assert.strictEqual(argument, ORIGIN); | |
}); | |
it('the returned value should wrap the expected value', function () { | |
assert.strictEqual(result.unwrap(), EXPECTED); | |
}); | |
}); | |
describe('return Err', function () { | |
const ORIGIN = 0; | |
const EXPECTED = 1; | |
let argument = null; | |
let result = null; | |
const op = function (v) { | |
argument = v; | |
return new Err(EXPECTED); | |
}; | |
before(function(){ | |
assert.notStrictEqual(argument, ORIGIN); | |
assert.notStrictEqual(result, EXPECTED); | |
assert.notStrictEqual(ORIGIN, EXPECTED); | |
const original = new Ok(ORIGIN); | |
result = original.andThen(op); | |
}); | |
it('the returned value should be `Err', function () { | |
assert.ok(result.isErr()); | |
}); | |
it('the argument of `op` should be the expected value', function () { | |
assert.strictEqual(argument, ORIGIN); | |
}); | |
it('the returned value should wrap the expected value', function () { | |
assert.strictEqual(result.unwrapErr(), EXPECTED); | |
}); | |
}); | |
}); | |
describe('or()', function () { | |
describe('with Ok', function () { | |
const EXPECTED = 0; | |
const UNEXPECTED = 1; | |
let result = null; | |
before(function(){ | |
assert.notStrictEqual(EXPECTED, UNEXPECTED); | |
const left = new Ok(EXPECTED); | |
const right = new Err(UNEXPECTED); | |
result = left.or(right); | |
}); | |
it('the returned value should be `Ok', function () { | |
assert.ok(result.isOk()); | |
}); | |
it('the returned value should wrap the expected value', function () { | |
assert.strictEqual(result.unwrap(), EXPECTED); | |
}); | |
}); | |
describe('with Err', function () { | |
const EXPECTED = 0; | |
const UNEXPECTED = 1; | |
let result = null; | |
before(function(){ | |
assert.notStrictEqual(EXPECTED, UNEXPECTED); | |
const left = new Ok(EXPECTED); | |
const right = new Err(UNEXPECTED); | |
result = left.or(right); | |
}); | |
it('the returned value should be `Ok', function () { | |
assert.ok(result.isOk()); | |
}); | |
it('the returned value should wrap the expected value', function () { | |
assert.strictEqual(result.unwrap(), EXPECTED); | |
}); | |
}); | |
}); | |
describe('orElse()', function () { | |
describe('return Ok', function () { | |
const EXPECTED = 0; | |
const NOT_EXPECTED = 1; | |
let opIsCalled = false; | |
let result = null; | |
const op = function () { | |
opIsCalled = true; | |
return new Ok(NOT_EXPECTED); | |
}; | |
before(function(){ | |
assert.notStrictEqual(opIsCalled, true); | |
assert.notStrictEqual(EXPECTED, NOT_EXPECTED); | |
const original = new Ok(EXPECTED); | |
result = original.orElse(op); | |
}); | |
it('the returned value should be `Ok', function () { | |
assert.ok(result.isOk()); | |
}); | |
it('the `op` callbacl should not be called', function () { | |
assert.strictEqual(opIsCalled, false); | |
}); | |
it('the returned value should wrap the expected value', function () { | |
assert.strictEqual(result.unwrap(), EXPECTED); | |
}); | |
}); | |
describe('return Err', function () { | |
const EXPECTED = 0; | |
const NOT_EXPECTED = 1; | |
let opIsCalled = false; | |
let result = null; | |
const op = function () { | |
opIsCalled = true; | |
return new Err(NOT_EXPECTED); | |
}; | |
before(function(){ | |
assert.notStrictEqual(opIsCalled, true); | |
assert.notStrictEqual(EXPECTED, NOT_EXPECTED); | |
const original = new Ok(EXPECTED); | |
result = original.orElse(op); | |
}); | |
it('the returned value should be `Ok', function () { | |
assert.ok(result.isOk()); | |
}); | |
it('the `op` callbacl should not be called', function () { | |
assert.strictEqual(opIsCalled, false); | |
}); | |
it('the returned value should wrap the expected value', function () { | |
assert.strictEqual(result.unwrap(), EXPECTED); | |
}); | |
}); | |
}); | |
describe('unwrapOr()', function () { | |
const EXPECTED = 0; | |
const NOT_EXPECTED = 1; | |
before(function(){ | |
assert.notStrictEqual(EXPECTED, NOT_EXPECTED); | |
}); | |
it('unwrapOr()', function () { | |
const result = new Ok(EXPECTED); | |
assert.strictEqual(result.unwrapOr(NOT_EXPECTED), EXPECTED); | |
}); | |
}); | |
describe('unwrapOrElse()', function () { | |
const EXPECTED = 0; | |
const NOT_EXPECTED = 1; | |
let opIsCalled = false; | |
let acutual = null; | |
const op = function () { | |
opIsCalled = true; | |
return NOT_EXPECTED; | |
}; | |
before(function() { | |
assert.notStrictEqual(opIsCalled, true); | |
assert.notStrictEqual(acutual, EXPECTED); | |
const result = new Ok(EXPECTED); | |
acutual = result.unwrapOrElse(op); | |
}); | |
it('the `op` callback should not be called', function () { | |
assert.strictEqual(opIsCalled, false); | |
}); | |
it('the returned is expected', function () { | |
assert.strictEqual(acutual, EXPECTED); | |
}); | |
}); | |
describe('unwrap()', function () { | |
it('unwrap()', function () { | |
const ok = new Ok(EXPECTED_OK); | |
assert.strictEqual(ok.unwrap(), EXPECTED_OK); | |
}); | |
}); | |
describe('unwrapErr()', function () { | |
let caught = null; | |
let ok = null; | |
before(function(){ | |
ok = new Ok(EXPECTED_OK); | |
try { | |
ok.unwrapErr(); | |
} | |
catch (e) { | |
caught = e; | |
} | |
}); | |
it('is instance of `Error`', function () { | |
assert.ok( (caught instanceof Error) ); | |
}); | |
it('the error message is expected', function () { | |
assert.strictEqual(caught.message, 'called `unwrapErr()` on a `Ok` value'); | |
}); | |
}); | |
describe('expect()', function () { | |
it('expect()', function () { | |
const ok = new Ok(EXPECTED_OK); | |
assert.strictEqual(ok.expect('not expected message'), EXPECTED_OK); | |
}); | |
}); | |
describe('drop()', function () { | |
it('is callable', function () { | |
const ok = new Ok(EXPECTED_OK); | |
ok.drop(); | |
}); | |
it('should be freezed', function () { | |
const ok = new Ok(EXPECTED_OK); | |
ok.drop(); | |
assert.strictEqual(Object.isFrozen(ok), true); | |
}); | |
}); | |
}); | |
}); | |
describe('Err<T, E>', function () { | |
describe('object characteristic', function () { | |
it('the object is sealed', function () { | |
const err = new Err(EXPECTED_ERR); | |
assert.ok( Object.isSealed(err) ); | |
}); | |
}); | |
describe('instanceof', function () { | |
let err = null; | |
before(function(){ | |
err = new Err(EXPECTED_ERR); | |
}); | |
it('Err', function () { | |
assert.ok(err instanceof Err); | |
}); | |
it('errBase', function () { | |
assert.ok(err instanceof ResultBase); | |
}); | |
it('not instanceof Ok', function () { | |
assert.ok( !(err instanceof Ok) ); | |
}); | |
}); | |
describe('implementations of Result<T, E>', function () { | |
describe('isOk()', function () { | |
it('isOk()', function () { | |
const err = new Err(EXPECTED_ERR); | |
assert.strictEqual(err.isOk(), false); | |
}); | |
}); | |
describe('isErr()', function () { | |
it('isErr()', function () { | |
const err = new Err(EXPECTED_ERR); | |
assert.strictEqual(err.isErr(), true); | |
}); | |
}); | |
describe('ok()', function () { | |
it('return `None<T>`', function () { | |
const err = new Err(EXPECTED_ERR); | |
assert.ok(err.ok().isNone); | |
}); | |
}); | |
describe('err()', function () { | |
let err = null; | |
before(function(){ | |
err = new Err(EXPECTED_ERR); | |
}); | |
it('return `Some<E>`', function () { | |
assert.ok(err.err().isSome); | |
}); | |
it('the inner value is expected', function () { | |
assert.strictEqual(err.err().unwrap(), EXPECTED_ERR); | |
}); | |
}); | |
describe('map()', function () { | |
const ORIGIN = 0; | |
const NOT_EXPECTED = 1; | |
let opIsCalled = false; | |
let result = null; | |
const op = function () { | |
opIsCalled = true; | |
return NOT_EXPECTED; | |
}; | |
before(function(){ | |
assert.notStrictEqual(opIsCalled, true); | |
assert.notStrictEqual(ORIGIN, NOT_EXPECTED); | |
const original = new Err(ORIGIN); | |
result = original.map(op); | |
}); | |
it('the returned value should be `Err<U, E>', function () { | |
assert.ok(result.isErr()); | |
}); | |
it('the `op` callbacl should not be called', function () { | |
assert.strictEqual(opIsCalled, false); | |
}); | |
it('the returned value should wrap the expected value', function () { | |
assert.strictEqual(result.unwrapErr(), ORIGIN); | |
}); | |
}); | |
describe('mapErr()', function () { | |
const ORIGIN = 0; | |
const EXPECTED = 1; | |
let argument = null; | |
let result = null; | |
const op = function (v) { | |
argument = v; | |
return EXPECTED; | |
}; | |
before(function(){ | |
assert.notStrictEqual(ORIGIN, EXPECTED); | |
assert.notStrictEqual(argument, ORIGIN); | |
const original = new Err(ORIGIN); | |
result = original.mapErr(op); | |
}); | |
it('the returned value should be `Err<T, F>', function () { | |
assert.ok(result.isErr()); | |
}); | |
it('the argument of `op` callback is expected', function () { | |
assert.strictEqual(argument, ORIGIN); | |
}); | |
it('the returned value should wrap the expected value', function () { | |
assert.strictEqual(result.unwrapErr(), EXPECTED); | |
}); | |
}); | |
describe('and()', function () { | |
describe('with Ok', function () { | |
const EXPECTED = 0; | |
const UNEXPECTED = 1; | |
let result = null; | |
before(function(){ | |
assert.notStrictEqual(EXPECTED, UNEXPECTED); | |
const left = new Err(EXPECTED); | |
const right = new Ok(UNEXPECTED); | |
result = left.and(right); | |
}); | |
it('the returned value should be `Err', function () { | |
assert.ok(result.isErr()); | |
}); | |
it('the returned value should wrap the expected value', function () { | |
assert.strictEqual(result.unwrapErr(), EXPECTED); | |
}); | |
}); | |
describe('with Err', function () { | |
const EXPECTED = 0; | |
const UNEXPECTED = 1; | |
let result = null; | |
before(function(){ | |
assert.notStrictEqual(EXPECTED, UNEXPECTED); | |
const left = new Err(EXPECTED); | |
const right = new Err(UNEXPECTED); | |
result = left.and(right); | |
}); | |
it('the returned value should be `Err', function () { | |
assert.ok(result.isErr()); | |
}); | |
it('the returned value should wrap the expected value', function () { | |
assert.strictEqual(result.unwrapErr(), EXPECTED); | |
}); | |
}); | |
}); | |
describe('andThen()', function () { | |
describe('return Ok', function () { | |
const ORIGIN = 0; | |
const NOT_EXPECTED = 1; | |
let opIsCalled = false; | |
let result = null; | |
const op = function () { | |
opIsCalled = true; | |
return new Ok(NOT_EXPECTED); | |
}; | |
before(function(){ | |
assert.notStrictEqual(opIsCalled, true); | |
assert.notStrictEqual(ORIGIN, NOT_EXPECTED); | |
const original = new Err(ORIGIN); | |
result = original.andThen(op); | |
}); | |
it('the returned value should be `Err', function () { | |
assert.ok(result.isErr()); | |
}); | |
it('the `op` callbacl should not be called', function () { | |
assert.strictEqual(opIsCalled, false); | |
}); | |
it('the returned value should wrap the expected value', function () { | |
assert.strictEqual(result.unwrapErr(), ORIGIN); | |
}); | |
}); | |
describe('return Err', function () { | |
const ORIGIN = 0; | |
const NOT_EXPECTED = 1; | |
let opIsCalled = false; | |
let result = null; | |
const op = function () { | |
opIsCalled = true; | |
return new Err(NOT_EXPECTED); | |
}; | |
before(function(){ | |
assert.notStrictEqual(opIsCalled, true); | |
assert.notStrictEqual(ORIGIN, NOT_EXPECTED); | |
const original = new Err(ORIGIN); | |
result = original.andThen(op); | |
}); | |
it('the returned value should be `Err', function () { | |
assert.ok(result.isErr()); | |
}); | |
it('the `op` callbacl should not be called', function () { | |
assert.strictEqual(opIsCalled, false); | |
}); | |
it('the returned value should wrap the expected value', function () { | |
assert.strictEqual(result.unwrapErr(), ORIGIN); | |
}); | |
}); | |
}); | |
describe('or()', function () { | |
describe('with Ok', function () { | |
const EXPECTED = 0; | |
const UNEXPECTED = 1; | |
let result = null; | |
before(function(){ | |
assert.notStrictEqual(EXPECTED, UNEXPECTED); | |
const left = new Err(UNEXPECTED); | |
const right = new Ok(EXPECTED); | |
result = left.or(right); | |
}); | |
it('the returned value should be `Ok', function () { | |
assert.ok(result.isOk()); | |
}); | |
it('the returned value should wrap the expected value', function () { | |
assert.strictEqual(result.unwrap(), EXPECTED); | |
}); | |
}); | |
describe('with Err', function () { | |
const EXPECTED = 0; | |
const UNEXPECTED = 1; | |
let result = null; | |
before(function(){ | |
assert.notStrictEqual(EXPECTED, UNEXPECTED); | |
const left = new Err(UNEXPECTED); | |
const right = new Err(EXPECTED); | |
result = left.or(right); | |
}); | |
it('the returned value should be `Err', function () { | |
assert.ok(result.isErr()); | |
}); | |
it('the returned value should wrap the expected value', function () { | |
assert.strictEqual(result.unwrapErr(), EXPECTED); | |
}); | |
}); | |
}); | |
describe('orElse()', function () { | |
describe('return Ok', function () { | |
const ORIGIN = 0; | |
const EXPECTED = 1; | |
let argument = null; | |
let result = null; | |
const op = function (v) { | |
argument = v; | |
return new Ok(EXPECTED); | |
}; | |
before(function(){ | |
assert.notStrictEqual(argument, ORIGIN); | |
assert.notStrictEqual(result, EXPECTED); | |
assert.notStrictEqual(ORIGIN, EXPECTED); | |
const original = new Err(ORIGIN); | |
result = original.orElse(op); | |
}); | |
it('the returned value should be `Ok', function () { | |
assert.strictEqual(result.isOk(), true); | |
}); | |
it('the argument of `op` should be the expected value', function () { | |
assert.strictEqual(argument, ORIGIN); | |
}); | |
it('the returned value should wrap the expected value', function () { | |
assert.strictEqual(result.unwrap(), EXPECTED); | |
}); | |
}); | |
describe('return Err', function () { | |
const ORIGIN = 0; | |
const EXPECTED = 1; | |
let argument = null; | |
let result = null; | |
const op = function (v) { | |
argument = v; | |
return new Err(EXPECTED); | |
}; | |
before(function(){ | |
assert.notStrictEqual(argument, ORIGIN); | |
assert.notStrictEqual(result, EXPECTED); | |
assert.notStrictEqual(ORIGIN, EXPECTED); | |
const original = new Err(ORIGIN); | |
result = original.orElse(op); | |
}); | |
it('the returned value should be `Err', function () { | |
assert.strictEqual(result.isErr(), true); | |
}); | |
it('the argument of `op` should be the expected value', function () { | |
assert.strictEqual(argument, ORIGIN); | |
}); | |
it('the returned value should wrap the expected value', function () { | |
assert.strictEqual(result.unwrapErr(), EXPECTED); | |
}); | |
}); | |
}); | |
describe('unwrapOr()', function () { | |
const EXPECTED = 0; | |
const NOT_EXPECTED = 1; | |
before(function(){ | |
assert.notStrictEqual(EXPECTED, NOT_EXPECTED); | |
}); | |
it('unwrapOr()', function () { | |
const result = new Err(NOT_EXPECTED); | |
assert.strictEqual(result.unwrapOr(EXPECTED), EXPECTED); | |
}); | |
}); | |
describe('unwrapOrElse()', function () { | |
const ORIGINAL = 0; | |
const EXPECTED = 1; | |
let argument = null; | |
let acutual = null; | |
const op = function (v) { | |
argument = v; | |
return EXPECTED; | |
}; | |
before(function() { | |
assert.notStrictEqual(argument, ORIGINAL); | |
assert.notStrictEqual(acutual, EXPECTED); | |
assert.notStrictEqual(ORIGINAL, EXPECTED); | |
const result = new Err(ORIGINAL); | |
acutual = result.unwrapOrElse(op); | |
}); | |
it('the argument of `op` is expeced', function () { | |
assert.strictEqual(argument, ORIGINAL); | |
}); | |
it('the returned is expected', function () { | |
assert.strictEqual(acutual, EXPECTED); | |
}); | |
}); | |
describe('unwrap()', function () { | |
let caught = null; | |
let err = null; | |
before(function(){ | |
err = new Err(EXPECTED_ERR); | |
try { | |
err.unwrap(); | |
} | |
catch (e) { | |
caught = e; | |
} | |
}); | |
it('is instance of `Error`', function () { | |
assert.ok( (caught instanceof Error) ); | |
}); | |
it('the error message is expected', function () { | |
assert.strictEqual(caught.message, 'called `unwrap()` on a `Err` value'); | |
}); | |
}); | |
describe('unwrapErr()', function () { | |
it('unwrapErr()', function () { | |
const err = new Err(EXPECTED_ERR); | |
assert.strictEqual(err.unwrapErr(), EXPECTED_ERR); | |
}); | |
}); | |
describe('expect()', function () { | |
const UNEXPECTED = 100; | |
let caught = null; | |
before(function(){ | |
try { | |
const err = new Err(UNEXPECTED); | |
err.expect(EXPECTED_ERR); | |
} | |
catch (e) { | |
caught = e; | |
} | |
}); | |
it('is instance of `Error`', function () { | |
assert.ok( (caught instanceof Error) ); | |
}); | |
it('the error message is expected', function () { | |
assert.strictEqual(caught.message, EXPECTED_ERR); | |
}); | |
}); | |
describe('drop()', function () { | |
it('is callable', function () { | |
const err = new Err(EXPECTED_ERR); | |
err.drop(); | |
}); | |
it('should be freezed', function () { | |
const err = new Err(EXPECTED_ERR); | |
err.drop(); | |
assert.strictEqual(Object.isFrozen(err), true); | |
}); | |
}); | |
}); | |
}); | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment