Skip to content

Instantly share code, notes, and snippets.

@tetsuharuohzeki
Last active March 7, 2016 05:44
Show Gist options
  • Save tetsuharuohzeki/431dcf07df7b8dbbdf38 to your computer and use it in GitHub Desktop.
Save tetsuharuohzeki/431dcf07df7b8dbbdf38 to your computer and use it in GitHub Desktop.
Result<T, E> in TypeScript
/**
* 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);
}
}
/// <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