util.x509: Nameprep commonName once
[prosody.git] / spec / util_promise_spec.lua
blob65d252f63253bbe858cf80a5b4757cbe9133f053
1 local promise = require "util.promise";
3 describe("util.promise", function ()
4 --luacheck: ignore 212/resolve 212/reject
5 describe("new()", function ()
6 it("returns a promise object", function ()
7 assert(promise.new());
8 end);
9 end);
10 it("notifies immediately for fulfilled promises", function ()
11 local p = promise.new(function (resolve)
12 resolve("foo");
13 end);
14 local cb = spy.new(function (v)
15 assert.equal("foo", v);
16 end);
17 p:next(cb);
18 assert.spy(cb).was_called(1);
19 end);
20 it("notifies on fulfilment of pending promises", function ()
21 local r;
22 local p = promise.new(function (resolve)
23 r = resolve;
24 end);
25 local cb = spy.new(function (v)
26 assert.equal("foo", v);
27 end);
28 p:next(cb);
29 assert.spy(cb).was_called(0);
30 r("foo");
31 assert.spy(cb).was_called(1);
32 end);
33 it("allows chaining :next() calls", function ()
34 local r;
35 local result;
36 local p = promise.new(function (resolve)
37 r = resolve;
38 end);
39 local cb1 = spy.new(function (v)
40 assert.equal("foo", v);
41 return "bar";
42 end);
43 local cb2 = spy.new(function (v)
44 assert.equal("bar", v);
45 result = v;
46 end);
47 p:next(cb1):next(cb2);
48 assert.spy(cb1).was_called(0);
49 assert.spy(cb2).was_called(0);
50 r("foo");
51 assert.spy(cb1).was_called(1);
52 assert.spy(cb2).was_called(1);
53 assert.equal("bar", result);
54 end);
55 it("supports multiple :next() calls on the same promise", function ()
56 local r;
57 local result;
58 local p = promise.new(function (resolve)
59 r = resolve;
60 end);
61 local cb1 = spy.new(function (v)
62 assert.equal("foo", v);
63 result = v;
64 end);
65 local cb2 = spy.new(function (v)
66 assert.equal("foo", v);
67 result = v;
68 end);
69 p:next(cb1);
70 p:next(cb2);
71 assert.spy(cb1).was_called(0);
72 assert.spy(cb2).was_called(0);
73 r("foo");
74 assert.spy(cb1).was_called(1);
75 assert.spy(cb2).was_called(1);
76 assert.equal("foo", result);
77 end);
78 it("automatically rejects on error", function ()
79 local r;
80 local p = promise.new(function (resolve)
81 r = resolve;
82 error("oh no");
83 end);
84 local cb = spy.new(function () end);
85 local err_cb = spy.new(function (v)
86 assert.equal("oh no", v);
87 end);
88 p:next(cb, err_cb);
89 assert.spy(cb).was_called(0);
90 assert.spy(err_cb).was_called(1);
91 r("foo");
92 assert.spy(cb).was_called(0);
93 assert.spy(err_cb).was_called(1);
94 end);
95 it("supports reject()", function ()
96 local r, result;
97 local p = promise.new(function (resolve, reject)
98 r = reject;
99 end);
100 local cb = spy.new(function () end);
101 local err_cb = spy.new(function (v)
102 result = v;
103 assert.equal("oh doh", v);
104 end);
105 p:next(cb, err_cb);
106 assert.spy(cb).was_called(0);
107 assert.spy(err_cb).was_called(0);
108 r("oh doh");
109 assert.spy(cb).was_called(0);
110 assert.spy(err_cb).was_called(1);
111 assert.equal("oh doh", result);
112 end);
113 it("supports chaining of rejected promises", function ()
114 local r, result;
115 local p = promise.new(function (resolve, reject)
116 r = reject;
117 end);
118 local cb = spy.new(function () end);
119 local err_cb = spy.new(function (v)
120 result = v;
121 assert.equal("oh doh", v);
122 return "ok"
123 end);
124 local cb2 = spy.new(function (v)
125 result = v;
126 end);
127 local err_cb2 = spy.new(function () end);
128 p:next(cb, err_cb):next(cb2, err_cb2)
129 assert.spy(cb).was_called(0);
130 assert.spy(err_cb).was_called(0);
131 assert.spy(cb2).was_called(0);
132 assert.spy(err_cb2).was_called(0);
133 r("oh doh");
134 assert.spy(cb).was_called(0);
135 assert.spy(err_cb).was_called(1);
136 assert.spy(cb2).was_called(1);
137 assert.spy(err_cb2).was_called(0);
138 assert.equal("ok", result);
139 end);
141 it("propagates errors down the chain, even when some handlers are not provided", function ()
142 local r, result;
143 local test_error = {};
144 local p = promise.new(function (resolve, reject)
145 r = reject;
146 end);
147 local cb = spy.new(function () end);
148 local err_cb = spy.new(function (e) result = e end);
149 local p2 = p:next(function () error(test_error) end);
150 local p3 = p2:next(cb)
151 p3:catch(err_cb);
152 assert.spy(cb).was_called(0);
153 assert.spy(err_cb).was_called(0);
154 r("oh doh");
155 assert.spy(cb).was_called(0);
156 assert.spy(err_cb).was_called(1);
157 assert.spy(err_cb).was_called_with("oh doh");
158 assert.equal("oh doh", result);
159 end);
161 it("propagates values down the chain, even when some handlers are not provided", function ()
162 local r;
163 local p = promise.new(function (resolve, reject)
164 r = resolve;
165 end);
166 local cb = spy.new(function () end);
167 local err_cb = spy.new(function () end);
168 local p2 = p:next(function (v) return v; end);
169 local p3 = p2:catch(err_cb)
170 p3:next(cb);
171 assert.spy(cb).was_called(0);
172 assert.spy(err_cb).was_called(0);
173 r(1337);
174 assert.spy(cb).was_called(1);
175 assert.spy(cb).was_called_with(1337);
176 assert.spy(err_cb).was_called(0);
177 end);
179 it("fulfilled promises do not call error handlers and do propagate value", function ()
180 local p = promise.resolve("foo");
181 local cb = spy.new(function () end);
182 local p2 = p:catch(cb);
183 assert.spy(cb).was_called(0);
185 local cb2 = spy.new(function () end);
186 p2:catch(cb2);
187 assert.spy(cb2).was_called(0);
188 end);
190 it("rejected promises do not call fulfilled handlers and do propagate reason", function ()
191 local p = promise.reject("foo");
192 local cb = spy.new(function () end);
193 local p2 = p:next(cb);
194 assert.spy(cb).was_called(0);
196 local cb2 = spy.new(function () end);
197 local cb2_err = spy.new(function () end);
198 p2:next(cb2, cb2_err);
199 assert.spy(cb2).was_called(0);
200 assert.spy(cb2_err).was_called(1);
201 assert.spy(cb2_err).was_called_with("foo");
202 end);
204 describe("allows callbacks to return", function ()
205 it("pending promises", function ()
206 local r;
207 local p = promise.resolve()
208 local cb = spy.new(function ()
209 return promise.new(function (resolve)
210 r = resolve;
211 end);
212 end);
213 local cb2 = spy.new(function () end);
214 p:next(cb):next(cb2);
215 assert.spy(cb).was_called(1);
216 assert.spy(cb2).was_called(0);
217 r("hello");
218 assert.spy(cb).was_called(1);
219 assert.spy(cb2).was_called(1);
220 assert.spy(cb2).was_called_with("hello");
221 end);
223 it("resolved promises", function ()
224 local p = promise.resolve()
225 local cb = spy.new(function ()
226 return promise.resolve("hello");
227 end);
228 local cb2 = spy.new(function () end);
229 p:next(cb):next(cb2);
230 assert.spy(cb).was_called(1);
231 assert.spy(cb2).was_called(1);
232 assert.spy(cb2).was_called_with("hello");
233 end);
235 it("rejected promises", function ()
236 local p = promise.resolve()
237 local cb = spy.new(function ()
238 return promise.reject("hello");
239 end);
240 local cb2 = spy.new(function ()
241 return promise.reject("goodbye");
242 end);
243 local cb3 = spy.new(function () end);
244 p:next(cb):catch(cb2):catch(cb3);
245 assert.spy(cb).was_called(1);
246 assert.spy(cb2).was_called(1);
247 assert.spy(cb2).was_called_with("hello");
248 assert.spy(cb3).was_called(1);
249 assert.spy(cb3).was_called_with("goodbye");
250 end);
251 end);
253 describe("race()", function ()
254 it("works with fulfilled promises", function ()
255 local p1, p2 = promise.resolve("yep"), promise.resolve("nope");
256 local p = promise.race({ p1, p2 });
257 local result;
258 p:next(function (v)
259 result = v;
260 end);
261 assert.equal("yep", result);
262 end);
263 it("works with pending promises", function ()
264 local r1, r2;
265 local p1, p2 = promise.new(function (resolve) r1 = resolve end), promise.new(function (resolve) r2 = resolve end);
266 local p = promise.race({ p1, p2 });
268 local result;
269 local cb = spy.new(function (v)
270 result = v;
271 end);
272 p:next(cb);
273 assert.spy(cb).was_called(0);
274 r2("yep");
275 r1("nope");
276 assert.spy(cb).was_called(1);
277 assert.equal("yep", result);
278 end);
279 end);
280 describe("all()", function ()
281 it("works with fulfilled promises", function ()
282 local p1, p2 = promise.resolve("yep"), promise.resolve("nope");
283 local p = promise.all({ p1, p2 });
284 local result;
285 p:next(function (v)
286 result = v;
287 end);
288 assert.same({ "yep", "nope" }, result);
289 end);
290 it("works with pending promises", function ()
291 local r1, r2;
292 local p1, p2 = promise.new(function (resolve) r1 = resolve end), promise.new(function (resolve) r2 = resolve end);
293 local p = promise.all({ p1, p2 });
295 local result;
296 local cb = spy.new(function (v)
297 result = v;
298 end);
299 p:next(cb);
300 assert.spy(cb).was_called(0);
301 r2("yep");
302 assert.spy(cb).was_called(0);
303 r1("nope");
304 assert.spy(cb).was_called(1);
305 assert.same({ "nope", "yep" }, result);
306 end);
307 it("rejects if any promise rejects", function ()
308 local r1, r2;
309 local p1 = promise.new(function (resolve, reject) r1 = reject end);
310 local p2 = promise.new(function (resolve, reject) r2 = reject end);
311 local p = promise.all({ p1, p2 });
313 local result;
314 local cb = spy.new(function (v)
315 result = v;
316 end);
317 local cb_err = spy.new(function (v)
318 result = v;
319 end);
320 p:next(cb, cb_err);
321 assert.spy(cb).was_called(0);
322 assert.spy(cb_err).was_called(0);
323 r2("fail");
324 assert.spy(cb).was_called(0);
325 assert.spy(cb_err).was_called(1);
326 r1("nope");
327 assert.spy(cb).was_called(0);
328 assert.spy(cb_err).was_called(1);
329 assert.equal("fail", result);
330 end);
331 end);
332 describe("catch()", function ()
333 it("works", function ()
334 local result;
335 local p = promise.new(function (resolve)
336 error({ foo = true });
337 end);
338 local cb1 = spy.new(function (v)
339 result = v;
340 end);
341 assert.spy(cb1).was_called(0);
342 p:catch(cb1);
343 assert.spy(cb1).was_called(1);
344 assert.same({ foo = true }, result);
345 end);
346 end);
347 it("promises may be resolved by other promises", function ()
348 local r1, r2;
349 local p1, p2 = promise.new(function (resolve) r1 = resolve end), promise.new(function (resolve) r2 = resolve end);
351 local result;
352 local cb = spy.new(function (v)
353 result = v;
354 end);
355 p1:next(cb);
356 assert.spy(cb).was_called(0);
358 r1(p2);
359 assert.spy(cb).was_called(0);
360 r2("yep");
361 assert.spy(cb).was_called(1);
362 assert.equal("yep", result);
363 end);
364 describe("reject()", function ()
365 it("returns a rejected promise", function ()
366 local p = promise.reject("foo");
367 local cb = spy.new(function () end);
368 p:catch(cb);
369 assert.spy(cb).was_called(1);
370 assert.spy(cb).was_called_with("foo");
371 end);
372 it("returns a rejected promise and does not call on_fulfilled", function ()
373 local p = promise.reject("foo");
374 local cb = spy.new(function () end);
375 p:next(cb);
376 assert.spy(cb).was_called(0);
377 end);
378 end);
379 describe("finally()", function ()
380 local p, p2, resolve, reject, on_finally;
381 before_each(function ()
382 p = promise.new(function (_resolve, _reject)
383 resolve, reject = _resolve, _reject;
384 end);
385 on_finally = spy.new(function () end);
386 p2 = p:finally(on_finally);
387 end);
388 it("runs when a promise is resolved", function ()
389 assert.spy(on_finally).was_called(0);
390 resolve("foo");
391 assert.spy(on_finally).was_called(1);
392 assert.spy(on_finally).was_not_called_with("foo");
393 end);
394 it("runs when a promise is rejected", function ()
395 assert.spy(on_finally).was_called(0);
396 reject("foo");
397 assert.spy(on_finally).was_called(1);
398 assert.spy(on_finally).was_not_called_with("foo");
399 end);
400 it("returns a promise that fulfills with the original value", function ()
401 local cb2 = spy.new(function () end);
402 p2:next(cb2);
403 assert.spy(on_finally).was_called(0);
404 assert.spy(cb2).was_called(0);
405 resolve("foo");
406 assert.spy(on_finally).was_called(1);
407 assert.spy(cb2).was_called(1);
408 assert.spy(on_finally).was_not_called_with("foo");
409 assert.spy(cb2).was_called_with("foo");
410 end);
411 it("returns a promise that rejects with the original error", function ()
412 local on_finally_err = spy.new(function () end);
413 local on_finally_ok = spy.new(function () end);
414 p2:catch(on_finally_err);
415 p2:next(on_finally_ok);
416 assert.spy(on_finally).was_called(0);
417 assert.spy(on_finally_err).was_called(0);
418 reject("foo");
419 assert.spy(on_finally).was_called(1);
420 -- Since the original promise was rejected, the finally promise should also be
421 assert.spy(on_finally_ok).was_called(0);
422 assert.spy(on_finally_err).was_called(1);
423 assert.spy(on_finally).was_not_called_with("foo");
424 assert.spy(on_finally_err).was_called_with("foo");
425 end);
426 it("returns a promise that rejects with an uncaught error inside on_finally", function ()
427 p = promise.new(function (_resolve, _reject)
428 resolve, reject = _resolve, _reject;
429 end);
430 local test_error = {};
431 on_finally = spy.new(function () error(test_error) end);
432 p2 = p:finally(on_finally);
434 local on_finally_err = spy.new(function () end);
435 p2:catch(on_finally_err);
436 assert.spy(on_finally).was_called(0);
437 assert.spy(on_finally_err).was_called(0);
438 reject("foo");
439 assert.spy(on_finally).was_called(1);
440 assert.spy(on_finally_err).was_called(1);
441 assert.spy(on_finally).was_not_called_with("foo");
442 assert.spy(on_finally).was_not_called_with(test_error);
443 assert.spy(on_finally_err).was_called_with(test_error);
444 end);
445 end);
446 describe("try()", function ()
447 it("works with functions that return a promise", function ()
448 local resolve;
449 local p = promise.try(function ()
450 return promise.new(function (_resolve)
451 resolve = _resolve;
452 end);
453 end);
454 assert.is_function(resolve);
455 local on_resolved = spy.new(function () end);
456 p:next(on_resolved);
457 assert.spy(on_resolved).was_not_called();
458 resolve("foo");
459 assert.spy(on_resolved).was_called_with("foo");
460 end);
462 it("works with functions that return a value", function ()
463 local p = promise.try(function ()
464 return "foo";
465 end);
466 local on_resolved = spy.new(function () end);
467 p:next(on_resolved);
468 assert.spy(on_resolved).was_called_with("foo");
469 end);
471 it("works with functions that return a promise that rejects", function ()
472 local reject;
473 local p = promise.try(function ()
474 return promise.new(function (_, _reject)
475 reject = _reject;
476 end);
477 end);
478 assert.is_function(reject);
479 local on_rejected = spy.new(function () end);
480 p:catch(on_rejected);
481 assert.spy(on_rejected).was_not_called();
482 reject("foo");
483 assert.spy(on_rejected).was_called_with("foo");
484 end);
486 it("works with functions that throw errors", function ()
487 local test_error = {};
488 local p = promise.try(function ()
489 error(test_error);
490 end);
491 local on_rejected = spy.new(function () end);
492 p:catch(on_rejected);
493 assert.spy(on_rejected).was_called(1);
494 assert.spy(on_rejected).was_called_with(test_error);
495 end);
496 end);
497 end);