felipealmeida pushed a commit to branch master. http://git.enlightenment.org/core/efl.git/commit/?id=3b090b808bf668f393d01c87dbfe5071615a7a72
commit 3b090b808bf668f393d01c87dbfe5071615a7a72 Author: Lauro Moura <[email protected]> Date: Tue Jun 7 14:05:15 2016 -0300 eina: Fixes on promises behavior when cancelling - Free the cancel callbacks on promise delete - Cancelling an ended promise should be a nop - More tests to increase coverage --- src/lib/eina/eina_promise.c | 12 +- src/tests/eina/eina_test_promise.c | 241 ++++++++++++++++++++++++++++++++++++- 2 files changed, 251 insertions(+), 2 deletions(-) diff --git a/src/lib/eina/eina_promise.c b/src/lib/eina/eina_promise.c index 7ce0112..eac1517 100644 --- a/src/lib/eina/eina_promise.c +++ b/src/lib/eina/eina_promise.c @@ -147,6 +147,14 @@ static void _eina_promise_free_progress_notify_callback_node(void* node) free(progress_notify_cb); } +static void _eina_promise_free_cancel_callback_node(void *node) +{ + _Eina_Promise_Cancel_Cb *cancel_cb = node; + if (cancel_cb->free) + cancel_cb->free(cancel_cb->data); + free(cancel_cb); +} + static void _eina_promise_finish(_Eina_Promise_Default_Owner* promise); static void _eina_promise_ref(_Eina_Promise_Default* promise); static void _eina_promise_unref(_Eina_Promise_Default* promise); @@ -249,6 +257,8 @@ _eina_promise_del(_Eina_Promise_Default_Owner* promise) &_eina_promise_free_progress_callback_node); _eina_promise_free_callback_list(&promise->promise.progress_notify_callbacks, &_eina_promise_free_progress_notify_callback_node); + _eina_promise_free_callback_list(&promise->promise.cancel_callbacks, + &_eina_promise_free_cancel_callback_node); free(promise); } @@ -437,7 +447,7 @@ _eina_promise_cancel(_Eina_Promise_Default* promise) { _Eina_Promise_Default_Owner* owner = EINA_PROMISE_GET_OWNER(promise); - if (!owner->promise.is_cancelled) + if (!owner->promise.is_cancelled && !owner->promise.has_finished) { owner->promise.is_cancelled = EINA_TRUE; owner->promise.has_finished = EINA_TRUE; diff --git a/src/tests/eina/eina_test_promise.c b/src/tests/eina/eina_test_promise.c index 4629869..086b6d5 100644 --- a/src/tests/eina/eina_test_promise.c +++ b/src/tests/eina/eina_test_promise.c @@ -80,6 +80,42 @@ START_TEST(eina_test_promise_normal_lifetime_all) } END_TEST +static void +_eina_test_error_cb(void *data, Eina_Error error) +{ + *(int *)data = error; +} + +START_TEST(eina_test_promise_error_set) +{ + Eina_Promise_Owner* promise_owner; + Eina_Promise* promise; + int ran = 0; + int error = 0xdeadbeef; + + eina_init(); + + promise_owner = eina_promise_value_add(0); + + promise = eina_promise_owner_promise_get(promise_owner); + + eina_promise_ref(promise); + + eina_promise_then(promise, NULL, &_eina_test_error_cb, &ran); + + eina_promise_owner_error_set(promise_owner, error); + + ck_assert(ran == error); + ck_assert_int_eq(error, eina_promise_error_get(promise)); + ck_assert(!eina_promise_pending_is(promise)); + ck_assert(!eina_promise_owner_cancelled_is(promise_owner)); + + eina_promise_unref(promise); + + eina_shutdown(); +} +END_TEST + START_TEST(eina_test_promise_immediate_set_lifetime) { Eina_Promise_Owner* owner; @@ -208,7 +244,95 @@ START_TEST(eina_test_promise_cancel_promise) // Finally free the owner eina_promise_owner_value_set(owner, NULL, NULL); - ck_assert(ran); + eina_shutdown(); +} +END_TEST + +static void +_cancel_then_callback(void *data, void *value EINA_UNUSED) +{ + *(int*)data = 1; +} + +static void +_cancel_error_callback(void *data, Eina_Error error EINA_UNUSED) +{ + *(int*)data = -1; +} + +START_TEST(eina_test_promise_cancel_finished_promise) +{ + Eina_Bool cancel_ran = EINA_FALSE; + int ran = 0; + Eina_Promise_Owner* owner; + Eina_Promise* promise; + + eina_init(); + + owner = eina_promise_value_add(0); + eina_promise_owner_default_cancel_cb_add(owner, &cancel_callback, &cancel_ran, NULL); + + promise = eina_promise_owner_promise_get(owner); + + eina_promise_then(promise, &_cancel_then_callback, &_cancel_error_callback, &ran); + + eina_promise_ref(promise); + eina_promise_owner_value_set(owner, NULL, NULL); + + ck_assert(!cancel_ran); + ck_assert_int_eq(1, ran); + ck_assert(!eina_promise_owner_cancelled_is(owner)); + ck_assert(!eina_promise_pending_is(promise)); + ck_assert_int_eq(0, eina_promise_error_get(promise)); + + eina_promise_cancel(promise); + + // The conditions should not have been changed. + ck_assert(!cancel_ran); + ck_assert_int_eq(1, ran); + ck_assert(!eina_promise_owner_cancelled_is(owner)); + ck_assert(!eina_promise_pending_is(promise)); + ck_assert_int_eq(0, eina_promise_error_get(promise)); + + eina_promise_unref(promise); + + eina_shutdown(); +} +END_TEST + +START_TEST(eina_test_promise_double_cancel_promise) +{ + Eina_Bool ran = EINA_FALSE, cancel_ran = EINA_FALSE; + Eina_Promise_Owner* owner; + Eina_Promise* promise; + + eina_init(); + + owner = eina_promise_value_add(0); + eina_promise_owner_default_cancel_cb_add(owner, &cancel_callback, &cancel_ran, NULL); + + promise = eina_promise_owner_promise_get(owner); + + eina_promise_then(promise, NULL, &_cancel_promise_callback, &ran); + + eina_promise_cancel(promise); + + ck_assert(cancel_ran && ran); + ck_assert(eina_promise_owner_cancelled_is(owner)); + ck_assert(!eina_promise_pending_is(promise)); + ck_assert_int_eq(EINA_ERROR_PROMISE_CANCEL, eina_promise_error_get(promise)); + + cancel_ran = EINA_FALSE; + ran = EINA_FALSE; + + eina_promise_cancel(promise); + + ck_assert(!cancel_ran && !ran); + ck_assert(eina_promise_owner_cancelled_is(owner)); + ck_assert(!eina_promise_pending_is(promise)); + + // Finally free the owner + eina_promise_owner_value_set(owner, NULL, NULL); eina_shutdown(); } @@ -420,6 +544,36 @@ START_TEST(eina_test_pointer_promise_normal_lifetime_all) } END_TEST +START_TEST(eina_test_pointer_promise_error_set) +{ + Eina_Promise_Owner* promise_owner; + Eina_Promise* promise; + int ran = 0; + int error = 0xdeadbeef; + + eina_init(); + + promise_owner = eina_promise_add(); + + promise = eina_promise_owner_promise_get(promise_owner); + + eina_promise_ref(promise); + + eina_promise_then(promise, NULL, &_eina_test_error_cb, &ran); + + eina_promise_owner_error_set(promise_owner, error); + + ck_assert(ran == error); + ck_assert_int_eq(error, eina_promise_error_get(promise)); + ck_assert(!eina_promise_pending_is(promise)); + ck_assert(!eina_promise_owner_cancelled_is(promise_owner)); + + eina_promise_unref(promise); + + eina_shutdown(); +} +END_TEST + START_TEST(eina_test_pointer_promise_immediate_set_lifetime) { Eina_Promise_Owner* owner; @@ -526,6 +680,84 @@ START_TEST(eina_test_pointer_promise_cancel_promise) } END_TEST +START_TEST(eina_test_pointer_promise_cancel_finished_promise) +{ + Eina_Bool cancel_ran = EINA_FALSE; + int ran = 0; + Eina_Promise_Owner* owner; + Eina_Promise* promise; + + eina_init(); + + owner = eina_promise_add(); + eina_promise_owner_default_cancel_cb_add(owner, &cancel_callback, &cancel_ran, NULL); + + promise = eina_promise_owner_promise_get(owner); + + eina_promise_then(promise, &_cancel_then_callback, &_cancel_error_callback, &ran); + + eina_promise_ref(promise); + eina_promise_owner_value_set(owner, NULL, NULL); + + ck_assert(!cancel_ran); + ck_assert_int_eq(1, ran); + ck_assert(!eina_promise_owner_cancelled_is(owner)); + ck_assert(!eina_promise_pending_is(promise)); + ck_assert_int_eq(0, eina_promise_error_get(promise)); + + eina_promise_cancel(promise); + + // The conditions should not have been changed. + ck_assert(!cancel_ran); + ck_assert_int_eq(1, ran); + ck_assert(!eina_promise_owner_cancelled_is(owner)); + ck_assert(!eina_promise_pending_is(promise)); + ck_assert_int_eq(0, eina_promise_error_get(promise)); + + eina_promise_unref(promise); + + eina_shutdown(); +} +END_TEST + +START_TEST(eina_test_pointer_promise_double_cancel_promise) +{ + Eina_Bool ran = EINA_FALSE, cancel_ran = EINA_FALSE; + Eina_Promise_Owner* owner; + Eina_Promise* promise; + + eina_init(); + + owner = eina_promise_add(); + eina_promise_owner_default_cancel_cb_add(owner, &cancel_callback, &cancel_ran, NULL); + + promise = eina_promise_owner_promise_get(owner); + + eina_promise_then(promise, NULL, &_cancel_promise_callback, &ran); + + eina_promise_cancel(promise); + + ck_assert(cancel_ran && ran); + ck_assert(eina_promise_owner_cancelled_is(owner)); + ck_assert(!eina_promise_pending_is(promise)); + ck_assert_int_eq(EINA_ERROR_PROMISE_CANCEL, eina_promise_error_get(promise)); + + cancel_ran = EINA_FALSE; + ran = EINA_FALSE; + + eina_promise_cancel(promise); + + ck_assert(!cancel_ran && !ran); + ck_assert(eina_promise_owner_cancelled_is(owner)); + ck_assert(!eina_promise_pending_is(promise)); + + // Finally free the owner + eina_promise_owner_value_set(owner, NULL, NULL); + + eina_shutdown(); +} +END_TEST + START_TEST(eina_test_pointer_promise_progress) { Eina_Bool progress_ran = EINA_FALSE; @@ -668,10 +900,14 @@ eina_test_promise(TCase *tc) { tcase_add_test(tc, eina_test_promise_normal_lifetime); tcase_add_test(tc, eina_test_promise_normal_lifetime_all); + tcase_add_test(tc, eina_test_promise_error_set); + /* tcase_add_test(tc, eina_test_promise_error_set_all); */ tcase_add_test(tc, eina_test_promise_immediate_set_lifetime); tcase_add_test(tc, eina_test_promise_immediate_set_lifetime_all); tcase_add_test(tc, eina_test_promise_values_all); tcase_add_test(tc, eina_test_promise_cancel_promise); + tcase_add_test(tc, eina_test_promise_cancel_finished_promise); + tcase_add_test(tc, eina_test_promise_double_cancel_promise); tcase_add_test(tc, eina_test_promise_progress); tcase_add_test(tc, eina_test_promise_progress_notify1); tcase_add_test(tc, eina_test_promise_progress_notify2); @@ -681,10 +917,13 @@ eina_test_promise(TCase *tc) // pointer tcase_add_test(tc, eina_test_pointer_promise_normal_lifetime); tcase_add_test(tc, eina_test_pointer_promise_normal_lifetime_all); + tcase_add_test(tc, eina_test_pointer_promise_error_set); tcase_add_test(tc, eina_test_pointer_promise_immediate_set_lifetime); tcase_add_test(tc, eina_test_pointer_promise_immediate_set_lifetime_all); tcase_add_test(tc, eina_test_pointer_promise_values_all); tcase_add_test(tc, eina_test_pointer_promise_cancel_promise); + tcase_add_test(tc, eina_test_pointer_promise_cancel_finished_promise); + tcase_add_test(tc, eina_test_pointer_promise_double_cancel_promise); tcase_add_test(tc, eina_test_pointer_promise_progress); tcase_add_test(tc, eina_test_pointer_promise_progress_notify1); tcase_add_test(tc, eina_test_pointer_promise_progress_notify2); --
