1 | var R = require('ramda');
|
2 | var assert = require('assert');
|
3 | var types = require('./types');
|
4 | var Future = require('../src/Future');
|
5 |
|
6 | Future.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 |
|
23 | describe('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 |
|
91 | var add = R.add;
|
92 | function delayError(delay, err) {
|
93 |
|
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 |
|