describe('concat', function(){ it('is associative', claire.forAll(validGen, validGen, validGen).satisfy(function(v1, v2, v3){ assert.deepEqual(v1.concat(v2.concat(v3)), v1.concat(v2).concat(v3)); return true; }).asTest() ); it('chooses the last of two success values', claire.forAll(successGen, successGen).satisfy(function(s1, s2){ assert.deepEqual(s1.concat(s2), s2); return true; }).asTest() ); it('returns a failure over a success', claire.forAll(successGen, failureGen).satisfy(function(s, f){ assert.deepEqual(s.concat(f), f); assert.deepEqual(f.concat(s), f); return true; }).asTest() ); it('concats two failure values', claire.forAll(failureGen, failureGen).satisfy(function(f1, f2){ assert.deepEqual(f1.concat(f2).value, f1.value.concat(f2.value)); return true; }).asTest() ); });
describe('fromConnectionsList', function(){ var g; it('has as many edges as pairs passed', claire.forAll(PairList).satisfy(function(pairs){ g = graph.fromConnectionsList(pairs); assert.equal(g.nedges, pairs.length); return true; }).asTest() ); it('has as many vertices as the max vertex passed', claire.forAll(PairList).satisfy(function(pairs){ g = graph.fromConnectionsList(pairs); if(pairs.length){ assert.equal(g.nvertices, _.max(_.flatten(pairs))); } else { assert.equal(g.nvertices, 0); } return true; }).asTest() ); it('produces the right adjacency lists', function(){ var pairs = [[0,1], [1,2], [1,3],[2,1], [3,0], [0, 4]]; var g = graph.fromConnectionsList(pairs); _.each(pairs, function(pair) { assert( list.any(function(edge){return edge.y === pair[1];}, g.edges[pair[0]]) ); }); }); });
describe('traverse', function(){ function arrayToMaybe(a){return a.length ? some(a[0]) : none}; function maybeToArray(m){return m.isJust ? [m.value] : [] }; function idToArray(i){return [i.value]}; function idToMaybe(i){return some(i.value)}; function idToValid(i){return Success(i.value)}; function arrayToValid(a){return a.length ? Success(a[0]) : Failure(['empty'])} function maybeToValid(m){return m.isJust ? Success(m.value) : Failure(['empty']); }; var transformGen = claire.choice( {t: arrayToMaybe, i: Array.of, o: some}, {t: maybeToArray, i: some, o: Array.of}, {t: idToArray, i: Id, o: Array.of}, {t: idToMaybe, i: Id, o: some}, {t: idToValid, i: Id, o: Success}, {t: arrayToValid, i: Array.of, o: Success}, {t: maybeToValid, i: some, o: Success} ); //wrapping because of generator issue in interchange comment var fGen = claire.choice([drop1], [isEmpty], [arrayToMaybe], [function(a){return a.length;}]); it('obeys naturality', claire.forAll(transformGen, fGen, validGen).satisfy(function(t, f, v){ var apF = B(t.i)(f[0]); assert.deepEqual(t.t(v.traverse(apF, t.i)), v.traverse(B(t.t)(apF), t.o)); return true; }).asTest() ); it('obeys identity', claire.forAll(validGen).satisfy(function(v){ assert.deepEqual(v.traverse(Id, Id), Id(v)); return true; }).asTest()); var _ = require('lodash'); function ComposeF(nestedFs){ if(this instanceof ComposeF){ this.value = nestedFs; } else { return new ComposeF(nestedFs) } }; ComposeF.prototype.map = function(f){ return new ComposeF(this.value.map(function(x){return x.map(f)})); }; it('obeys composition', claire.forAll(validGen).satisfy(function(v){ var a = v.traverse(function(a){return ComposeF(drop1(a).map(some))}, function(x){return ComposeF(Array.of(some(x)))} ); var b = ComposeF(v.traverse(drop1, Array.of).map(function(x){return x.traverse(some, some)})); assert.deepEqual(a, b); return true; }).asTest()); });
describe('ap', function(){ it('obeys homomorphism', claire.forAll(val).satisfy(function(x){ assert.deepEqual(Success(drop1).ap(Success(x)), Success(drop1(x))); return true; }).asTest()); it('obeys interchange', //wrap success and failure in arrays, otherwise claire treats them as //generators and invokes them with a size hint to get a value. claire.forAll(claire.choice([Success], [Failure]), val).satisfy(function(c, x){ var u = c[0](drop1); assert.deepEqual(u.ap(Success(x)), Success(function(f){return f(x)}).ap(u)); return true; }).asTest() ); });
describe('chain', function(){ var mDrop1 = B(Success)(drop1); var mEmpty = B(Success)(isEmpty); it('is associative', claire.forAll(validGen).satisfy(function(v){ assert.deepEqual(v.chain(mDrop1).chain(mEmpty), v.chain(function(x){return mDrop1(x).chain(mEmpty)}) ); return true; }).asTest()); it('has left identity', claire.forAll(val).satisfy(function(x){ assert.deepEqual(Success(x).chain(mDrop1), mDrop1(x)); return true; }).asTest()); it('has right identity', claire.forAll(validGen).satisfy(function(v){ assert.deepEqual(v.chain(Success), v); return true; }).asTest()); });
describe('map', function(){ it('obeys identity', claire.forAll(validGen).satisfy(function(v){ assert.deepEqual(v.map(I), v); return true; }).asTest()); it('obeys composition', claire.forAll(validGen).satisfy(function(v){ assert.deepEqual(v.map(B(isEmpty)(drop1)), v.map(drop1).map(isEmpty)); return true; }).asTest()); it('maps the inner value of a success', claire.forAll(successGen).satisfy(function(s){ assert.deepEqual(s.map(drop1).value, drop1(s.value)); return true; }).asTest() ); it('is no-op with a failure', claire.forAll(failureGen).satisfy(function(f){ assert.deepEqual(f.map(drop1).value, f.value); return true; }).asTest()); });
'use strict' var gen = require('./generators') var forall = require('claire').forAll module.exports = { ints: { add: { assoc: forall(gen.Int, gen.Int, gen.Int).satisfy(function(x, y, z){ return (x+y)+z === x+(y+z) }) ,commute: forall(gen.Int, gen.Int).satisfy(function(x, y) { return x+y === y+x }) ,ident: forall(gen.Int).satisfy(function(x) { return x+0 === x }) ,closure: forall(gen.Int, gen.Int).satisfy(function(x, y){ return x+y === Math.floor(x+y) }) } ,mul: { assoc: forall(gen.Int, gen.Int, gen.Int).satisfy(function(x, y, z){ return (x*y)*z === x*(y*z) }) ,commute: forall(gen.Int, gen.Int).satisfy(function(x, y) { return x*y === y*x }) ,ident: forall(gen.Int).satisfy(function(x) { return x*1 === x }) ,closure: forall(gen.Int, gen.Int).satisfy(function(x, y){