UNPKG

sodiumjs

Version:

A Functional Reactive Programming (FRP) library for JavaScript

157 lines (120 loc) 3.84 kB
/** * 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<A>(arb: jsc.Arbitrary<A>) { return arb.smap(x => new Cell<A>(x), x => x.sample()); } function CellEq<T>(a: Cell<T>, b: Cell<T>) { return a.sample() === b.sample(); } function CellHead(x: string): Cell<string> { const head = S.head(x); return new Cell<string>(head.isNothing ? "" : head.value); } function CellParseInt(radix: number): ((x: number) => Cell<number>) { return function (x: number) { const m = S.parseInt(radix)(x); return new Cell<number>(m.isNothing ? 0 : m.value); }; } test('Cell - Functor Laws', () => { const testLaws = laws.Functor(CellEq); testLaws.identity( CellArb<number>(jsc.number) ); testLaws.composition( CellArb<number>(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<number>(2)) (new Cell<number>(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<Array<number>>(); const s2 = new StreamSink<Array<number>>(); const s3 = S.concat(s1) (s2); const kill = s3.listen((n: Array<number>) => { 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<A>(arb: jsc.Arbitrary<A>) { return arb.smap(x => { const sink = new StreamSink<A>(); sink.listen(() => {}); sink.send(x); return sink; }, x => x.hold(undefined).sample()); } function StreamEq<T>(a: Stream<T>, b: Stream<T>) { 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<number>(jsc.number) )); it('Composition', testLaws.composition( StreamArb<number>(jsc.number), jsc.constant(Math.sqrt), jsc.constant(Math.abs) )); }); */