summaryrefslogtreecommitdiff
path: root/src/tests/ecore/ecore_test_promise2.c
diff options
context:
space:
mode:
authorGuilherme Iscaro <iscaro@profusion.mobi>2017-08-08 18:11:23 -0300
committerGuilherme Iscaro <iscaro@profusion.mobi>2017-09-04 10:24:00 -0300
commit3ba9f25cf7ad74986bf77b679041ce2ad6758536 (patch)
tree1dbef24daeb1b047bace8a1f209cc1b5a8f6249b /src/tests/ecore/ecore_test_promise2.c
parentd12c652a965c177d35dd1e2c7f3774dc54f49f56 (diff)
Eina_Promise/Eina_Future: Add example and tests.
Diffstat (limited to '')
-rw-r--r--src/tests/ecore/ecore_test_promise2.c1286
1 files changed, 1286 insertions, 0 deletions
diff --git a/src/tests/ecore/ecore_test_promise2.c b/src/tests/ecore/ecore_test_promise2.c
new file mode 100644
index 0000000000..ea8d0d272e
--- /dev/null
+++ b/src/tests/ecore/ecore_test_promise2.c
@@ -0,0 +1,1286 @@
1#ifdef HAVE_CONFIG_H
2# include <config.h>
3#endif
4
5#include <Ecore.h>
6#include <Eina.h>
7#include <stdlib.h>
8#include <errno.h>
9#include <time.h>
10#include <stdarg.h>
11#include <Eo.h>
12#include "ecore_suite.h"
13
14#define CHAIN_SIZE (3)
15#define DEFAULT_ERROR (EFBIG)
16#define DEFAULT_MSG ("Future resolve is working!")
17#define DEFAULT_INT_VALUE (5466)
18#define DEFAULT_INT_VALUE_AS_STRING ("5466")
19#define DEFAULT_TIMEOUT (0.1)
20
21#define VALUE_TYPE_CHECK(_v, _type) \
22 do { \
23 ck_assert_ptr_eq(_v.type, _type); \
24} while(0)
25
26#define ERROR_CHECK(_v, _errno) \
27 do { \
28 Eina_Error _err; \
29 VALUE_TYPE_CHECK(_v, EINA_VALUE_TYPE_ERROR); \
30 fail_if(!eina_value_get(&_v, &_err)); \
31 ck_assert_int_eq(_err, _errno); \
32 } while (0)
33
34typedef struct _PromiseCtx {
35 Eina_Promise *p;
36 Ecore_Timer *t;
37 Eina_Bool fail;
38 Eina_Value *value;
39} PromiseCtx;
40
41typedef struct _Easy_Ctx {
42 Eina_Bool success_called;
43 Eina_Bool error_called;
44 Eina_Bool free_called;
45 Eina_Bool stop_loop;
46} Easy_Ctx;
47
48typedef struct _Race_Ctx {
49 Eina_Value value;
50 unsigned int success_idx;
51 unsigned int failed;
52 unsigned int success;
53} Race_Ctx;
54
55typedef struct _Race_Future_Ctx {
56 Race_Ctx *race_ctx;
57 unsigned int idx;
58 int value;
59} Race_Future_Ctx;
60
61#ifdef EINA_SAFETY_CHECKS
62
63#define LOG_CTX_MULTIPLE_FUNC_CTX_SET(_ctx, ...) \
64 do { \
65 _ctx.level = EINA_LOG_LEVEL_ERR; \
66 _ctx.did = EINA_FALSE; \
67 _ctx.just_fmt = EINA_FALSE; \
68 _ctx.func_ctx_idx = 0; \
69 _ctx.func_ctx = (struct Func_Ctx []){ __VA_ARGS__, {NULL, NULL}}; \
70 } while(0)
71
72#define LOG_CTX_SET(_ctx, _fnc, _msg) LOG_CTX_MULTIPLE_FUNC_CTX_SET(_ctx, {_fnc, _msg})
73
74typedef struct _Log_Ctx {
75 struct Func_Ctx {
76 const char *fnc;
77 const char *msg;
78 } *func_ctx;
79 int level;
80 int func_ctx_idx;
81 Eina_Bool did;
82 Eina_Bool just_fmt;
83} Log_Ctx;
84
85static void
86_eina_test_safety_print_cb(const Eina_Log_Domain *d,
87 Eina_Log_Level level,
88 const char *file,
89 const char *fnc, int line,
90 const char *fmt,
91 void *data,
92 va_list args)
93{
94 Log_Ctx *ctx = data;
95 va_list cp_args;
96 const char *str;
97
98 va_copy(cp_args, args);
99 str = va_arg(cp_args, const char *);
100 va_end(cp_args);
101
102 ck_assert_ptr_nonnull(ctx->func_ctx[ctx->func_ctx_idx].msg);
103 ck_assert_int_eq(level, ctx->level);
104 if (ctx->just_fmt)
105 ck_assert_str_eq(fmt, ctx->func_ctx[ctx->func_ctx_idx].msg);
106 else
107 {
108 ck_assert_str_eq(fmt, "%s");
109 ck_assert_str_eq(ctx->func_ctx[ctx->func_ctx_idx].msg, str);
110 }
111 ck_assert_str_eq(ctx->func_ctx[ctx->func_ctx_idx].fnc, fnc);
112 ctx->did = EINA_TRUE;
113 ctx->func_ctx_idx++;
114
115 (void)d;
116 (void)file;
117 (void)line;
118}
119#endif
120
121static void
122_cancel(void *data, const Eina_Promise *dead_ptr EINA_UNUSED)
123{
124 PromiseCtx *ctx = data;
125 if (ctx->t) ecore_timer_del(ctx->t);
126 ctx->t = NULL;
127 eina_value_free(ctx->value);
128 free(ctx);
129}
130
131static void
132_promise_cancel_test(void *data, const Eina_Promise *dead_ptr EINA_UNUSED)
133{
134 Eina_Bool *cancel_called = data;
135 *cancel_called = EINA_TRUE;
136}
137
138static Eina_Bool
139_simple_timeout(void *data)
140{
141 PromiseCtx *ctx = data;
142
143 if (ctx->fail) eina_promise_reject(ctx->p, DEFAULT_ERROR);
144 else
145 {
146 Eina_Value v;
147
148 fail_if(!eina_value_copy(ctx->value, &v));
149 eina_promise_resolve(ctx->p, v);
150 eina_value_free(ctx->value);
151 }
152 free(ctx);
153 return EINA_FALSE;
154}
155
156static Eina_Future_Scheduler *
157_future_scheduler_get(void)
158{
159 return efl_loop_future_scheduler_get(ecore_main_loop_get());
160}
161
162static PromiseCtx *
163_promise_ctx_new(void)
164{
165 PromiseCtx *ctx;
166 ctx = calloc(1, sizeof(PromiseCtx));
167 fail_if(!ctx);
168 ctx->p = eina_promise_new(_future_scheduler_get(), _cancel, ctx);
169 fail_if(!ctx->p);
170 return ctx;
171}
172
173static Eina_Future *
174_future_get(PromiseCtx *ctx, double timeout)
175{
176 Eina_Future *f;
177
178 f = eina_future_new(ctx->p);
179 fail_if(!f);
180 ctx->t = ecore_timer_add(timeout, _simple_timeout, ctx);
181 fail_if(!ctx->t);
182 return f;
183}
184
185static Eina_Future *
186_fail_future_get(void)
187{
188 PromiseCtx *ctx = _promise_ctx_new();
189 ctx->fail = EINA_TRUE;
190 return _future_get(ctx, DEFAULT_TIMEOUT);
191}
192
193static Eina_Future *
194_int_future_with_value_and_timeout(int value, double timeout)
195{
196 PromiseCtx *ctx = _promise_ctx_new();
197 ctx->value = eina_value_util_int_new(value);
198 fail_if(!ctx->value);
199 return _future_get(ctx, timeout);
200}
201
202static Eina_Future *
203_int_future_get(void)
204{
205 return _int_future_with_value_and_timeout(DEFAULT_INT_VALUE, DEFAULT_TIMEOUT);
206}
207
208static Eina_Future *
209_str_future_get(void)
210{
211 PromiseCtx *ctx = _promise_ctx_new();
212 ctx->value = eina_value_util_string_new(DEFAULT_MSG);
213 fail_if(!ctx->value);
214 return _future_get(ctx, DEFAULT_TIMEOUT);
215}
216
217static Eina_Value
218_simple_err(void *data EINA_UNUSED, const Eina_Value v, const Eina_Future *dead_future EINA_UNUSED)
219{
220 ERROR_CHECK(v, DEFAULT_ERROR);
221 ecore_main_loop_quit();
222 return v;
223}
224
225static Eina_Value
226_simple_ok(void *data EINA_UNUSED, const Eina_Value v, const Eina_Future *dead_future EINA_UNUSED)
227{
228 const char *msg;
229
230 VALUE_TYPE_CHECK(v, EINA_VALUE_TYPE_STRING);
231 fail_if(!eina_value_get(&v, &msg));
232 ck_assert_str_eq(DEFAULT_MSG, msg);
233 ecore_main_loop_quit();
234 return v;
235}
236
237static Eina_Value
238_chain_stop(void *data, const Eina_Value v, const Eina_Future *dead_future EINA_UNUSED)
239{
240 int *i = data;
241 fail_if(*i != CHAIN_SIZE);
242 ecore_main_loop_quit();
243 return v;
244}
245
246static Eina_Value
247_chain_no_error(void *data, const Eina_Value v, const Eina_Future *dead_future EINA_UNUSED)
248{
249 Eina_Value new_v;
250 static int count = DEFAULT_INT_VALUE;
251 int current_i;
252 int *i = data;
253
254 VALUE_TYPE_CHECK(v, EINA_VALUE_TYPE_INT);
255 fail_if(!eina_value_get(&v, &current_i));
256 fail_if(current_i != count++);
257 fail_if(!eina_value_setup(&new_v, EINA_VALUE_TYPE_INT));
258 fail_if(!eina_value_set(&new_v, count));
259 (*i)++;
260 return new_v;
261}
262
263static Eina_Value
264_chain_error(void *data, const Eina_Value v, const Eina_Future *dead_future EINA_UNUSED)
265{
266 int *i = data;
267
268 ERROR_CHECK(v, DEFAULT_ERROR);
269 (*i)++;
270 return v;
271}
272
273static Eina_Value
274_cancel_cb(void *data, const Eina_Value v, const Eina_Future *dead_future EINA_UNUSED)
275{
276 Eina_Value new_v;
277 int *cancel_count = data;
278
279 fail_if(!eina_value_setup(&new_v, EINA_VALUE_TYPE_INT));
280 ERROR_CHECK(v, ECANCELED);
281 (*cancel_count)++;
282 /* Although this function returns an INT Eina_Value, the next
283 _cancel_cb must receive a EINA_VALYE_TYPE_ERROR as ECANCELED */
284 return new_v;
285}
286
287static Eina_Value
288_inner_resolve(void *data, const Eina_Value v, const Eina_Future *dead_future EINA_UNUSED)
289{
290 Eina_Value new_v;
291 fail_if(!eina_value_setup(&new_v, EINA_VALUE_TYPE_STRING));
292 fail_if(!eina_value_set(&new_v, DEFAULT_MSG));
293 eina_promise_resolve(data, new_v);
294 return v;
295}
296
297static Eina_Value
298_inner_fail(void *data, const Eina_Value v, const Eina_Future *dead_future EINA_UNUSED)
299{
300 eina_promise_reject(data, DEFAULT_ERROR);
301 return v;
302}
303
304static void
305_inner_promise_cancel(void *data EINA_UNUSED, const Eina_Promise *dead_ptr EINA_UNUSED)
306{
307 //This must never happen...
308 fail_if(EINA_FALSE);
309}
310
311static Eina_Value
312_future_promise_create(void *data, const Eina_Value v EINA_UNUSED, const Eina_Future *dead_future EINA_UNUSED)
313{
314 Eina_Promise *p;
315
316 p = eina_promise_new(_future_scheduler_get(), _inner_promise_cancel, NULL);
317 fail_if(!p);
318 eina_future_then(_str_future_get(),
319 data ? _inner_fail : _inner_resolve,
320 p);
321 return eina_promise_as_value(p);
322}
323
324static Eina_Value
325_inner_future_last(void *data, const Eina_Value v, const Eina_Future *dead_future EINA_UNUSED)
326{
327 if (data)
328 ERROR_CHECK(v, DEFAULT_ERROR);
329 else
330 {
331 const char *msg;
332 VALUE_TYPE_CHECK(v, EINA_VALUE_TYPE_STRING);
333 fail_if(!eina_value_get(&v, &msg));
334 ck_assert_str_eq(DEFAULT_MSG, msg);
335 }
336 ecore_main_loop_quit();
337 return v;
338}
339
340static Eina_Value
341_convert_check(void *data EINA_UNUSED, const Eina_Value v, const Eina_Future *dead_future EINA_UNUSED)
342{
343 const char *number;
344 VALUE_TYPE_CHECK(v, EINA_VALUE_TYPE_STRING);
345 fail_if(!eina_value_get(&v, &number));
346 ck_assert_str_eq(DEFAULT_INT_VALUE_AS_STRING, number);
347 ecore_main_loop_quit();
348 return v;
349}
350
351static Eina_Value
352_easy_success(void *data, const Eina_Value v)
353{
354 Easy_Ctx *ctx = data;
355 const char *msg;
356
357 ctx->success_called = EINA_TRUE;
358 VALUE_TYPE_CHECK(v, EINA_VALUE_TYPE_STRING);
359 fail_if(!eina_value_get(&v, &msg));
360 ck_assert_str_eq(DEFAULT_MSG, msg);
361 return v;
362}
363
364static Eina_Value
365_easy_error(void *data, const Eina_Error err)
366{
367 Eina_Value v;
368 Easy_Ctx *ctx = data;
369 fail_if(err != EINVAL);
370 fail_if(!eina_value_setup(&v, EINA_VALUE_TYPE_ERROR));
371 fail_if(!eina_value_set(&v, err));
372 ctx->error_called = EINA_TRUE;
373 return v;
374}
375
376static void
377_easy_free(void *data, const Eina_Future *dead_future EINA_UNUSED)
378{
379 Easy_Ctx *ctx = data;
380 ctx->free_called = EINA_TRUE;
381 if (ctx->stop_loop) ecore_main_loop_quit();
382}
383
384static Eina_Value
385_all_cb(void *data, const Eina_Value array, const Eina_Future *dead EINA_UNUSED)
386{
387 unsigned int len, i, *expected_len = data;
388
389 VALUE_TYPE_CHECK(array, EINA_VALUE_TYPE_ARRAY);
390 len = eina_value_array_count(&array);
391 fail_if(len != *expected_len);
392
393 for (i = 0; i < len; i++)
394 {
395 Eina_Value v;
396
397 fail_if(!eina_value_array_get(&array, i, &v));
398 if (i % 2 == 0)
399 {
400 const char *msg;
401 VALUE_TYPE_CHECK(v, EINA_VALUE_TYPE_STRING);
402 fail_if(!eina_value_get(&v, &msg));
403 ck_assert_str_eq(DEFAULT_MSG, msg);
404 }
405 else
406 {
407 int ivalue = 0;
408 VALUE_TYPE_CHECK(v, EINA_VALUE_TYPE_INT);
409 fail_if(!eina_value_get(&v, &ivalue));
410 fail_if(ivalue != DEFAULT_INT_VALUE);
411 }
412 eina_value_flush(&v);
413 }
414 ecore_main_loop_quit();
415 return array;
416}
417
418static Eina_Value
419_future_all_count(void *data, const Eina_Value v, const Eina_Future *dead EINA_UNUSED)
420{
421 unsigned int *futures_called = data;
422 (*futures_called)++;
423 return v;
424}
425
426static Eina_Value
427_race_cb(void *data, const Eina_Value v, const Eina_Future *dead EINA_UNUSED)
428{
429 Race_Future_Ctx *future_ctx = data;
430 Race_Ctx *ctx = future_ctx->race_ctx;
431
432 if (v.type == EINA_VALUE_TYPE_ERROR)
433 {
434 Eina_Error err;
435 eina_value_get(&v, &err);
436 fail_if(err != ECANCELED);
437 ctx->failed++;
438 }
439 else if (v.type == EINA_VALUE_TYPE_INT)
440 {
441 int i;
442 fail_if(!eina_value_get(&v, &i));
443 fail_if(future_ctx->value != i);
444 ctx->success++;
445 ctx->success_idx = future_ctx->idx;
446 fail_if(!eina_value_copy(&v, &ctx->value));
447 }
448 else fail_if(EINA_TRUE); //This is not supposed to happen!
449 free(future_ctx);
450 return v;
451}
452
453static Eina_Value
454_race_end_cb(void *data, const Eina_Value v, const Eina_Future *dead EINA_UNUSED)
455{
456 Race_Ctx *ctx = data;
457 unsigned int idx;
458 Eina_Value_Struct *st;
459 Eina_Value r;
460
461 VALUE_TYPE_CHECK(v, EINA_VALUE_TYPE_STRUCT);
462
463 st = eina_value_memory_get(&v);
464 fail_if(!st);
465 fail_if(st->desc != EINA_PROMISE_RACE_STRUCT_DESC);
466 fail_if(!eina_value_struct_get(&v, "index", &idx));
467 fail_if(idx != ctx->success_idx);
468 fail_if(!eina_value_struct_get(&v, "value", &r));
469 fail_if(eina_value_compare(&r, &ctx->value));
470 eina_value_flush(&r);
471 ecore_main_loop_quit();
472 return v;
473}
474
475START_TEST(efl_test_promise_future_success)
476{
477 Eina_Future *f;
478 fail_if(!ecore_init());
479 f = eina_future_then(_str_future_get(),
480 _simple_ok, NULL);
481 fail_if(!f);
482 ecore_main_loop_begin();
483 ecore_shutdown();
484}
485END_TEST
486
487START_TEST(efl_test_promise_future_failure)
488{
489 Eina_Future *f;
490 fail_if(!ecore_init());
491 f = eina_future_then(_fail_future_get(),
492 _simple_err, NULL);
493 fail_if(!f);
494 ecore_main_loop_begin();
495 ecore_shutdown();
496}
497END_TEST
498
499START_TEST(efl_test_promise_future_chain_no_error)
500{
501 Eina_Future *f;
502 static int i = 0;
503
504 fail_if(!ecore_init());
505 f = eina_future_chain(_int_future_get(),
506 {.cb = _chain_no_error, .data = &i},
507 {.cb = _chain_no_error, .data = &i},
508 {.cb = _chain_no_error, .data = &i},
509 {.cb = _chain_stop, .data = &i});
510 fail_if(!f);
511 ecore_main_loop_begin();
512 ecore_shutdown();
513}
514END_TEST
515
516START_TEST(efl_test_promise_future_chain_error)
517{
518 Eina_Future *f;
519 static int i = 0;
520
521 fail_if(!ecore_init());
522 f = eina_future_chain(_fail_future_get(),
523 {.cb = _chain_error, .data = &i},
524 {.cb = _chain_error, .data = &i},
525 {.cb = _chain_error, .data = &i},
526 {.cb = _chain_stop, .data = &i});
527 fail_if(!f);
528 ecore_main_loop_begin();
529 ecore_shutdown();
530}
531END_TEST
532
533START_TEST(efl_test_promise_future_cancel)
534{
535 fail_if(!ecore_init());
536 int i;
537
538 for (i = 0; i < 3; i++)
539 {
540 Eina_Promise *p;
541 Eina_Future *first, *last, *middle;
542 int cancel_count = 0;
543 Eina_Bool cancel_called = EINA_FALSE;
544
545 p = eina_promise_new(_future_scheduler_get(), _promise_cancel_test, &cancel_called);
546 fail_if(!p);
547 first = eina_future_new(p);
548 fail_if(!first);
549 if (i == 2)
550 {
551 Eina_Future *f;
552 last = NULL;
553 f = eina_future_then(first, _cancel_cb, &cancel_count);
554 fail_if(!f);
555 middle = eina_future_then(f, _cancel_cb, &cancel_count);
556 fail_if(!middle);
557 f = eina_future_then(middle, _cancel_cb, &cancel_count);
558 fail_if(!f);
559 }
560 else
561 {
562 middle = NULL;
563 last = eina_future_chain(first,
564 {.cb = _cancel_cb, .data = &cancel_count},
565 {.cb = _cancel_cb, .data = &cancel_count},
566 {.cb = _cancel_cb, .data = &cancel_count});
567 fail_if(!last);
568 }
569 if (i == 0)
570 eina_future_cancel(last);
571 else if (i == 1)
572 eina_future_cancel(first);
573 else
574 eina_future_cancel(middle);
575 fail_if(cancel_count != CHAIN_SIZE);
576 fail_if(!cancel_called);
577 }
578 ecore_shutdown();
579}
580END_TEST
581
582START_TEST(efl_test_promise_future_inner_promise)
583{
584 Eina_Future *f;
585
586 fail_if(!ecore_init());
587 f = eina_future_chain(_str_future_get(),
588 {.cb = _future_promise_create, .data = NULL},
589 {.cb = _inner_future_last, .data = NULL});
590 fail_if(!f);
591 ecore_main_loop_begin();
592 ecore_shutdown();
593}
594END_TEST
595
596START_TEST(efl_test_promise_future_inner_promise_fail)
597{
598 Eina_Future *f;
599 void *data =(void *) 0x01;
600
601 fail_if(!ecore_init());
602 f = eina_future_chain(_str_future_get(),
603 {.cb = _future_promise_create, .data = data},
604 {.cb = _inner_future_last, .data = data});
605 fail_if(!f);
606 ecore_main_loop_begin();
607 ecore_shutdown();
608}
609END_TEST
610
611START_TEST(efl_test_promise_future_implicit_cancel)
612{
613 Eina_Promise *p;
614 Eina_Future *f;
615 int cancel_count = 0;
616 Eina_Bool cancel_called = EINA_FALSE;
617 Eina_Value v = EINA_VALUE_EMPTY;
618
619 fail_if(!ecore_init());
620
621 p = eina_promise_new(_future_scheduler_get(), _promise_cancel_test, &cancel_called);
622 fail_if(!p);
623 f = eina_future_new(p);
624 fail_if(!f);
625 f = eina_future_chain(f,
626 {.cb = _cancel_cb, .data = &cancel_count},
627 {.cb = _cancel_cb, .data = &cancel_count},
628 {.cb = _cancel_cb, .data = &cancel_count});
629 fail_if(!f);
630 eina_promise_resolve(p, v);
631 /*
632 The promise was resolved, but the mainloop is not running.
633 Since ecore_shutdown() will be called all the futures must be cancelled
634 */
635 ecore_shutdown();
636 //All the futures were cancelled at this point
637 fail_if(cancel_count != CHAIN_SIZE);
638 //Cancel should not be called, since we called eina_promise_resolve()
639 fail_if(cancel_called);
640}
641END_TEST
642
643START_TEST(efl_test_promise_future_convert)
644{
645 Eina_Future *f;
646
647 fail_if(!ecore_init());
648 f = eina_future_chain(_int_future_get(),
649 eina_future_cb_convert_to(EINA_VALUE_TYPE_STRING),
650 { .cb = _convert_check, .data = NULL });
651 fail_if(!f);
652 ecore_main_loop_begin();
653 ecore_shutdown();
654
655}
656END_TEST
657
658START_TEST(efl_test_promise_future_easy)
659{
660 Eina_Future *f;
661 Easy_Ctx easy1 = { 0 };
662 Easy_Ctx easy2 = { 0 };
663 Easy_Ctx easy3 = { 0 };
664
665 easy3.stop_loop = EINA_TRUE;
666 fail_if(!ecore_init());
667 f = eina_future_then_from_desc(_str_future_get(),
668 eina_future_cb_easy(_easy_success,
669 _easy_error,
670 _easy_free,
671 EINA_VALUE_TYPE_STRING,
672 &easy1));
673 fail_if(!f);
674 f = eina_future_then_easy(f, _easy_success, _easy_error,
675 _easy_free, NULL, &easy2);
676 fail_if(!f);
677 f = eina_future_chain_easy(f, {_easy_success, _easy_error,
678 _easy_free, EINA_VALUE_TYPE_INT, &easy3});
679 fail_if(!f);
680 ecore_main_loop_begin();
681 ecore_shutdown();
682 fail_if(!(easy1.success_called && !easy1.error_called && easy1.free_called));
683 fail_if(!(easy2.success_called && !easy2.error_called && easy2.free_called));
684 fail_if(!(!easy3.success_called && easy3.error_called && easy3.free_called));
685}
686END_TEST
687
688START_TEST(efl_test_promise_future_all)
689{
690 Eina_Future *futures[11];
691 unsigned int i, futures_called = 0, len = EINA_C_ARRAY_LENGTH(futures);
692
693 fail_if(!ecore_init());
694 for (i = 0; i < len - 1; i++)
695 {
696 Eina_Future *f;
697 if (i % 2 == 0)
698 f = _str_future_get();
699 else
700 f = _int_future_get();
701 fail_if(!f);
702 futures[i] = eina_future_then(f, _future_all_count, &futures_called);
703 fail_if(!futures[i]);
704 }
705
706 futures[--len] = EINA_FUTURE_SENTINEL;
707 fail_if(!eina_future_then(eina_future_all_array(futures), _all_cb, &len));
708 ecore_main_loop_begin();
709 ecore_shutdown();
710 fail_if(futures_called != len);
711}
712END_TEST
713
714START_TEST(efl_test_promise_future_race)
715{
716 Race_Ctx ctx = { 0 };
717 Eina_Future *futures[11];
718 unsigned int i, len = EINA_C_ARRAY_LENGTH(futures);
719 double timeouts[10] = {
720 2.0, 1.0, 0.5, 0.1, 4.5, 2.3, 5.6, 1.0, 0.5, 0.3
721 };
722
723 srand(time(NULL));
724 fail_if(!ecore_init());
725 for (i = 0; i < len - 1; i++)
726 {
727 Race_Future_Ctx *future_ctx = calloc(1, sizeof(Race_Future_Ctx));
728 fail_if(!future_ctx);
729 future_ctx->race_ctx = &ctx;
730 future_ctx->idx = i;
731 future_ctx->value = rand() % RAND_MAX;
732 futures[i] = eina_future_then(_int_future_with_value_and_timeout(future_ctx->value, timeouts[i]),
733 _race_cb, future_ctx);
734 fail_if(!futures[i]);
735 }
736
737 futures[--len] = EINA_FUTURE_SENTINEL;
738 fail_if(!eina_future_then(eina_future_race_array(futures),
739 _race_end_cb, &ctx));
740 ecore_main_loop_begin();
741 eina_value_flush(&ctx.value);
742 ecore_shutdown();
743 fail_if(ctx.success != 1);
744 fail_if(ctx.failed != (len - 1));
745}
746END_TEST
747
748static Eina_Value
749_eo_future1_ok(Eo *eo EINA_UNUSED, const Eina_Value v)
750{
751 const char *number;
752
753 VALUE_TYPE_CHECK(v, EINA_VALUE_TYPE_STRING);
754 fail_if(!eina_value_get(&v, &number));
755 ck_assert_str_eq(DEFAULT_INT_VALUE_AS_STRING, number);
756 return v;
757}
758
759static Eina_Value
760_eo_future1_err(Eo *eo EINA_UNUSED, Eina_Error err EINA_UNUSED)
761{
762 //Should not happen
763 fail_if(EINA_TRUE);
764}
765
766static Eina_Value
767_eo_future2_ok(Eo *eo EINA_UNUSED, const Eina_Value v)
768{
769 //Should not happen
770 fail_if(EINA_TRUE);
771 return v;
772}
773
774static Eina_Value
775_eo_future2_err(Eo *eo EINA_UNUSED, Eina_Error err)
776{
777 Eina_Value v;
778
779 fail_if(err != EINVAL);
780 fail_if(!eina_value_setup(&v, EINA_VALUE_TYPE_INT));
781 fail_if(!eina_value_set(&v, DEFAULT_INT_VALUE));
782 return v;
783}
784
785static void
786_eo_future_free(Eo *eo, const Eina_Future *dead EINA_UNUSED)
787{
788 int *free_called = efl_key_data_get(eo, "free_called");
789 (*free_called)++;
790}
791
792static Eina_Value
793_eo_chain_stop(void *data EINA_UNUSED, const Eina_Value v, const Eina_Future *dead_future EINA_UNUSED)
794{
795 int ivalue = 0;
796 VALUE_TYPE_CHECK(v, EINA_VALUE_TYPE_INT);
797 fail_if(!eina_value_get(&v, &ivalue));
798 ck_assert_int_eq(ivalue, DEFAULT_INT_VALUE);
799 ecore_main_loop_quit();
800 return v;
801}
802
803START_TEST(efl_test_promise_eo)
804{
805 Eina_Future *f;
806 Eo *obj;
807 int free_called = 0;
808
809 fail_if(!efl_object_init());
810 fail_if(!ecore_init());
811
812 //Use a random object..
813 obj = efl_add(EFL_IO_BUFFER_CLASS, NULL);
814 fail_if(!obj);
815 efl_key_data_set(obj, "free_called", &free_called);
816 f = eina_future_chain(_int_future_get(),
817 eina_future_cb_convert_to(EINA_VALUE_TYPE_STRING),
818 efl_future_cb(obj, _eo_future1_ok, _eo_future1_err, _eo_future_free, EINA_VALUE_TYPE_STRING),
819 efl_future_cb(obj, _eo_future2_ok, _eo_future2_err, _eo_future_free, EINA_VALUE_TYPE_INT),
820 { .cb = _eo_chain_stop });
821 fail_if(!f);
822 ecore_main_loop_begin();
823 efl_unref(obj);
824 ecore_shutdown();
825 efl_object_shutdown();
826 ck_assert_int_eq(free_called, 2);
827}
828END_TEST
829
830static Eina_Value
831_eo_future_link_success(Eo *eo EINA_UNUSED, const Eina_Value v)
832{
833 //This should never happen
834 fail_if(EINA_TRUE);
835 return v;
836}
837
838static Eina_Value
839_eo_future_link_err(Eo *eo, Eina_Error err)
840{
841 int *err_called = efl_key_data_get(eo, "err_called");
842 Eina_Value v;
843
844 fail_if(!err_called);
845 ck_assert_int_eq(err, ECANCELED);
846 fail_if(!eina_value_setup(&v, EINA_VALUE_TYPE_ERROR));
847 fail_if(!eina_value_set(&v, err));
848 (*err_called)++;
849 return v;
850}
851
852static Eina_Value
853_eo_link_chain_end(void *data EINA_UNUSED, const Eina_Value v, const Eina_Future *dead EINA_UNUSED)
854{
855 int *err_called = data;
856 VALUE_TYPE_CHECK(v, EINA_VALUE_TYPE_ERROR);
857 ERROR_CHECK(v, ECANCELED);
858 (*err_called)++;
859 return v;
860}
861
862START_TEST(efl_test_promise_eo_link)
863{
864 Eina_Future *f;
865 Eo *obj;
866 int err_called = 0;
867
868 fail_if(!efl_object_init());
869 fail_if(!ecore_init());
870
871 //Use a random object..
872 obj = efl_add(EFL_IO_BUFFER_CLASS, NULL);
873 fail_if(!obj);
874
875 efl_key_data_set(obj, "err_called", &err_called);
876 fail_if(!efl_key_data_get(obj, "err_called"));
877 f = efl_future_chain(obj, _int_future_get(),
878 {.success = _eo_future_link_success, .error = _eo_future_link_err},
879 {.success = _eo_future_link_success, .error = _eo_future_link_err},
880 {.success = _eo_future_link_success, .error = _eo_future_link_err},
881 {.success = _eo_future_link_success, .error = _eo_future_link_err},
882 {.success = _eo_future_link_success, .error = _eo_future_link_err});
883 fail_if(!f);
884 f = eina_future_then(f, _eo_link_chain_end, &err_called);
885 fail_if(!f);
886 /*
887 Since the mainloop is not running and the object is deleted the whole chain must be cancelled.
888 */
889 efl_unref(obj);
890 ecore_shutdown();
891 efl_object_shutdown();
892 ck_assert_int_eq(err_called, 6);
893}
894END_TEST
895
896static Eina_Value
897_err_ignored(void *data EINA_UNUSED, const Eina_Value v, const Eina_Future *f EINA_UNUSED)
898{
899 //Must be NULL since the error must be ignored.
900 VALUE_TYPE_CHECK(v, NULL);
901 ecore_main_loop_quit();
902 return v;
903}
904
905START_TEST(efl_test_promise_future_ignore_error)
906{
907 Eina_Future *f;
908
909 fail_if(!ecore_init());
910 f = _fail_future_get();
911 fail_if(!f);
912 eina_future_chain(f, eina_future_cb_ignore_error(DEFAULT_ERROR),
913 {.cb = _err_ignored});
914 ecore_main_loop_begin();
915 ecore_shutdown();
916}
917END_TEST
918
919#define PROMISE_LOG_DOMAIN_STR ("promise_test_domain")
920
921typedef struct _Promise_Log_Ctx {
922 Eina_Future_Cb_Log_Desc dbg;
923 Eina_Future_Cb_Log_Desc crit;
924 Eina_Future_Cb_Log_Desc warn;
925 Eina_Future_Cb_Log_Desc info;
926 Eina_Future_Cb_Log_Desc err;
927 Eina_Bool dbg_log_ok;
928 Eina_Bool crit_log_ok;
929 Eina_Bool warn_log_ok;
930 Eina_Bool info_log_ok;
931 Eina_Bool err_log_ok;
932} Promise_Log_Ctx;
933
934static Eina_Value
935_log_quit(void *data EINA_UNUSED, const Eina_Value v, const Eina_Future *dead EINA_UNUSED)
936{
937 int ivalue;
938
939 VALUE_TYPE_CHECK(v, EINA_VALUE_TYPE_INT);
940 fail_if(!eina_value_get(&v, &ivalue));
941 fail_if(ivalue != DEFAULT_INT_VALUE);
942 ecore_main_loop_quit();
943 return v;
944}
945
946static void
947_log_test(const Eina_Log_Domain *d,
948 Eina_Log_Level level,
949 const char *file, const char *fnc, int line,
950 const char *fmt, void *data, va_list args)
951{
952 Promise_Log_Ctx *ctx = data;
953 Eina_Bool *log_ok;
954 Eina_Future_Cb_Log_Desc *desc;
955 va_list cpy;
956 const char *prefix, *suffix, *value;
957
958 if (strcmp(d->name, PROMISE_LOG_DOMAIN_STR))
959 return;
960
961 switch (level)
962 {
963 case EINA_LOG_LEVEL_DBG:
964 log_ok = &ctx->dbg_log_ok;
965 desc = &ctx->dbg;
966 break;
967 case EINA_LOG_LEVEL_CRITICAL:
968 log_ok = &ctx->crit_log_ok;
969 desc = &ctx->crit;
970 break;
971 case EINA_LOG_LEVEL_WARN:
972 log_ok = &ctx->warn_log_ok;
973 desc = &ctx->warn;
974 break;
975 case EINA_LOG_LEVEL_INFO:
976 log_ok = &ctx->info_log_ok;
977 desc = &ctx->info;
978 break;
979 default:
980 log_ok = &ctx->err_log_ok;
981 desc = &ctx->err;
982 }
983
984 ck_assert_str_eq(fnc, desc->func);
985 ck_assert_str_eq(file, desc->file);
986 ck_assert_str_eq(fmt, "%s%s%s");
987 ck_assert_int_eq(desc->line, line);
988 //FIXME: REmove this check
989 ck_assert_int_eq(desc->level, level);
990 va_copy(cpy, args);
991 prefix = va_arg(cpy, const char *);
992 value = va_arg(cpy, const char *);
993 suffix = va_arg(cpy, const char *);
994 ck_assert_str_eq(prefix, desc->prefix ? desc->prefix : "");
995 ck_assert_str_eq(suffix, desc->suffix ? desc->suffix : "");
996 ck_assert_str_eq(value, DEFAULT_INT_VALUE_AS_STRING);
997 va_end(cpy);
998 *log_ok = EINA_TRUE;
999}
1000
1001START_TEST(efl_test_promise_log)
1002{
1003 Promise_Log_Ctx ctx = { 0 };
1004 Eina_Future *f;
1005 int domain;
1006
1007 fail_if(!ecore_init());
1008
1009 domain = eina_log_domain_register(PROMISE_LOG_DOMAIN_STR, EINA_COLOR_CYAN);
1010 fail_if(domain < 0);
1011 eina_log_domain_level_set(PROMISE_LOG_DOMAIN_STR, EINA_LOG_LEVEL_DBG);
1012 ctx.dbg = (Eina_Future_Cb_Log_Desc){"dbg prefix:", " dbg suffix", __FILE__,
1013 __FUNCTION__, EINA_LOG_LEVEL_DBG,
1014 domain, __LINE__};
1015 ctx.crit = (Eina_Future_Cb_Log_Desc){NULL, NULL, __FILE__,
1016 __FUNCTION__, EINA_LOG_LEVEL_CRITICAL,
1017 domain, __LINE__};
1018 ctx.warn = (Eina_Future_Cb_Log_Desc){"warn prefix:", NULL, __FILE__,
1019 __FUNCTION__, EINA_LOG_LEVEL_WARN,
1020 domain, __LINE__};
1021 ctx.err = (Eina_Future_Cb_Log_Desc){NULL, " err suffix", __FILE__,
1022 __FUNCTION__, EINA_LOG_LEVEL_ERR,
1023 domain, __LINE__};
1024 ctx.info = (Eina_Future_Cb_Log_Desc){"info prefix:", " info suffix",
1025 __FILE__, __FUNCTION__, EINA_LOG_LEVEL_INFO,
1026 domain, __LINE__};
1027 eina_log_print_cb_set(_log_test, &ctx);
1028 f = eina_future_chain(_int_future_get(),
1029 eina_future_cb_log_from_desc(ctx.dbg),
1030 eina_future_cb_log_from_desc(ctx.crit),
1031 eina_future_cb_log_from_desc(ctx.warn),
1032 eina_future_cb_log_from_desc(ctx.err),
1033 eina_future_cb_log_from_desc(ctx.info),
1034 { _log_quit });
1035 fail_if(!f);
1036 ecore_main_loop_begin();
1037 eina_log_domain_unregister(domain);
1038 ecore_shutdown();
1039 fail_if(!ctx.dbg_log_ok);
1040 fail_if(!ctx.crit_log_ok);
1041 fail_if(!ctx.warn_log_ok);
1042 fail_if(!ctx.err_log_ok);
1043 fail_if(!ctx.info_log_ok);
1044}
1045END_TEST
1046
1047#ifdef EINA_SAFETY_CHECKS
1048
1049static void
1050_dummy_cancel(void *data EINA_UNUSED, const Eina_Promise *dead EINA_UNUSED)
1051{
1052}
1053
1054START_TEST(efl_test_promise_null)
1055{
1056 Log_Ctx ctx = { 0 };
1057 Eina_Promise *p;
1058
1059 fail_if(!ecore_init());
1060
1061 eina_log_print_cb_set(_eina_test_safety_print_cb, &ctx);
1062 LOG_CTX_SET(ctx, "eina_promise_new", "safety check failed: scheduler == NULL");
1063 p = eina_promise_new(NULL, _dummy_cancel, NULL);
1064 ck_assert_ptr_null(p);
1065 fail_unless(ctx.did);
1066
1067 LOG_CTX_SET(ctx, "eina_promise_new", "safety check failed: cancel_cb == NULL");
1068 p = eina_promise_new(_future_scheduler_get(), NULL, NULL);
1069 ck_assert_ptr_null(p);
1070 fail_unless(ctx.did);
1071
1072 ecore_shutdown();
1073}
1074END_TEST
1075
1076START_TEST(efl_test_promise_reject_resolve_null)
1077{
1078 Log_Ctx ctx = { 0 };
1079 Eina_Value v;
1080
1081 fail_if(!ecore_init());
1082
1083 LOG_CTX_SET(ctx, "eina_promise_resolve", "safety check failed: (p) == NULL");
1084 eina_log_print_cb_set(_eina_test_safety_print_cb, &ctx);
1085 eina_value_setup(&v, EINA_VALUE_TYPE_INT);
1086 VALUE_TYPE_CHECK(v, EINA_VALUE_TYPE_INT);
1087 eina_promise_resolve(NULL, v);
1088 fail_unless(ctx.did);
1089
1090 LOG_CTX_SET(ctx, "eina_promise_reject", "safety check failed: (p) == NULL");
1091 eina_promise_reject(NULL, DEFAULT_ERROR);
1092 fail_unless(ctx.did);
1093 ecore_shutdown();
1094}
1095END_TEST
1096
1097static Eina_Value
1098_future_null_cb(void *data, const Eina_Value v, const Eina_Future *dead)
1099{
1100 int err;
1101 int *cb_called = data;
1102
1103 ck_assert_ptr_null(dead);
1104 VALUE_TYPE_CHECK(v, EINA_VALUE_TYPE_ERROR);
1105 fail_if(!eina_value_get(&v, &err));
1106 ck_assert_int_eq(err, EINVAL);
1107 (*cb_called)++;
1108 return v;
1109}
1110
1111static Eina_Value
1112_future_easy_null_success(void *data EINA_UNUSED, const Eina_Value v)
1113{
1114 //Should not happen
1115 fail_if(EINA_TRUE);
1116 return v;
1117}
1118
1119static Eina_Value
1120_future_easy_null_err(void *data, Eina_Error err)
1121{
1122 int *cb_called = data;
1123 ck_assert_int_eq(err, EINVAL);
1124 (*cb_called)++;
1125 return eina_value_error_init(err);
1126}
1127
1128static void
1129_future_easy_null_free(void *data, const Eina_Future *dead)
1130{
1131 int *cb_called = data;
1132 ck_assert_ptr_null(dead);
1133 (*cb_called)++;
1134}
1135
1136START_TEST(efl_test_future_null)
1137{
1138 Eina_Future *f;
1139 Log_Ctx ctx = { 0 };
1140 int cb_called = 0;
1141 int easy_cb_calls = 0;
1142
1143 fail_if(!ecore_init());
1144
1145 LOG_CTX_SET(ctx, "eina_future_then_from_desc", "safety check failed: (prev) == NULL");
1146 eina_log_print_cb_set(_eina_test_safety_print_cb, &ctx);
1147 f = eina_future_then(NULL, _future_null_cb, &cb_called);
1148 ck_assert_ptr_null(f);
1149
1150 ck_assert_int_eq(cb_called, 1);
1151
1152 cb_called = 0;
1153 LOG_CTX_SET(ctx, "eina_future_chain_array", "safety check failed: (prev) == NULL");
1154 f = eina_future_chain(NULL,
1155 eina_future_cb_easy(_future_easy_null_success,
1156 _future_easy_null_err,
1157 _future_easy_null_free,
1158 NULL, &easy_cb_calls),
1159 {_future_null_cb, &cb_called},
1160 {_future_null_cb, &cb_called},
1161 {_future_null_cb, &cb_called},
1162 {_future_null_cb, &cb_called},
1163 {_future_null_cb, &cb_called});
1164 ck_assert_ptr_null(f);
1165 ck_assert_int_eq(cb_called, 5);
1166 ck_assert_int_eq(easy_cb_calls, 2);
1167
1168 easy_cb_calls = 0;
1169 LOG_CTX_SET(ctx, "eina_future_chain_easy_array", "safety check failed: (prev) == NULL");
1170 f = eina_future_chain_easy(NULL,
1171 {_future_easy_null_success,
1172 _future_easy_null_err,
1173 _future_easy_null_free,
1174 NULL, &easy_cb_calls});
1175 ck_assert_ptr_null(f);
1176 ck_assert_int_eq(easy_cb_calls, 2);
1177 ecore_shutdown();
1178}
1179END_TEST
1180
1181static Eina_Value
1182_future_race_all_null_cb(void *data, const Eina_Value v, const Eina_Future *dead EINA_UNUSED)
1183{
1184 int err;
1185 int *cb_called = data;
1186
1187 VALUE_TYPE_CHECK(v, EINA_VALUE_TYPE_ERROR);
1188 fail_if(!eina_value_get(&v, &err));
1189 ck_assert_int_eq(err, ENOMEM);
1190 (*cb_called)++;
1191 return v;
1192}
1193
1194START_TEST(efl_test_future_all_null)
1195{
1196 Log_Ctx ctx = { 0 };
1197 unsigned i, len;
1198 int cb_called = 0;
1199 Eina_Future *futures[11] = { 0 }, *f;
1200
1201 fail_if(!ecore_init());
1202
1203 eina_log_print_cb_set(_eina_test_safety_print_cb, &ctx);
1204
1205 len = EINA_C_ARRAY_LENGTH(futures);
1206 len--;
1207 for (i = 0; i < len; i++)
1208 {
1209 futures[i] = eina_future_then(_int_future_get(),
1210 _future_race_all_null_cb, &cb_called);
1211 fail_if(!futures[i]);
1212 }
1213
1214 LOG_CTX_MULTIPLE_FUNC_CTX_SET(ctx,
1215 {"promise_proxy_of_future_array_create", "safety check failed: array[i] == NULL"},
1216 {"eina_promise_all_array", "safety check failed: r is false"});
1217 //The last future is NULL, which may cause the cancel.
1218 f = eina_future_all_array(futures);
1219 ck_assert_ptr_null(f);
1220 ecore_shutdown();
1221 ck_assert_int_eq(cb_called, len);
1222}
1223END_TEST
1224
1225START_TEST(efl_test_future_race_null)
1226{
1227 Log_Ctx ctx = { 0 };
1228 unsigned i, len;
1229 int cb_called = 0;
1230 Eina_Future *futures[11] = { 0 }, *f;
1231
1232 fail_if(!ecore_init());
1233
1234 eina_log_print_cb_set(_eina_test_safety_print_cb, &ctx);
1235
1236 len = EINA_C_ARRAY_LENGTH(futures);
1237 len--;
1238 for (i = 0; i < len; i++)
1239 {
1240 futures[i] = eina_future_then(_int_future_get(),
1241 _future_race_all_null_cb, &cb_called);
1242 fail_if(!futures[i]);
1243 }
1244
1245 LOG_CTX_MULTIPLE_FUNC_CTX_SET(ctx,
1246 {"promise_proxy_of_future_array_create", "safety check failed: array[i] == NULL"},
1247 {"eina_promise_race_array", "safety check failed: r is false"});
1248 //The last future is NULL, which may cause the cancel.
1249 f = eina_future_race_array(futures);
1250 ck_assert_ptr_null(f);
1251 ecore_shutdown();
1252 ck_assert_int_eq(cb_called, len);
1253}
1254END_TEST
1255
1256#endif
1257
1258
1259void ecore_test_ecore_promise2(TCase *tc)
1260{
1261 tcase_add_test(tc, efl_test_promise_future_success);
1262 tcase_add_test(tc, efl_test_promise_future_failure);
1263 tcase_add_test(tc, efl_test_promise_future_chain_no_error);
1264 tcase_add_test(tc, efl_test_promise_future_chain_error);
1265 tcase_add_test(tc, efl_test_promise_future_cancel);
1266 tcase_add_test(tc, efl_test_promise_future_implicit_cancel);
1267 tcase_add_test(tc, efl_test_promise_future_inner_promise);
1268 tcase_add_test(tc, efl_test_promise_future_inner_promise_fail);
1269 tcase_add_test(tc, efl_test_promise_future_convert);
1270 tcase_add_test(tc, efl_test_promise_future_easy);
1271 tcase_add_test(tc, efl_test_promise_future_all);
1272 tcase_add_test(tc, efl_test_promise_future_race);
1273 tcase_add_test(tc, efl_test_promise_future_ignore_error);
1274 tcase_add_test(tc, efl_test_promise_log);
1275 //FIXME: We should move this to EO tests, however they depend on Ecore...
1276 tcase_add_test(tc, efl_test_promise_eo);
1277 tcase_add_test(tc, efl_test_promise_eo_link);
1278
1279#ifdef EINA_SAFETY_CHECKS
1280 tcase_add_test(tc, efl_test_promise_null);
1281 tcase_add_test(tc, efl_test_promise_reject_resolve_null);
1282 tcase_add_test(tc, efl_test_future_null);
1283 tcase_add_test(tc, efl_test_future_all_null);
1284 tcase_add_test(tc, efl_test_future_race_null);
1285#endif
1286}