/**
* Fantasy-land Algebraic Data Type Compatability.
* Cell satisfies the Functor, Apply, and Applicative categories
* @see {@link https://github.com/fantasyland/fantasy-land} for more info
* @see {@link https://github.com/sanctuary-js/sanctuary/blob/master/test/Maybe/Maybe.js} for valid test examples (Sanctuary's Maybe)
*/
import * as jsc from 'jsverify';
import { S} from "../test-utils/Sanctuary";
import { Cell, StreamSink, Stream, Transaction} from '../../lib/Lib';
import * as laws from 'fantasy-laws';
import { testSequence } from '../test-utils/Sequence';
/*
* Cell
*/
//would be nice if we could push all samples off to listeners... like in Fantasy-land Practical Tests below, but for unit testing it's okay
function CellArb(arb: jsc.Arbitrary) {
return arb.smap(x => new Cell(x), x => x.sample());
}
function CellEq(a: Cell, b: Cell) {
return a.sample() === b.sample();
}
function CellHead(x: string): Cell {
const head = S.head(x);
return new Cell(head.isNothing ? "" : head.value);
}
function CellParseInt(radix: number): ((x: number) => Cell) {
return function (x: number) {
const m = S.parseInt(radix)(x);
return new Cell(m.isNothing ? 0 : m.value);
};
}
test('Cell - Functor Laws', () => {
const testLaws = laws.Functor(CellEq);
testLaws.identity(
CellArb(jsc.number)
);
testLaws.composition(
CellArb(jsc.number),
jsc.constant(Math.sqrt),
jsc.constant(Math.abs)
);
});
test('Apply Laws', () => {
const testLaws = laws.Apply(CellEq);
testLaws.composition(
CellArb(jsc.constant(Math.sqrt)),
CellArb(jsc.constant(Math.abs)),
CellArb(jsc.number)
);
});
test('Appplicative Laws', () => {
const testLaws = laws.Applicative(CellEq, Cell);
testLaws.identity(
CellArb(jsc.number)
);
testLaws.homomorphism(
jsc.constant(Math.abs),
jsc.number
);
testLaws.interchange(
CellArb(jsc.constant(Math.abs)),
jsc.number
);
});
test('Lift', (done) => {
const addFunctors = S.lift2(S.add);
const cResult = addFunctors(new Cell(2)) (new Cell(3));
const kill = cResult.listen((n: number) => {
expect(n).toBe(5);
done();
});
kill();
});
test('Sequence', (done) => {
testSequence (S.sequence(Cell)) (done)
});
test('Concat', (done) => {
const s1 = new StreamSink>();
const s2 = new StreamSink>();
const s3 = S.concat(s1) (s2);
const kill = s3.listen((n: Array) => {
expect(n).toEqual([5, 3, 42]);
done();
});
Transaction.run(() => {
s1.send([5]);
s2.send([3, 42]);
})
kill();
});
/*
Stream
describe('Fantasy-land Stream', () => {
/*
TODO: figure out right way to define arb and equality here
If a solution is found that uses listen(), consider porting Cell to that approach as well.
function StreamArb(arb: jsc.Arbitrary) {
return arb.smap(x => {
const sink = new StreamSink();
sink.listen(() => {});
sink.send(x);
return sink;
}, x => x.hold(undefined).sample());
}
function StreamEq(a: Stream, b: Stream) {
console.log(a.hold(undefined).sample());
return a.hold(undefined).sample() === b.hold(undefined).sample();
}
describe('Functor Laws', () => {
const testLaws = laws.Functor(StreamEq);
it('Identity', testLaws.identity(
StreamArb(jsc.number)
));
it('Composition', testLaws.composition(
StreamArb(jsc.number),
jsc.constant(Math.sqrt),
jsc.constant(Math.abs)
));
});
*/