UNPKG

5.57 kBJavaScriptView Raw
1var R = require('ramda');
2var assert = require('assert');
3var types = require('./types');
4var Future = require('../src/Future');
5
6Future.prototype.equals = function(b) {
7 this.fork(function(e1) {
8 b.fork(function(e2) {
9 assert.equal(e1, e2);
10 }, function() {
11 assert.fail(null, e1, 'Futures not equal: f1 failed, f2 did not', '===');
12 });
13 }, function(v1) {
14 b.fork(function() {
15 assert.fail(null, v1, 'Futures not equal: f1 succeeded, f2 did not', '===');
16 }, function(v2) {
17 assert.equal(v1, v2);
18 });
19 });
20 return true;
21};
22
23describe('Future', function() {
24
25 it('should equal another future', function() {
26 var f1 = Future.of(2);
27 var f2 = Future.of(2);
28 assert.equal(true, f1.equals(f2));
29 });
30
31 it('is a Functor', function() {
32 var fTest = types.functor;
33 var f = Future.of(2);
34 assert.equal(true, fTest.iface(f));
35 assert.equal(true, fTest.id(f));
36 assert.equal(true, fTest.compose(f, R.multiply(2), R.add(3)));
37 });
38
39 it('is an Apply', function() {
40 var aTest = types.apply;
41 var appA = Future.of(R.multiply(10));
42 var appU = Future.of(R.add(5));
43 var appV = Future.of(10);
44 assert.equal(true, aTest.iface(appA));
45 assert.equal(true, aTest.compose(appA, appU, appV));
46 });
47
48 it('is an Applicative', function() {
49 var aTest = types.applicative;
50 var app1 = Future.of(101);
51 var app2 = Future.of(-123);
52 var appF = Future.of(R.multiply(3));
53
54 assert.equal(true, aTest.iface(app1));
55 assert.equal(true, aTest.id(app1, app2));
56 assert.equal(true, aTest.homomorphic(app1, R.add(3), 46));
57 assert.equal(true, aTest.interchange(app1, appF, 17));
58 });
59
60 it('is a Chain', function() {
61 var cTest = types.chain;
62 var f = Future.of(2);
63 var f1 = function(x) {return Future.of((3 * x));};
64 var f2 = function(x) {return Future.of((5 + x));};
65
66 assert.equal(true, cTest.iface(f));
67 assert.equal(true, cTest.associative(f, f1, f2));
68 });
69
70 it('is a Monad', function() {
71 var mTest = types.monad;
72 var f = Future.of(null);
73 assert.equal(true, mTest.iface(f));
74 });
75
76 it('.map should work according to the functor specification', function() {
77 var result = Future.of(1).map(R.inc);
78 assert.equal(true, Future.of(2).equals(result));
79 });
80
81 it('.chain should work according to the chainable specification', function() {
82 var incInTheFuture = function(val) {
83 return Future.of(R.inc(val));
84 };
85 var result = Future.of(1).chain(incInTheFuture);
86 assert.equal(true, Future.of(2).equals(result));
87 });
88
89 describe('#ap', function() {
90 /*jshint browser:true */
91 var add = R.add;
92 function delayError(delay, err) {
93 /*jshint unused:false */
94 return new Future(function(reject, resolve) {
95 setTimeout(reject, delay, err);
96 });
97 }
98
99 function delayValue(delay, value) {
100 return new Future(function(reject, resolve) {
101 setTimeout(resolve, delay, value);
102 });
103 }
104
105 function assertCbVal(done, expectedVal) {
106 return function(val) {
107 assert.equal(expectedVal, val);
108 done();
109 };
110 }
111
112 it('applies its function to the passed in future', function() {
113 var f1 = Future.of(add(1));
114 var result = f1.ap(Future.of(2));
115 assert.equal(true, Future.of(3).equals(result));
116 });
117
118 it('does the apply in parallel', function(done) {
119 this.timeout(25);
120 var f1 = delayValue(15, 1);
121 var f2 = delayValue(15, 2);
122 f1.map(add).ap(f2).fork(null, assertCbVal(done, 3));
123 });
124
125 it('can handle itself being resolved first', function(done) {
126 var f1 = delayValue(1, 1);
127 var f2 = delayValue(15, 2);
128 f1.map(add).ap(f2).fork(null, assertCbVal(done, 3));
129 });
130
131 it('can handle the input future being resolved first', function(done) {
132 var f1 = delayValue(15, 1);
133 var f2 = delayValue(1, 2);
134 f1.map(add).ap(f2).fork(null, assertCbVal(done, 3));
135 });
136
137 it('is rejected with the first error to occur - case 1', function(done) {
138 var f1 = delayError(10, 'firstError');
139 var f2 = delayError(20, 'secondError');
140 f1.map(add).ap(f2).fork(assertCbVal(done, 'firstError'));
141 });
142
143 it('is rejected with the first error to occur - case 2', function(done) {
144 var f1 = delayError(20, 'firstError');
145 var f2 = delayError(10, 'secondError');
146 f1.map(add).ap(f2).fork(assertCbVal(done, 'secondError'));
147 });
148
149 });
150
151 describe('reject', function() {
152
153 it('creates a rejected future with the given value', function() {
154 var f = Future.reject('foo');
155 var forked;
156 f.fork(function(err) {
157 forked = true;
158 assert.equal('foo', err);
159 });
160 assert.equal(true, forked);
161 });
162
163 });
164
165 describe('#bimap', function() {
166
167 it('maps the first function over the rejected value', function() {
168 var f = Future.reject('err');
169 var result = f.bimap(R.concat('map over '));
170 result.fork(function(e) {
171 assert.equal(e, 'map over err');
172 });
173 });
174
175 it('maps the second function over the resolved value', function() {
176 var f = Future.of(1);
177 var result = f.bimap(null, R.add(1));
178 result.fork(null, function(v) {
179 assert.equal(v, 2);
180 });
181 });
182
183 });
184
185 describe('#toString', function() {
186
187 it('returns the string representation of a Future', function() {
188 assert.strictEqual(
189 Future(function(reject, resolve) { void resolve; }).toString(),
190 'Future(function (reject, resolve) { void resolve; })'
191 );
192 });
193
194 });
195
196});
197