1 | var R = require('ramda');
|
2 | var assert = require('assert');
|
3 | var equalsInvoker = require('./utils').equalsInvoker;
|
4 | var types = require('./types')(equalsInvoker);
|
5 | var jsv = require('jsverify');
|
6 |
|
7 | var Maybe = require('..').Maybe;
|
8 |
|
9 | var MaybeGen = R.curry(function(a, n) {
|
10 | return n % 2 === 0 ? Maybe.Just(a.generator(n)) : Maybe.Nothing();
|
11 | });
|
12 |
|
13 | var MaybeShow = R.curry(function(a, m) {
|
14 | return (Maybe.isJust(m)) ?
|
15 | 'Just(' + a.show(m.value) + ')' :
|
16 | 'Nothing';
|
17 | });
|
18 |
|
19 | var MaybeShrink = R.curry(function(a, m) {
|
20 | return (Maybe.isJust(m)) ?
|
21 | [Maybe.Nothing()].concat(a.shrink(m.value).map(Maybe.Just)) :
|
22 | [];
|
23 | });
|
24 |
|
25 | var MaybeArb = function(a) {
|
26 | return {
|
27 | generator: jsv.generator.bless(MaybeGen(a)),
|
28 | show: MaybeShow(a),
|
29 | shrink: jsv.shrink.bless(MaybeShrink(a))
|
30 | };
|
31 | };
|
32 |
|
33 | describe('Maybe', function() {
|
34 | var m = MaybeArb(jsv.nat);
|
35 | var env = {Maybe: MaybeArb};
|
36 | var appF = 'Maybe (nat -> nat)';
|
37 | var appN = 'Maybe nat';
|
38 |
|
39 | it('has an arbitrary', function() {
|
40 | var arb = jsv.forall(m, function(m) {
|
41 | return m instanceof Maybe;
|
42 | });
|
43 | jsv.assert(arb);
|
44 | });
|
45 |
|
46 | it('is a Functor', function() {
|
47 | var fTest = types.functor;
|
48 |
|
49 | jsv.assert(jsv.forall(m, fTest.iface));
|
50 | jsv.assert(jsv.forall(m, fTest.id));
|
51 | jsv.assert(jsv.forall(m, 'nat -> nat', 'nat -> nat', fTest.compose));
|
52 | });
|
53 |
|
54 | it('is an Apply', function() {
|
55 | var aTest = types.apply;
|
56 |
|
57 | jsv.assert(jsv.forall(m, aTest.iface));
|
58 | jsv.assert(jsv.forall(appF, appF, appN, env, aTest.compose));
|
59 | });
|
60 |
|
61 | it('is an Applicative', function() {
|
62 | var aTest = types.applicative;
|
63 |
|
64 | jsv.assert(jsv.forall(m, aTest.iface));
|
65 | jsv.assert(jsv.forall(appN, appN, env, aTest.id));
|
66 | jsv.assert(jsv.forall(appN, 'nat -> nat', 'nat', env, aTest.homomorphic));
|
67 | jsv.assert(jsv.forall(appN, appF, 'nat', env, aTest.interchange));
|
68 | });
|
69 |
|
70 | it('is a Chain', function() {
|
71 | var cTest = types.chain;
|
72 | var f = 'nat -> Maybe nat';
|
73 |
|
74 | jsv.assert(jsv.forall(m, cTest.iface));
|
75 | jsv.assert(jsv.forall(m, f, f, env, cTest.associative));
|
76 | });
|
77 |
|
78 | it('is a Monad', function() {
|
79 | var mTest = types.monad;
|
80 |
|
81 | jsv.assert(jsv.forall(m, mTest.iface));
|
82 | });
|
83 |
|
84 | it('is Foldable', function() {
|
85 | var fTest = types.foldable;
|
86 |
|
87 | jsv.assert(jsv.forall(m, fTest.iface));
|
88 | jsv.assert(jsv.forall('nat -> nat -> nat', 'nat', 'nat', function(f, n1, n2) {
|
89 | return Maybe.Just(n1).reduce(R.uncurryN(2, f), n2) === f(n2)(n1);
|
90 | }));
|
91 | jsv.assert(jsv.forall('nat -> nat -> nat', 'nat', function(f, n) {
|
92 | return Maybe.Nothing().reduce(R.uncurryN(2, f), n) === n;
|
93 | }));
|
94 | });
|
95 | });
|
96 |
|
97 | describe('Maybe usage', function() {
|
98 |
|
99 | describe('checking for Just | Nothing', function() {
|
100 | it('should allow the user to check if the instance is a Nothing', function() {
|
101 | assert.equal(true, Maybe(null).isNothing);
|
102 | assert.equal(false, Maybe(42).isNothing);
|
103 | });
|
104 |
|
105 | it('should allow the user to check if the instance is a Just', function() {
|
106 | assert.equal(true, Maybe(42).isJust);
|
107 | assert.equal(false, Maybe(null).isJust);
|
108 | });
|
109 |
|
110 | it('can check the type statically', function() {
|
111 | var nada = Maybe.Nothing();
|
112 | var just1 = Maybe.Just(1);
|
113 | assert.equal(Maybe.isJust(nada), false);
|
114 | assert.equal(Maybe.isNothing(nada), true);
|
115 | assert.equal(Maybe.isJust(just1), true);
|
116 | assert.equal(Maybe.isNothing(just1), false);
|
117 | });
|
118 | });
|
119 |
|
120 | describe('#getOrElse', function() {
|
121 |
|
122 | it('should return the contained value for if the instance is a Just', function() {
|
123 | assert.equal(42, Maybe(42).getOrElse(24));
|
124 | });
|
125 |
|
126 | it('should return the input value if the instance is a Nothing', function() {
|
127 | assert.equal(24, Maybe(null).getOrElse(24));
|
128 | });
|
129 |
|
130 | });
|
131 |
|
132 | describe('#toString', function() {
|
133 |
|
134 | it('returns the string representation of a Just', function() {
|
135 | assert.strictEqual(Maybe.Just([1, 2, 3]).toString(),
|
136 | 'Maybe.Just([1, 2, 3])');
|
137 | });
|
138 |
|
139 | it('returns the string representation of a Nothing', function() {
|
140 | assert.strictEqual(Maybe.Nothing().toString(),
|
141 | 'Maybe.Nothing()');
|
142 | });
|
143 |
|
144 | });
|
145 |
|
146 | describe('#maybe', function() {
|
147 |
|
148 | it('returns the result of applying the value of a Just to the second argument', function() {
|
149 | jsv.assert(jsv.forall('nat -> nat', 'nat', 'nat', function(f, n1, n2) {
|
150 | return R.equals(Maybe.maybe(n2, f, Maybe.Just(n1)), f(n1));
|
151 | }));
|
152 | });
|
153 |
|
154 | it('returns the first argument for a Nothing', function() {
|
155 | jsv.assert(jsv.forall('nat -> nat', 'nat', 'nat', function(f, n) {
|
156 | return R.equals(Maybe.maybe(n, f, Maybe.Nothing()), n);
|
157 | }));
|
158 | });
|
159 | });
|
160 | });
|