efl/src/tests/eo/suite/eo_test_general.c

1362 lines
33 KiB
C
Raw Normal View History

#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <stdio.h>
#include <Eo.h>
#include "eo_suite.h"
2012-09-25 23:56:52 -07:00
#include "eo_test_class_simple.h"
#include "eo_test_class_singleton.h"
/* Loading this internal header for testing purposes. */
#include "eo_ptr_indirection.h"
START_TEST(eo_simple)
{
efl_object_init();
Eo *obj = efl_add(EO_CLASS, NULL);
fail_if(obj);
obj = efl_add(SIMPLE_CLASS, NULL);
fail_if(!obj);
efl_constructor(obj);
efl_destructor(obj);
efl_unref(obj);
efl_object_shutdown();
}
END_TEST
START_TEST(eo_singleton)
{
efl_object_init();
Eo *obj = efl_add(SINGLETON_CLASS, NULL);
fail_if(!obj);
Eo *obj2 = efl_add(SINGLETON_CLASS, NULL);
fail_if(!obj2);
ck_assert_ptr_eq(obj, obj2);
efl_unref(obj);
efl_unref(obj2);
efl_object_shutdown();
}
END_TEST
#define OVERRIDE_A_SIMPLE 100859
#define OVERRIDE_A 324000
static int
_simple_obj_override_a_get(Eo *obj, void *class_data EINA_UNUSED)
{
return OVERRIDE_A + simple_a_get(efl_super(obj, EFL_OBJECT_OVERRIDE_CLASS));
}
static void
_simple_obj_override_a_double_set(Eo *obj, void *class_data EINA_UNUSED, int a)
{
simple_a_set(efl_super(obj, EFL_OBJECT_OVERRIDE_CLASS), 2 * a);
}
START_TEST(efl_object_override_tests)
{
efl_object_init();
Eo *obj = efl_add(SIMPLE_CLASS, NULL);
fail_if(!obj);
/* First get the value before the override to make sure it works and to
* make sure we don't cache. */
ck_assert_int_eq(simple_a_get(obj), 0);
EFL_OBJECT_OVERRIDE_OPS_DEFINE(
overrides,
EFL_OBJECT_OP_FUNC_OVERRIDE(simple_a_get, _simple_obj_override_a_get));
fail_if(!efl_object_override(obj, &overrides));
ck_assert_int_eq(simple_a_get(obj), OVERRIDE_A);
/* Check super works. */
simple_a_set(obj, OVERRIDE_A_SIMPLE);
ck_assert_int_eq(simple_a_get(obj), OVERRIDE_A + OVERRIDE_A_SIMPLE);
/* Override again. */
EFL_OBJECT_OVERRIDE_OPS_DEFINE(
overrides2,
EFL_OBJECT_OP_FUNC_OVERRIDE(simple_a_set, _simple_obj_override_a_double_set));
fail_if(!efl_object_override(obj, NULL));
fail_if(!efl_object_override(obj, &overrides2));
simple_a_set(obj, OVERRIDE_A_SIMPLE);
ck_assert_int_eq(simple_a_get(obj), OVERRIDE_A_SIMPLE * 2);
/* Try overriding again - not allowed by policy */
fail_if(efl_object_override(obj, &overrides));
ck_assert_int_eq(simple_a_get(obj), OVERRIDE_A_SIMPLE * 2);
/* Try introducing a new function */
EFL_OBJECT_OVERRIDE_OPS_DEFINE(
overrides3,
EFL_OBJECT_OP_FUNC(simple2_class_beef_get, _simple_obj_override_a_double_set));
fail_if(!efl_object_override(obj, NULL));
fail_if(efl_object_override(obj, &overrides3));
/* Test override reset */
fail_if(!efl_object_override(obj, NULL));
simple_a_set(obj, 42 * OVERRIDE_A_SIMPLE);
ck_assert_int_eq(simple_a_get(obj), 42 * OVERRIDE_A_SIMPLE);
efl_unref(obj);
efl_object_shutdown();
}
END_TEST
static int _eo_signals_cb_current = 0;
static int _eo_signals_cb_flag = 0;
static void
_eo_signals_a_changed_cb(void *_data, const Efl_Event *event EINA_UNUSED)
{
int data = (intptr_t) _data;
_eo_signals_cb_current++;
ck_assert_int_eq(data, _eo_signals_cb_current);
_eo_signals_cb_flag |= 0x1;
}
static void
_eo_signals_a_changed_cb2(void *_data EINA_UNUSED, const Efl_Event *event EINA_UNUSED)
{
_eo_signals_cb_flag |= 0x2;
efl_event_callback_stop(event->object);
2013-04-12 05:46:30 -07:00
}
static void
_eo_signals_a_changed_within_cb(void *_data EINA_UNUSED, const Efl_Event *event)
{
int a = 3;
efl_event_callback_legacy_call(event->object, EV_A_CHANGED, &a);
_eo_signals_cb_flag = 0x8;
}
static void
_eo_signals_a_changed_never(void *_data EINA_UNUSED, const Efl_Event *event EINA_UNUSED)
2013-04-12 05:46:30 -07:00
{
/* This one should never be called. */
fail_if(1);
}
static void
_eo_signals_efl_del_cb(void *_data EINA_UNUSED, const Efl_Event *event EINA_UNUSED)
{
_eo_signals_cb_flag |= 0x4;
}
void
_eo_signals_cb_added_deled(void *data, const Efl_Event *event)
{
const Efl_Callback_Array_Item *callback_array = event->info;
const Efl_Callback_Array_Item *(*callback_data)(void) = data;
fail_if((callback_data() != callback_array) &&
(callback_array->func != _eo_signals_cb_added_deled));
}
EFL_CALLBACKS_ARRAY_DEFINE(_eo_signals_callbacks,
{ EV_A_CHANGED, _eo_signals_a_changed_cb },
{ EV_A_CHANGED, _eo_signals_a_changed_cb2 },
{ EV_A_CHANGED, _eo_signals_a_changed_never },
{ EFL_EVENT_DEL, _eo_signals_efl_del_cb });
START_TEST(eo_signals)
{
efl_object_init();
Eo *obj = efl_add(SIMPLE_CLASS, NULL);
Eina_Bool r;
2014-04-02 01:46:34 -07:00
efl_event_callback_add(obj, EFL_EVENT_CALLBACK_ADD, _eo_signals_cb_added_deled, &_eo_signals_callbacks);
r = efl_event_callback_add(obj, EFL_EVENT_CALLBACK_DEL, _eo_signals_cb_added_deled, &_eo_signals_callbacks);
fail_if(!r);
efl_event_callback_array_priority_add(obj, _eo_signals_callbacks(), -100, (void *) 1);
efl_event_callback_array_add(obj, _eo_signals_callbacks(), (void *) 3);
r = efl_event_callback_array_priority_add(obj, _eo_signals_callbacks(), -50, (void *) 2);
fail_if(!r);
simple_a_set(obj, 1);
ck_assert_int_eq(_eo_signals_cb_flag, 0x3);
efl_event_callback_array_del(obj, _eo_signals_callbacks(), (void *) 1);
efl_event_callback_array_del(obj, _eo_signals_callbacks(), (void *) 2);
r = efl_event_callback_array_del(obj, _eo_signals_callbacks(), (void *) 3);
fail_if(!r);
2013-04-12 05:46:30 -07:00
/* Try to delete something that doesn't exist. */
r = efl_event_callback_array_del(obj, _eo_signals_callbacks(), (void *) 4);
fail_if(r);
_eo_signals_cb_flag = 0;
simple_a_set(obj, 1);
ck_assert_int_eq(_eo_signals_cb_flag, 0x0);
r = efl_event_callback_array_add(obj, NULL, NULL);
fail_if(r);
efl_unref(obj);
obj = efl_add(SIMPLE_CLASS, NULL);
/* Legacy support signals. */
{
const Efl_Event_Description *a_desc = efl_object_legacy_only_event_description_get("a,changed");
fail_if(!a_desc);
ck_assert_str_eq(a_desc->name, "a,changed");
fail_if(a_desc == EV_A_CHANGED);
/* Check that when calling again we still get the same event. */
const Efl_Event_Description *a_desc2 = efl_object_legacy_only_event_description_get("a,changed");
fail_if(!a_desc2);
fail_if(a_desc2 != a_desc);
const Efl_Event_Description *bad_desc = efl_object_legacy_only_event_description_get("bad");
fail_if(!bad_desc);
ck_assert_str_eq(bad_desc->name, "bad");
/* Call Eo event with legacy and non-legacy callbacks. */
_eo_signals_cb_current = 0;
efl_event_callback_priority_add(obj, EV_A_CHANGED2, -1000, _eo_signals_a_changed_never, (void *) 1);
efl_event_callback_priority_add(obj, EV_A_CHANGED2, 0, _eo_signals_a_changed_within_cb, NULL);
efl_event_callback_priority_add(obj, EV_A_CHANGED, -100, _eo_signals_a_changed_cb, (void *) 1);
efl_event_callback_add(obj, a_desc, _eo_signals_a_changed_cb2, NULL);
simple_a_set(obj, 1);
ck_assert_int_eq(_eo_signals_cb_flag, 0x3);
/* We don't need this one anymore. */
r = efl_event_callback_del(obj, EV_A_CHANGED2, _eo_signals_a_changed_never, (void *) 1);
fail_if(!r);
r = efl_event_callback_del(obj, a_desc, _eo_signals_a_changed_cb2, NULL);
fail_if(!r);
efl_event_callback_add(obj, EV_A_CHANGED, _eo_signals_a_changed_cb2, NULL);
/* Call legacy event with legacy and non-legacy callbacks. */
int a = 3;
_eo_signals_cb_current = 0;
_eo_signals_cb_flag = 0;
efl_event_callback_legacy_call(obj, a_desc, &a);
ck_assert_int_eq(_eo_signals_cb_flag, 0x3);
/* Stop event within event. */
_eo_signals_cb_current = 0;
_eo_signals_cb_flag = 0;
fail_if(!efl_event_callback_legacy_call(obj, EV_A_CHANGED2, &a));
ck_assert_int_eq(_eo_signals_cb_flag, 0x8);
fail_if(!r);
}
efl_unref(obj);
efl_object_shutdown();
}
END_TEST
START_TEST(efl_data_fetch)
{
efl_object_init();
/* Usually should be const, not const only for the test... */
static Efl_Class_Description class_desc = {
2014-04-02 01:46:34 -07:00
EO_VERSION,
"Simple2",
EFL_CLASS_TYPE_REGULAR,
EFL_CLASS_DESCRIPTION_NOOPS(),
10,
NULL,
NULL
};
const Efl_Class *klass = efl_class_new(&class_desc, EO_CLASS, NULL);
fail_if(!klass);
Eo *obj = efl_add(klass, NULL);
fail_if(!obj);
#ifdef EO_DEBUG
fail_if(efl_data_scope_get(obj, SIMPLE_CLASS));
#endif
efl_unref(obj);
class_desc.data_size = 0;
klass = efl_class_new(&class_desc, EO_CLASS, NULL);
fail_if(!klass);
obj = efl_add(klass, NULL);
fail_if(!obj);
fail_if(efl_data_scope_get(obj, klass));
fail_if(!efl_data_scope_get(obj, EFL_OBJECT_CLASS));
efl_unref(obj);
efl_object_shutdown();
}
END_TEST
START_TEST(efl_isa_tests)
{
efl_object_init();
const Efl_Class *klass, *iface, *mixin;
{
/* Usually should be const, not const only for the test... */
static Efl_Class_Description class_desc = {
2014-04-02 01:46:34 -07:00
EO_VERSION,
"Iface",
EFL_CLASS_TYPE_INTERFACE,
EFL_CLASS_DESCRIPTION_NOOPS(),
0,
NULL,
NULL
};
iface = efl_class_new(&class_desc, NULL, NULL);
fail_if(!iface);
}
{
/* Usually should be const, not const only for the test... */
static Efl_Class_Description class_desc = {
2014-04-02 01:46:34 -07:00
EO_VERSION,
"Mixin",
EFL_CLASS_TYPE_MIXIN,
EFL_CLASS_DESCRIPTION_NOOPS(),
0,
NULL,
NULL
};
mixin = efl_class_new(&class_desc, NULL, NULL);
fail_if(!mixin);
}
{
/* Usually should be const, not const only for the test... */
static Efl_Class_Description class_desc = {
2014-04-02 01:46:34 -07:00
EO_VERSION,
"Simple2",
EFL_CLASS_TYPE_REGULAR,
EFL_CLASS_DESCRIPTION_NOOPS(),
10,
NULL,
NULL
};
klass = efl_class_new(&class_desc, EO_CLASS, iface, mixin, NULL);
fail_if(!klass);
}
Eo *obj = efl_add(klass, NULL);
fail_if(!obj);
fail_if(efl_isa(obj, SIMPLE_CLASS));
fail_if(!efl_isa(obj, iface));
fail_if(!efl_isa(obj, mixin));
fail_if(!efl_isa(obj, klass));
fail_if(!efl_isa(obj, EO_CLASS));
efl_unref(obj);
obj = efl_add(SIMPLE_CLASS, NULL);
fail_if(!obj);
fail_if(efl_isa(obj, klass));
fail_if(efl_isa(obj, iface));
fail_if(efl_isa(obj, mixin));
fail_if(!efl_isa(obj, SIMPLE_CLASS));
fail_if(!efl_isa(obj, EO_CLASS));
efl_unref(obj);
efl_object_shutdown();
}
END_TEST
START_TEST(efl_composite_tests)
{
efl_object_init();
Eo *obj = efl_add(SIMPLE_CLASS, NULL);
fail_if(!obj);
Eo *obj2 = efl_add(SIMPLE_CLASS, NULL);
fail_if(!obj2);
Eo *obj3 = efl_add(SIMPLE_CLASS, NULL);
fail_if(!obj3);
efl_composite_attach(obj, obj2);
fail_if(!efl_composite_part_is(obj2));
/* Check swapping attachments works. */
efl_composite_attach(obj3, obj2);
fail_if(!efl_composite_part_is(obj2));
/* Check that a deletion of a child detaches from the parent. */
efl_del(obj2);
fail_if(!efl_composite_attach(obj3, obj));
/* Check that a deletion of the parent detaches the child. */
efl_del(obj3);
fail_if(efl_composite_part_is(obj));
efl_unref(obj);
efl_object_shutdown();
}
END_TEST
static Eina_Bool _man_should_con = EINA_TRUE;
static Eina_Bool _man_should_des = EINA_TRUE;
static const Efl_Class *cur_klass = NULL;
static Eo *
_man_con(Eo *obj, void *data EINA_UNUSED, va_list *list EINA_UNUSED)
{
if (_man_should_con)
efl_manual_free_set(obj, EINA_TRUE);
return efl_constructor(efl_super(obj, cur_klass));
}
static void
_man_des(Eo *obj, void *data EINA_UNUSED, va_list *list EINA_UNUSED)
{
efl_destructor(efl_super(obj, cur_klass));
if (_man_should_des)
efl_manual_free_set(obj, EINA_FALSE);
}
static Efl_Op_Description op_descs[] = {
EFL_OBJECT_OP_FUNC_OVERRIDE(efl_constructor, _man_con),
EFL_OBJECT_OP_FUNC_OVERRIDE(efl_destructor, _man_des),
};
START_TEST(eo_man_free)
{
efl_object_init();
/* Usually should be const, not const only for the test... */
static Efl_Class_Description class_desc = {
2014-04-02 01:46:34 -07:00
EO_VERSION,
"Simple2",
EFL_CLASS_TYPE_REGULAR,
EFL_CLASS_DESCRIPTION_OPS(op_descs),
10,
NULL,
NULL
};
const Efl_Class *klass = efl_class_new(&class_desc, EO_CLASS, NULL);
fail_if(!klass);
cur_klass = klass;
Eo *obj = efl_add(klass, NULL);
fail_if(!obj);
efl_unref(obj);
obj = efl_add(klass, NULL);
fail_if(!obj);
fail_if(efl_manual_free(obj));
efl_unref(obj);
_man_should_des = EINA_FALSE;
klass = efl_class_new(&class_desc, EO_CLASS, NULL);
cur_klass = klass;
fail_if(!klass);
obj = efl_add(klass, NULL);
fail_if(!obj);
fail_if(efl_manual_free(obj));
fail_if(efl_destructed_is(obj));
efl_unref(obj);
fail_if(!efl_destructed_is(obj));
fail_if(!efl_manual_free(obj));
obj = efl_add(klass, NULL);
fail_if(!obj);
efl_unref(obj);
fail_if(!efl_destructed_is(obj));
fail_if(!efl_manual_free(obj));
_man_should_con = EINA_FALSE;
klass = efl_class_new(&class_desc, EO_CLASS, NULL);
cur_klass = klass;
fail_if(!klass);
obj = efl_add(klass, NULL);
fail_if(!obj);
fail_if(efl_manual_free(obj));
efl_unref(obj);
obj = efl_add(klass, NULL);
fail_if(!obj);
efl_manual_free_set(obj, EINA_TRUE);
efl_unref(obj);
efl_ref(obj);
efl_unref(obj);
efl_unref(obj);
fail_if(!efl_manual_free(obj));
obj = efl_add(klass, NULL);
fail_if(!obj);
efl_manual_free_set(obj, EINA_TRUE);
efl_unref(obj);
efl_ref(obj);
efl_unref(obj);
efl_unref(obj);
efl_unref(obj);
efl_unref(obj);
fail_if(!efl_manual_free(obj));
efl_object_shutdown();
}
END_TEST
START_TEST(efl_refs)
{
efl_object_init();
Eo *obj = efl_add(SIMPLE_CLASS, NULL);
Eo *obj2 = efl_add(SIMPLE_CLASS, NULL);
Eo *obj3 = efl_add(SIMPLE_CLASS, NULL);
efl_xref(obj, obj2);
fail_if(efl_ref_get(obj) != 2);
efl_xref(obj, obj3);
fail_if(efl_ref_get(obj) != 3);
efl_xunref(obj, obj2);
fail_if(efl_ref_get(obj) != 2);
efl_xunref(obj, obj3);
fail_if(efl_ref_get(obj) != 1);
#ifdef EO_DEBUG
efl_xunref(obj, obj3);
fail_if(efl_ref_get(obj) != 1);
efl_xref(obj, obj2);
fail_if(efl_ref_get(obj) != 2);
efl_xunref(obj, obj3);
fail_if(efl_ref_get(obj) != 2);
efl_xunref(obj, obj2);
fail_if(efl_ref_get(obj) != 1);
#endif
/* Check we don't seg if there's an extra xref. */
efl_xref(obj, obj2);
efl_unref(obj);
efl_unref(obj);
efl_unref(obj2);
efl_unref(obj3);
/* Check hierarchy */
obj = efl_add(SIMPLE_CLASS, NULL);
obj2 = efl_ref(efl_add(SIMPLE_CLASS, obj));
Eo *wref = NULL;
efl_wref_add(obj2, &wref);
fail_if(!wref);
efl_unref(obj2);
fail_if(!wref); /* Parent is still holding a reference. */
efl_unref(obj);
fail_if(wref);
/* efl_add_ref and normal efl_add */
obj = efl_add(SIMPLE_CLASS, NULL);
obj2 = efl_add(SIMPLE_CLASS, obj);
obj3 = efl_add_ref(SIMPLE_CLASS, obj);
ck_assert_int_eq(efl_ref_get(obj), 1);
ck_assert_int_eq(efl_ref_get(obj2), 1);
ck_assert_int_eq(efl_ref_get(obj3), 2);
/* Setting and removing parents. */
obj = efl_add(SIMPLE_CLASS, NULL);
obj2 = efl_ref(efl_add(SIMPLE_CLASS, obj));
obj3 = efl_ref(efl_add(SIMPLE_CLASS, NULL));
efl_parent_set(obj2, obj3);
efl_parent_set(obj3, obj);
ck_assert_int_eq(efl_ref_get(obj2), 2);
ck_assert_int_eq(efl_ref_get(obj3), 2);
efl_parent_set(obj2, NULL);
efl_parent_set(obj3, NULL);
ck_assert_int_eq(efl_ref_get(obj2), 1);
ck_assert_int_eq(efl_ref_get(obj3), 1);
efl_parent_set(obj2, obj);
efl_parent_set(obj3, obj);
ck_assert_int_eq(efl_ref_get(obj2), 1);
ck_assert_int_eq(efl_ref_get(obj3), 1);
efl_del(obj);
efl_del(obj2);
efl_del(obj3);
/* Just check it doesn't seg atm. */
obj = efl_add(SIMPLE_CLASS, NULL);
efl_ref(obj);
efl_unref(obj);
efl_unref(obj);
obj = efl_add(SIMPLE_CLASS, NULL);
obj2 = efl_add(SIMPLE_CLASS, obj);
efl_unref(obj2);
efl_ref(obj2);
efl_del(obj2);
efl_unref(obj);
efl_object_shutdown();
}
END_TEST
START_TEST(efl_weak_reference)
{
efl_object_init();
Eo *obj = efl_add(SIMPLE_CLASS, NULL);
Eo *obj2 = efl_add(SIMPLE_CLASS, NULL);
Eo *wref = NULL, *wref2 = NULL, *wref3 = NULL;
efl_wref_add(obj, &wref);
fail_if(!wref);
efl_unref(obj);
fail_if(wref);
obj = efl_add(SIMPLE_CLASS, NULL);
efl_wref_add(obj, &wref);
efl_ref(obj);
fail_if(!wref);
efl_unref(obj);
fail_if(!wref);
efl_unref(obj);
fail_if(wref);
obj = efl_add(SIMPLE_CLASS, NULL);
efl_wref_add(obj, &wref);
efl_wref_del(obj, &wref);
fail_if(wref);
efl_wref_add(obj, &wref);
efl_wref_del(obj2, &wref);
fail_if(!wref);
efl_wref_del_safe(&wref);
fail_if(wref);
wref = obj;
efl_wref_del(obj, &wref);
fail_if(wref);
wref = wref2 = wref3 = NULL;
efl_wref_add(obj, &wref);
efl_wref_add(obj, &wref2);
efl_wref_add(obj, &wref3);
fail_if(!wref);
fail_if(!wref2);
fail_if(!wref3);
efl_wref_del(obj, &wref);
efl_wref_del(obj, &wref2);
efl_wref_del(obj, &wref3);
fail_if(wref);
fail_if(wref2);
fail_if(wref3);
efl_wref_add(obj, &wref2);
efl_wref_add(obj, &wref3);
wref = obj;
efl_wref_del(obj, &wref);
fail_if(wref);
efl_wref_del(obj, &wref2);
efl_wref_del(obj, &wref3);
efl_unref(obj);
efl_unref(obj2);
efl_object_shutdown();
}
END_TEST
START_TEST(eo_generic_data)
{
efl_object_init();
Eo *obj = efl_add(SIMPLE_CLASS, NULL);
Eo *obj2 = efl_add(SIMPLE_CLASS, NULL);
Eo *obj3 = efl_add(SIMPLE_CLASS, NULL);
Eo *objtmp;
void *data = NULL;
Eina_Value *value;
Eina_Value *value2;
efl_key_data_set(obj, "test1", (void *) 1);
data = efl_key_data_get(obj, "test1");
fail_if(1 != (intptr_t) data);
efl_key_data_set(obj, "test1", NULL);
data = efl_key_data_get(obj, "test1");
fail_if(data);
efl_key_data_set(obj, "test1", (void *) 1);
efl_key_data_set(obj, "test2", (void *) 2);
data = efl_key_data_get(obj, "test1");
fail_if(1 != (intptr_t) data);
data = efl_key_data_get(obj, "test2");
fail_if(2 != (intptr_t) data);
data = efl_key_data_get(obj, "test2");
fail_if(2 != (intptr_t) data);
efl_key_data_set(obj, "test2", NULL);
data = efl_key_data_get(obj, "test2");
fail_if(data);
data = efl_key_data_get(obj, "test1");
fail_if(1 != (intptr_t) data);
efl_key_data_set(obj, "test1", NULL);
data = efl_key_data_get(obj, "test1");
fail_if(data);
efl_key_ref_set(obj, "test1", obj2);
objtmp = efl_key_ref_get(obj, "test1");
fail_if(obj2 != objtmp);
efl_key_ref_set(obj, "test1", NULL);
objtmp = efl_key_ref_get(obj, "test1");
fail_if(objtmp);
efl_key_ref_set(obj, "test1", obj2);
fail_if(efl_ref_get(obj2) != 2);
efl_key_ref_set(obj, "test2", obj3);
fail_if(efl_ref_get(obj3) != 2);
objtmp = efl_key_ref_get(obj, "test1");
fail_if(obj2 != objtmp);
objtmp = efl_key_ref_get(obj, "test2");
fail_if(obj3 != objtmp);
data = efl_key_ref_get(obj, "test2");
fail_if(obj3 != objtmp);
efl_key_ref_set(obj, "test2", NULL);
fail_if(efl_ref_get(obj3) != 1);
objtmp = efl_key_ref_get(obj, "test2");
fail_if(objtmp);
objtmp = efl_key_ref_get(obj, "test1");
fail_if(obj2 != objtmp);
efl_key_ref_set(obj, "test1", NULL);
fail_if(efl_ref_get(obj2) != 1);
objtmp = efl_key_ref_get(obj, "test1");
fail_if(objtmp);
efl_key_ref_set(obj, "test1", obj2);
efl_key_ref_set(obj, "test2", obj3);
efl_del(obj2);
efl_del(obj2);
efl_del(obj3);
efl_del(obj3);
objtmp = efl_key_ref_get(obj, "test1");
fail_if(objtmp);
objtmp = efl_key_ref_get(obj, "test2");
fail_if(objtmp);
obj2 = efl_add(SIMPLE_CLASS, NULL);
obj3 = efl_add(SIMPLE_CLASS, NULL);
efl_key_wref_set(obj, "test1", obj2);
objtmp = efl_key_wref_get(obj, "test1");
fail_if(obj2 != objtmp);
efl_key_wref_set(obj, "test1", NULL);
objtmp = efl_key_wref_get(obj, "test1");
fail_if(objtmp);
efl_key_wref_set(obj, "test1", obj2);
fail_if(efl_ref_get(obj2) != 1);
efl_key_wref_set(obj, "test2", obj3);
fail_if(efl_ref_get(obj3) != 1);
objtmp = efl_key_wref_get(obj, "test1");
fail_if(obj2 != objtmp);
objtmp = efl_key_wref_get(obj, "test2");
fail_if(obj3 != objtmp);
data = efl_key_wref_get(obj, "test2");
fail_if(obj3 != objtmp);
efl_key_wref_set(obj, "test2", NULL);
fail_if(efl_ref_get(obj3) != 1);
objtmp = efl_key_wref_get(obj, "test2");
fail_if(objtmp);
objtmp = efl_key_wref_get(obj, "test1");
fail_if(obj2 != objtmp);
efl_key_wref_set(obj, "test1", NULL);
fail_if(efl_ref_get(obj2) != 1);
objtmp = efl_key_wref_get(obj, "test1");
fail_if(objtmp);
efl_key_wref_set(obj, "test1", obj2);
efl_key_wref_set(obj, "test2", obj3);
efl_del(obj2);
efl_del(obj3);
objtmp = efl_key_wref_get(obj, "test1");
fail_if(objtmp);
objtmp = efl_key_wref_get(obj, "test2");
fail_if(objtmp);
value = eina_value_new(EINA_VALUE_TYPE_INT);
eina_value_set(value, 1234);
value2 = efl_key_value_get(obj, "value1");
fail_if(value2 != NULL);
efl_key_value_set(obj, "value1", value);
value2 = efl_key_value_get(obj, "value1");
fail_if(value != value2);
efl_key_value_set(obj, "value1", NULL);
value2 = efl_key_value_get(obj, "value1");
fail_if(value2 != NULL);
efl_key_value_set(obj, "value1", NULL);
efl_unref(obj);
efl_unref(obj2);
efl_unref(obj3);
efl_object_shutdown();
}
END_TEST
START_TEST(eo_magic_checks)
{
char _buf[sizeof(long)]; /* Just enough to hold eina magic + a bit more. */
char *buf = _buf;
efl_object_init();
memset(_buf, 1, sizeof(_buf));
Eo *obj = efl_add(SIMPLE_CLASS, (Eo *) buf);
fail_if(obj);
while (1)
{
int i = 20, a = 0;
2013-09-24 23:29:19 -07:00
Eo *parent = NULL;
Eo *wref = NULL;
Eo *obj2 = NULL;
2013-09-24 23:29:19 -07:00
obj = efl_add((Efl_Class *) buf, NULL);
fail_if(obj);
obj = efl_add(SIMPLE_CLASS, NULL);
fail_if(!obj);
simple_a_set((Eo *) buf, ++i);
a = simple_a_get((Eo *) buf);
ck_assert_int_ne(i, a);
simple_a_set(efl_super((Eo *) buf, SIMPLE_CLASS), ++i);
a = simple_a_get(efl_super((Eo *) buf, SIMPLE_CLASS));
ck_assert_int_ne(i, a);
simple_a_set(efl_super(obj, (const Efl_Class *) buf), ++i);
a = simple_a_get(efl_super(obj, (const Efl_Class *) buf));
ck_assert_int_ne(i, a);
fail_if(efl_class_get((Eo *) buf));
fail_if(efl_class_name_get((Efl_Class*) buf));
fail_if(efl_class_get(obj) != SIMPLE_CLASS);
fail_if(efl_class_get(SIMPLE_CLASS) != EFL_CLASS_CLASS);
simple_a_set((Efl_Class *) buf, 1);
simple_a_set(efl_super((Efl_Class *) buf, SIMPLE_CLASS), ++i);
simple_a_set(efl_super(SIMPLE_CLASS, (Efl_Class *) buf), ++i);
fail_if(efl_class_new(NULL, (Efl_Class *) buf), NULL);
efl_xref(obj, (Eo *) buf);
efl_xunref(obj, (Eo *) buf);
efl_xref((Eo *) buf, obj);
efl_xunref((Eo *) buf, obj);
efl_ref((Eo *) buf);
efl_unref((Eo *) buf);
efl_del((Eo *) buf);
efl_isa((Eo *) buf, SIMPLE_CLASS);
efl_isa(obj, (Efl_Class *) buf);
fail_if(0 != efl_ref_get((Eo *) buf));
efl_wref_add((Eo *) buf, &wref);
parent = efl_parent_get((Eo *) buf);
fail_if(wref);
2013-09-24 23:29:19 -07:00
fail_if(parent);
fail_if(efl_data_scope_get((Eo *) buf, SIMPLE_CLASS));
efl_composite_attach(obj, (Eo *) buf);
efl_composite_detach(obj, (Eo *) buf);
efl_composite_part_is((Eo *) buf);
efl_event_callback_forwarder_add(obj, NULL, (Eo *) buf);
efl_event_callback_forwarder_del(obj, NULL, (Eo *) buf);
efl_manual_free_set((Eo *) buf, EINA_TRUE);
efl_manual_free((Eo *) buf);
efl_destructed_is((Eo *) buf);
obj2 = NULL;
efl_parent_set(obj, (Eo *) buf);
obj2 = efl_parent_get(obj);
fail_if(obj2 && (obj2 == (Eo *) buf));
efl_unref(obj);
if (!buf)
break;
else
buf = NULL;
}
efl_object_shutdown();
}
END_TEST
/* MULTI */
static Eina_Bool
_a_print(Eo *obj EINA_UNUSED, void *class_data EINA_UNUSED)
{
printf("Hey\n");
return EINA_TRUE;
}
static Eina_Bool
_class_hi_print(Efl_Class *klass EINA_UNUSED, void *class_data EINA_UNUSED)
{
printf("Hi\n");
return EINA_TRUE;
}
EFL_FUNC_BODY(multi_a_print, Eina_Bool, EINA_FALSE);
EFL_FUNC_BODY_CONST(multi_class_hi_print, Eina_Bool, EINA_FALSE);
static Efl_Op_Description _multi_do_op_descs[] = {
EFL_OBJECT_OP_FUNC(multi_a_print, _a_print),
EFL_OBJECT_OP_FUNC(multi_class_hi_print, _class_hi_print),
};
START_TEST(eo_multiple_do)
{
efl_object_init();
/* Usually should be const, not const only for the test... */
static Efl_Class_Description class_desc = {
2014-04-02 01:46:34 -07:00
EO_VERSION,
"Inherit",
EFL_CLASS_TYPE_REGULAR,
EFL_CLASS_DESCRIPTION_OPS(_multi_do_op_descs),
0,
NULL,
NULL
};
const Efl_Class *klass = efl_class_new(&class_desc, SIMPLE_CLASS, NULL);
fail_if(!klass);
Eo *obj = efl_add(klass, NULL);
fail_if(!obj);
Eina_Bool ca, cb, cc;
ca = cb = cc = EINA_FALSE;
ca = simple_a_print(obj);
cb = multi_a_print(obj);
cc = multi_a_print(obj);
fail_if(!(ca && cb && cc));
ca = cb = cc = EINA_FALSE;
ca = simple_class_hi_print(klass);
cb = multi_class_hi_print(klass);
cc = multi_class_hi_print(klass);
fail_if(!(ca && cb && cc));
efl_unref(obj);
efl_object_shutdown();
}
END_TEST
START_TEST(efl_add_do_and_custom)
{
Simple_Public_Data *pd = NULL;
Eo *obj = NULL;
efl_object_init();
obj = efl_add(SIMPLE_CLASS, NULL, efl_constructor(efl_self));
fail_if(!obj);
efl_unref(obj);
obj = efl_add(SIMPLE_CLASS, NULL, simple_a_set(efl_self, 7));
fail_if(!obj);
pd = efl_data_scope_get(obj, SIMPLE_CLASS);
fail_if(pd->a != 7);
efl_unref(obj);
obj = efl_add(SIMPLE_CLASS, NULL, efl_constructor(efl_self), simple_a_set(efl_self, 7));
fail_if(!obj);
pd = efl_data_scope_get(obj, SIMPLE_CLASS);
fail_if(pd->a != 7);
efl_unref(obj);
Eina_Bool finalized;
obj = efl_add(SIMPLE_CLASS, NULL, finalized = efl_finalized_get(efl_self));
fail_if(finalized);
finalized = efl_finalized_get(obj);
fail_if(!finalized);
efl_unref(obj);
efl_object_shutdown();
}
END_TEST
START_TEST(eo_pointers_indirection)
{
#ifdef HAVE_EO_ID
efl_object_init();
static const Efl_Class_Description class_desc = {
2014-04-02 01:46:34 -07:00
EO_VERSION,
"Simple",
EFL_CLASS_TYPE_REGULAR,
EFL_CLASS_DESCRIPTION_NOOPS(),
0,
NULL,
NULL
};
const Efl_Class *klass = efl_class_new(&class_desc, EO_CLASS, NULL);
fail_if(!klass);
/* Check simple id validity */
Eo *obj = efl_add(klass, NULL);
fail_if(!obj);
fail_if(!efl_isa(obj, klass));
obj = (Eo *)((char *)(obj) + 1);
fail_if(efl_isa(obj, klass));
obj = (Eo *)((char *)(obj) - 1);
fail_if(!efl_isa(obj, klass));
efl_unref(obj);
fail_if(efl_isa(obj, klass));
/* Check id invalidity after deletion */
Eo *obj1 = efl_add(klass, NULL);
fail_if(!obj1);
efl_unref(obj1);
Eo *obj2 = efl_add(klass, NULL);
fail_if(!obj2);
fail_if(!efl_isa(obj2, klass));
fail_if(efl_isa(obj1, klass));
efl_unref(obj2);
/* Check id sanity checks for "close enough" ids. */
obj1 = efl_add(klass, NULL);
fail_if(!obj1);
obj2 = (Eo *) (((Eo_Id) obj1) & ~MASK_OBJ_TAG);
fail_if(efl_class_get(obj2));
efl_unref(obj1);
#define NB_OBJS 10000
unsigned int obj_id;
Eo **objs = calloc(NB_OBJS, sizeof(Eo *));
fail_if(!objs);
/* Creation of the objects */
for ( obj_id = 0; obj_id < NB_OBJS; obj_id++)
{
objs[obj_id] = efl_add(klass, NULL);
if(!objs[obj_id])
fail_if(!objs[obj_id]);
if(!efl_isa(objs[obj_id], klass))
fail_if(!efl_isa(objs[obj_id], klass));
}
/* Deletion of a few objects */
for ( obj_id = 0; obj_id < NB_OBJS; obj_id+=2000)
{
efl_unref(objs[obj_id]);
if(efl_isa(objs[obj_id], klass))
fail_if(efl_isa(objs[obj_id], klass));
}
/* Creation of the deleted objects */
for ( obj_id = 0; obj_id < NB_OBJS; obj_id+=2000)
{
objs[obj_id] = efl_add(klass, NULL);
if(!objs[obj_id])
fail_if(!objs[obj_id]);
if(!efl_isa(objs[obj_id], klass))
fail_if(!efl_isa(objs[obj_id], klass));
}
/* Deletion of all the objects */
for ( obj_id = 0; obj_id < NB_OBJS; obj_id++)
efl_unref(objs[obj_id]);
/* Just be sure that we trigger an already freed error */
efl_unref(objs[0]);
free(objs);
efl_object_shutdown();
#endif
}
END_TEST
static Eo *
_efl_add_failures_finalize(Eo *obj EINA_UNUSED, void *class_data EINA_UNUSED)
{
return NULL;
}
static Efl_Op_Description _efl_add_failures_op_descs[] = {
EFL_OBJECT_OP_FUNC_OVERRIDE(efl_finalize, _efl_add_failures_finalize),
};
START_TEST(efl_add_failures)
{
efl_object_init();
static const Efl_Class_Description class_desc = {
EO_VERSION,
"Simple2",
EFL_CLASS_TYPE_REGULAR,
EFL_CLASS_DESCRIPTION_OPS(_efl_add_failures_op_descs),
0,
NULL,
NULL
};
const Efl_Class *klass = efl_class_new(&class_desc, EO_CLASS, NULL);
Eo *obj = efl_add(klass, NULL);
fail_if(obj);
efl_object_shutdown();
}
END_TEST
#ifdef HAVE_EO_ID
eo del interceptor: add the ability to intercept deletions of eo objects Imagine this. You have an object. You pass this object handle as a message to another thread. Let's say it's not a UI object, so something you might expect to be able to be accessed from multiple threads. In order to keep the object alive you eo_ref() it when placing the message on a queue and eo_unref() it once the message is "done" in the other thread. If the original sender unref()ed the object before the message is done, then the object will be destroyed in the reciever thread. This is bad for objects "expecting" not to be destroyed outside their owning thread. This allows thius situation to be fixed. A constructor in a class of an object can set up a delete interceptor. For example if we have a "loop ownership" class you multi-ple-inherit from/use as a mixin. This class will set up the interceptor to ensure that on destruction if pthread_self() != owning loop thread id, then add object to "delete me" queue on the owning loop and wake it up. the owning loop thread will wake up and then process this queue and delete the queued objects nicely and safely within the "owning context". This can also be used in this same manner to defer deletion within a loop "until later" in the same delete_me queue. You can even use this as a caching mechanism for objects to prevernt their actual destruction and instead place them in a cached area to be picked from at a later date. The uses are many for this and this is a basic building block for future EFL features like generic messages where a message payload could be an eo object and thus the above loop onwership issue can happen and needs fixing. This adds APIs, implementation, documentation (doxy reference) and tests. @feature
2016-03-07 23:57:22 -08:00
static Eina_Bool intercepted = EINA_FALSE;
static void
_del_intercept(Eo *obj)
{
intercepted = EINA_TRUE;
efl_del_intercept_set(obj, NULL);
efl_unref(obj);
eo del interceptor: add the ability to intercept deletions of eo objects Imagine this. You have an object. You pass this object handle as a message to another thread. Let's say it's not a UI object, so something you might expect to be able to be accessed from multiple threads. In order to keep the object alive you eo_ref() it when placing the message on a queue and eo_unref() it once the message is "done" in the other thread. If the original sender unref()ed the object before the message is done, then the object will be destroyed in the reciever thread. This is bad for objects "expecting" not to be destroyed outside their owning thread. This allows thius situation to be fixed. A constructor in a class of an object can set up a delete interceptor. For example if we have a "loop ownership" class you multi-ple-inherit from/use as a mixin. This class will set up the interceptor to ensure that on destruction if pthread_self() != owning loop thread id, then add object to "delete me" queue on the owning loop and wake it up. the owning loop thread will wake up and then process this queue and delete the queued objects nicely and safely within the "owning context". This can also be used in this same manner to defer deletion within a loop "until later" in the same delete_me queue. You can even use this as a caching mechanism for objects to prevernt their actual destruction and instead place them in a cached area to be picked from at a later date. The uses are many for this and this is a basic building block for future EFL features like generic messages where a message payload could be an eo object and thus the above loop onwership issue can happen and needs fixing. This adds APIs, implementation, documentation (doxy reference) and tests. @feature
2016-03-07 23:57:22 -08:00
}
#endif
eo del interceptor: add the ability to intercept deletions of eo objects Imagine this. You have an object. You pass this object handle as a message to another thread. Let's say it's not a UI object, so something you might expect to be able to be accessed from multiple threads. In order to keep the object alive you eo_ref() it when placing the message on a queue and eo_unref() it once the message is "done" in the other thread. If the original sender unref()ed the object before the message is done, then the object will be destroyed in the reciever thread. This is bad for objects "expecting" not to be destroyed outside their owning thread. This allows thius situation to be fixed. A constructor in a class of an object can set up a delete interceptor. For example if we have a "loop ownership" class you multi-ple-inherit from/use as a mixin. This class will set up the interceptor to ensure that on destruction if pthread_self() != owning loop thread id, then add object to "delete me" queue on the owning loop and wake it up. the owning loop thread will wake up and then process this queue and delete the queued objects nicely and safely within the "owning context". This can also be used in this same manner to defer deletion within a loop "until later" in the same delete_me queue. You can even use this as a caching mechanism for objects to prevernt their actual destruction and instead place them in a cached area to be picked from at a later date. The uses are many for this and this is a basic building block for future EFL features like generic messages where a message payload could be an eo object and thus the above loop onwership issue can happen and needs fixing. This adds APIs, implementation, documentation (doxy reference) and tests. @feature
2016-03-07 23:57:22 -08:00
START_TEST(efl_del_intercept)
eo del interceptor: add the ability to intercept deletions of eo objects Imagine this. You have an object. You pass this object handle as a message to another thread. Let's say it's not a UI object, so something you might expect to be able to be accessed from multiple threads. In order to keep the object alive you eo_ref() it when placing the message on a queue and eo_unref() it once the message is "done" in the other thread. If the original sender unref()ed the object before the message is done, then the object will be destroyed in the reciever thread. This is bad for objects "expecting" not to be destroyed outside their owning thread. This allows thius situation to be fixed. A constructor in a class of an object can set up a delete interceptor. For example if we have a "loop ownership" class you multi-ple-inherit from/use as a mixin. This class will set up the interceptor to ensure that on destruction if pthread_self() != owning loop thread id, then add object to "delete me" queue on the owning loop and wake it up. the owning loop thread will wake up and then process this queue and delete the queued objects nicely and safely within the "owning context". This can also be used in this same manner to defer deletion within a loop "until later" in the same delete_me queue. You can even use this as a caching mechanism for objects to prevernt their actual destruction and instead place them in a cached area to be picked from at a later date. The uses are many for this and this is a basic building block for future EFL features like generic messages where a message payload could be an eo object and thus the above loop onwership issue can happen and needs fixing. This adds APIs, implementation, documentation (doxy reference) and tests. @feature
2016-03-07 23:57:22 -08:00
{
#ifdef HAVE_EO_ID
efl_object_init();
eo del interceptor: add the ability to intercept deletions of eo objects Imagine this. You have an object. You pass this object handle as a message to another thread. Let's say it's not a UI object, so something you might expect to be able to be accessed from multiple threads. In order to keep the object alive you eo_ref() it when placing the message on a queue and eo_unref() it once the message is "done" in the other thread. If the original sender unref()ed the object before the message is done, then the object will be destroyed in the reciever thread. This is bad for objects "expecting" not to be destroyed outside their owning thread. This allows thius situation to be fixed. A constructor in a class of an object can set up a delete interceptor. For example if we have a "loop ownership" class you multi-ple-inherit from/use as a mixin. This class will set up the interceptor to ensure that on destruction if pthread_self() != owning loop thread id, then add object to "delete me" queue on the owning loop and wake it up. the owning loop thread will wake up and then process this queue and delete the queued objects nicely and safely within the "owning context". This can also be used in this same manner to defer deletion within a loop "until later" in the same delete_me queue. You can even use this as a caching mechanism for objects to prevernt their actual destruction and instead place them in a cached area to be picked from at a later date. The uses are many for this and this is a basic building block for future EFL features like generic messages where a message payload could be an eo object and thus the above loop onwership issue can happen and needs fixing. This adds APIs, implementation, documentation (doxy reference) and tests. @feature
2016-03-07 23:57:22 -08:00
static const Efl_Class_Description class_desc = {
eo del interceptor: add the ability to intercept deletions of eo objects Imagine this. You have an object. You pass this object handle as a message to another thread. Let's say it's not a UI object, so something you might expect to be able to be accessed from multiple threads. In order to keep the object alive you eo_ref() it when placing the message on a queue and eo_unref() it once the message is "done" in the other thread. If the original sender unref()ed the object before the message is done, then the object will be destroyed in the reciever thread. This is bad for objects "expecting" not to be destroyed outside their owning thread. This allows thius situation to be fixed. A constructor in a class of an object can set up a delete interceptor. For example if we have a "loop ownership" class you multi-ple-inherit from/use as a mixin. This class will set up the interceptor to ensure that on destruction if pthread_self() != owning loop thread id, then add object to "delete me" queue on the owning loop and wake it up. the owning loop thread will wake up and then process this queue and delete the queued objects nicely and safely within the "owning context". This can also be used in this same manner to defer deletion within a loop "until later" in the same delete_me queue. You can even use this as a caching mechanism for objects to prevernt their actual destruction and instead place them in a cached area to be picked from at a later date. The uses are many for this and this is a basic building block for future EFL features like generic messages where a message payload could be an eo object and thus the above loop onwership issue can happen and needs fixing. This adds APIs, implementation, documentation (doxy reference) and tests. @feature
2016-03-07 23:57:22 -08:00
EO_VERSION,
"Simple",
EFL_CLASS_TYPE_REGULAR,
EFL_CLASS_DESCRIPTION_NOOPS(),
eo del interceptor: add the ability to intercept deletions of eo objects Imagine this. You have an object. You pass this object handle as a message to another thread. Let's say it's not a UI object, so something you might expect to be able to be accessed from multiple threads. In order to keep the object alive you eo_ref() it when placing the message on a queue and eo_unref() it once the message is "done" in the other thread. If the original sender unref()ed the object before the message is done, then the object will be destroyed in the reciever thread. This is bad for objects "expecting" not to be destroyed outside their owning thread. This allows thius situation to be fixed. A constructor in a class of an object can set up a delete interceptor. For example if we have a "loop ownership" class you multi-ple-inherit from/use as a mixin. This class will set up the interceptor to ensure that on destruction if pthread_self() != owning loop thread id, then add object to "delete me" queue on the owning loop and wake it up. the owning loop thread will wake up and then process this queue and delete the queued objects nicely and safely within the "owning context". This can also be used in this same manner to defer deletion within a loop "until later" in the same delete_me queue. You can even use this as a caching mechanism for objects to prevernt their actual destruction and instead place them in a cached area to be picked from at a later date. The uses are many for this and this is a basic building block for future EFL features like generic messages where a message payload could be an eo object and thus the above loop onwership issue can happen and needs fixing. This adds APIs, implementation, documentation (doxy reference) and tests. @feature
2016-03-07 23:57:22 -08:00
0,
NULL,
NULL
};
const Efl_Class *klass = efl_class_new(&class_desc, EO_CLASS, NULL);
eo del interceptor: add the ability to intercept deletions of eo objects Imagine this. You have an object. You pass this object handle as a message to another thread. Let's say it's not a UI object, so something you might expect to be able to be accessed from multiple threads. In order to keep the object alive you eo_ref() it when placing the message on a queue and eo_unref() it once the message is "done" in the other thread. If the original sender unref()ed the object before the message is done, then the object will be destroyed in the reciever thread. This is bad for objects "expecting" not to be destroyed outside their owning thread. This allows thius situation to be fixed. A constructor in a class of an object can set up a delete interceptor. For example if we have a "loop ownership" class you multi-ple-inherit from/use as a mixin. This class will set up the interceptor to ensure that on destruction if pthread_self() != owning loop thread id, then add object to "delete me" queue on the owning loop and wake it up. the owning loop thread will wake up and then process this queue and delete the queued objects nicely and safely within the "owning context". This can also be used in this same manner to defer deletion within a loop "until later" in the same delete_me queue. You can even use this as a caching mechanism for objects to prevernt their actual destruction and instead place them in a cached area to be picked from at a later date. The uses are many for this and this is a basic building block for future EFL features like generic messages where a message payload could be an eo object and thus the above loop onwership issue can happen and needs fixing. This adds APIs, implementation, documentation (doxy reference) and tests. @feature
2016-03-07 23:57:22 -08:00
fail_if(!klass);
/* Check unref interception */
intercepted = EINA_FALSE;
Eo *obj = efl_add(klass, NULL);
eo del interceptor: add the ability to intercept deletions of eo objects Imagine this. You have an object. You pass this object handle as a message to another thread. Let's say it's not a UI object, so something you might expect to be able to be accessed from multiple threads. In order to keep the object alive you eo_ref() it when placing the message on a queue and eo_unref() it once the message is "done" in the other thread. If the original sender unref()ed the object before the message is done, then the object will be destroyed in the reciever thread. This is bad for objects "expecting" not to be destroyed outside their owning thread. This allows thius situation to be fixed. A constructor in a class of an object can set up a delete interceptor. For example if we have a "loop ownership" class you multi-ple-inherit from/use as a mixin. This class will set up the interceptor to ensure that on destruction if pthread_self() != owning loop thread id, then add object to "delete me" queue on the owning loop and wake it up. the owning loop thread will wake up and then process this queue and delete the queued objects nicely and safely within the "owning context". This can also be used in this same manner to defer deletion within a loop "until later" in the same delete_me queue. You can even use this as a caching mechanism for objects to prevernt their actual destruction and instead place them in a cached area to be picked from at a later date. The uses are many for this and this is a basic building block for future EFL features like generic messages where a message payload could be an eo object and thus the above loop onwership issue can happen and needs fixing. This adds APIs, implementation, documentation (doxy reference) and tests. @feature
2016-03-07 23:57:22 -08:00
fail_if(!obj);
fail_if(!efl_isa(obj, klass));
efl_del_intercept_set(obj, _del_intercept);
efl_unref(obj);
eo del interceptor: add the ability to intercept deletions of eo objects Imagine this. You have an object. You pass this object handle as a message to another thread. Let's say it's not a UI object, so something you might expect to be able to be accessed from multiple threads. In order to keep the object alive you eo_ref() it when placing the message on a queue and eo_unref() it once the message is "done" in the other thread. If the original sender unref()ed the object before the message is done, then the object will be destroyed in the reciever thread. This is bad for objects "expecting" not to be destroyed outside their owning thread. This allows thius situation to be fixed. A constructor in a class of an object can set up a delete interceptor. For example if we have a "loop ownership" class you multi-ple-inherit from/use as a mixin. This class will set up the interceptor to ensure that on destruction if pthread_self() != owning loop thread id, then add object to "delete me" queue on the owning loop and wake it up. the owning loop thread will wake up and then process this queue and delete the queued objects nicely and safely within the "owning context". This can also be used in this same manner to defer deletion within a loop "until later" in the same delete_me queue. You can even use this as a caching mechanism for objects to prevernt their actual destruction and instead place them in a cached area to be picked from at a later date. The uses are many for this and this is a basic building block for future EFL features like generic messages where a message payload could be an eo object and thus the above loop onwership issue can happen and needs fixing. This adds APIs, implementation, documentation (doxy reference) and tests. @feature
2016-03-07 23:57:22 -08:00
fail_if(!intercepted);
fail_if(efl_isa(obj, klass));
eo del interceptor: add the ability to intercept deletions of eo objects Imagine this. You have an object. You pass this object handle as a message to another thread. Let's say it's not a UI object, so something you might expect to be able to be accessed from multiple threads. In order to keep the object alive you eo_ref() it when placing the message on a queue and eo_unref() it once the message is "done" in the other thread. If the original sender unref()ed the object before the message is done, then the object will be destroyed in the reciever thread. This is bad for objects "expecting" not to be destroyed outside their owning thread. This allows thius situation to be fixed. A constructor in a class of an object can set up a delete interceptor. For example if we have a "loop ownership" class you multi-ple-inherit from/use as a mixin. This class will set up the interceptor to ensure that on destruction if pthread_self() != owning loop thread id, then add object to "delete me" queue on the owning loop and wake it up. the owning loop thread will wake up and then process this queue and delete the queued objects nicely and safely within the "owning context". This can also be used in this same manner to defer deletion within a loop "until later" in the same delete_me queue. You can even use this as a caching mechanism for objects to prevernt their actual destruction and instead place them in a cached area to be picked from at a later date. The uses are many for this and this is a basic building block for future EFL features like generic messages where a message payload could be an eo object and thus the above loop onwership issue can happen and needs fixing. This adds APIs, implementation, documentation (doxy reference) and tests. @feature
2016-03-07 23:57:22 -08:00
/* Check del interception */
intercepted = EINA_FALSE;
obj = efl_add(klass, NULL);
eo del interceptor: add the ability to intercept deletions of eo objects Imagine this. You have an object. You pass this object handle as a message to another thread. Let's say it's not a UI object, so something you might expect to be able to be accessed from multiple threads. In order to keep the object alive you eo_ref() it when placing the message on a queue and eo_unref() it once the message is "done" in the other thread. If the original sender unref()ed the object before the message is done, then the object will be destroyed in the reciever thread. This is bad for objects "expecting" not to be destroyed outside their owning thread. This allows thius situation to be fixed. A constructor in a class of an object can set up a delete interceptor. For example if we have a "loop ownership" class you multi-ple-inherit from/use as a mixin. This class will set up the interceptor to ensure that on destruction if pthread_self() != owning loop thread id, then add object to "delete me" queue on the owning loop and wake it up. the owning loop thread will wake up and then process this queue and delete the queued objects nicely and safely within the "owning context". This can also be used in this same manner to defer deletion within a loop "until later" in the same delete_me queue. You can even use this as a caching mechanism for objects to prevernt their actual destruction and instead place them in a cached area to be picked from at a later date. The uses are many for this and this is a basic building block for future EFL features like generic messages where a message payload could be an eo object and thus the above loop onwership issue can happen and needs fixing. This adds APIs, implementation, documentation (doxy reference) and tests. @feature
2016-03-07 23:57:22 -08:00
fail_if(!obj);
fail_if(!efl_isa(obj, klass));
efl_del_intercept_set(obj, _del_intercept);
efl_del(obj);
eo del interceptor: add the ability to intercept deletions of eo objects Imagine this. You have an object. You pass this object handle as a message to another thread. Let's say it's not a UI object, so something you might expect to be able to be accessed from multiple threads. In order to keep the object alive you eo_ref() it when placing the message on a queue and eo_unref() it once the message is "done" in the other thread. If the original sender unref()ed the object before the message is done, then the object will be destroyed in the reciever thread. This is bad for objects "expecting" not to be destroyed outside their owning thread. This allows thius situation to be fixed. A constructor in a class of an object can set up a delete interceptor. For example if we have a "loop ownership" class you multi-ple-inherit from/use as a mixin. This class will set up the interceptor to ensure that on destruction if pthread_self() != owning loop thread id, then add object to "delete me" queue on the owning loop and wake it up. the owning loop thread will wake up and then process this queue and delete the queued objects nicely and safely within the "owning context". This can also be used in this same manner to defer deletion within a loop "until later" in the same delete_me queue. You can even use this as a caching mechanism for objects to prevernt their actual destruction and instead place them in a cached area to be picked from at a later date. The uses are many for this and this is a basic building block for future EFL features like generic messages where a message payload could be an eo object and thus the above loop onwership issue can happen and needs fixing. This adds APIs, implementation, documentation (doxy reference) and tests. @feature
2016-03-07 23:57:22 -08:00
fail_if(!intercepted);
fail_if(efl_isa(obj, klass));
eo del interceptor: add the ability to intercept deletions of eo objects Imagine this. You have an object. You pass this object handle as a message to another thread. Let's say it's not a UI object, so something you might expect to be able to be accessed from multiple threads. In order to keep the object alive you eo_ref() it when placing the message on a queue and eo_unref() it once the message is "done" in the other thread. If the original sender unref()ed the object before the message is done, then the object will be destroyed in the reciever thread. This is bad for objects "expecting" not to be destroyed outside their owning thread. This allows thius situation to be fixed. A constructor in a class of an object can set up a delete interceptor. For example if we have a "loop ownership" class you multi-ple-inherit from/use as a mixin. This class will set up the interceptor to ensure that on destruction if pthread_self() != owning loop thread id, then add object to "delete me" queue on the owning loop and wake it up. the owning loop thread will wake up and then process this queue and delete the queued objects nicely and safely within the "owning context". This can also be used in this same manner to defer deletion within a loop "until later" in the same delete_me queue. You can even use this as a caching mechanism for objects to prevernt their actual destruction and instead place them in a cached area to be picked from at a later date. The uses are many for this and this is a basic building block for future EFL features like generic messages where a message payload could be an eo object and thus the above loop onwership issue can happen and needs fixing. This adds APIs, implementation, documentation (doxy reference) and tests. @feature
2016-03-07 23:57:22 -08:00
efl_object_shutdown();
eo del interceptor: add the ability to intercept deletions of eo objects Imagine this. You have an object. You pass this object handle as a message to another thread. Let's say it's not a UI object, so something you might expect to be able to be accessed from multiple threads. In order to keep the object alive you eo_ref() it when placing the message on a queue and eo_unref() it once the message is "done" in the other thread. If the original sender unref()ed the object before the message is done, then the object will be destroyed in the reciever thread. This is bad for objects "expecting" not to be destroyed outside their owning thread. This allows thius situation to be fixed. A constructor in a class of an object can set up a delete interceptor. For example if we have a "loop ownership" class you multi-ple-inherit from/use as a mixin. This class will set up the interceptor to ensure that on destruction if pthread_self() != owning loop thread id, then add object to "delete me" queue on the owning loop and wake it up. the owning loop thread will wake up and then process this queue and delete the queued objects nicely and safely within the "owning context". This can also be used in this same manner to defer deletion within a loop "until later" in the same delete_me queue. You can even use this as a caching mechanism for objects to prevernt their actual destruction and instead place them in a cached area to be picked from at a later date. The uses are many for this and this is a basic building block for future EFL features like generic messages where a message payload could be an eo object and thus the above loop onwership issue can happen and needs fixing. This adds APIs, implementation, documentation (doxy reference) and tests. @feature
2016-03-07 23:57:22 -08:00
#endif
}
END_TEST
START_TEST(efl_name)
{
efl_object_init();
Eo *obj = efl_add(SIMPLE_CLASS, NULL);
Eo *obj2 = efl_add(SIMPLE_CLASS, NULL);
Eo *obj3 = efl_add(SIMPLE_CLASS, NULL);
Eo *objtmp;
const char *id;
id = efl_name_get(obj);
fail_if(NULL != id);
efl_name_set(obj, "Hello");
id = efl_name_get(obj);
fail_if(NULL == id);
fail_if(!!strcmp(id, "Hello"));
efl_name_set(obj, "Hello");
efl_name_set(obj, "");
id = efl_name_get(obj);
fail_if(NULL != id);
efl_name_set(obj, "Hello");
efl_name_set(obj, NULL);
id = efl_name_get(obj);
fail_if(NULL != id);
efl_name_set(obj2, "joe");
efl_name_set(obj3, "bob");
efl_parent_set(obj2, obj);
efl_parent_set(obj3, obj2);
objtmp = efl_name_find(obj, "bob");
fail_if(objtmp != obj3);
objtmp = efl_name_find(obj, "joe");
fail_if(objtmp != obj2);
objtmp = efl_name_find(obj, "bo*");
fail_if(objtmp != obj3);
objtmp = efl_name_find(obj, "*oe");
fail_if(objtmp != obj2);
objtmp = efl_name_find(obj, "Simple:*oe");
fail_if(objtmp != obj2);
objtmp = efl_name_find(obj, "*mple:joe");
fail_if(objtmp != obj2);
efl_del(obj);
efl_object_shutdown();
}
END_TEST
START_TEST(eo_comment)
{
efl_object_init();
Eo *obj = efl_add(SIMPLE_CLASS, NULL);
const char *comment;
comment = efl_comment_get(obj);
fail_if(NULL != comment);
efl_comment_set(obj, "Hello");
comment = efl_comment_get(obj);
fail_if(NULL == comment);
fail_if(!!strcmp(comment, "Hello"));
efl_comment_set(obj, "Hello");
efl_comment_set(obj, "");
comment = efl_comment_get(obj);
fail_if(NULL != comment);
efl_comment_set(obj, "Hello");
efl_comment_set(obj, NULL);
comment = efl_comment_get(obj);
fail_if(NULL != comment);
efl_del(obj);
efl_object_shutdown();
}
END_TEST
START_TEST(eo_rec_interface)
{
efl_object_init();
Eo *s = efl_add(SEARCHABLE_CLASS, NULL);
Eo *obj = efl_add(SIMPLE_CLASS, s);
Eo *obj2 = efl_add(SIMPLE_CLASS, obj);
Eo *objtmp;
objtmp = efl_provider_find(obj2, SEARCHABLE_CLASS);
fail_if(objtmp != s);
efl_del(obj);
efl_object_shutdown();
}
END_TEST
void eo_test_general(TCase *tc)
{
tcase_add_test(tc, eo_simple);
tcase_add_test(tc, eo_singleton);
tcase_add_test(tc, efl_object_override_tests);
tcase_add_test(tc, eo_signals);
tcase_add_test(tc, efl_data_fetch);
tcase_add_test(tc, efl_isa_tests);
tcase_add_test(tc, efl_composite_tests);
tcase_add_test(tc, eo_man_free);
tcase_add_test(tc, efl_refs);
tcase_add_test(tc, efl_weak_reference);
tcase_add_test(tc, eo_generic_data);
tcase_add_test(tc, eo_magic_checks);
tcase_add_test(tc, eo_multiple_do);
tcase_add_test(tc, efl_add_do_and_custom);
tcase_add_test(tc, eo_pointers_indirection);
tcase_add_test(tc, efl_add_failures);
tcase_add_test(tc, efl_del_intercept);
tcase_add_test(tc, efl_name);
tcase_add_test(tc, eo_comment);
tcase_add_test(tc, eo_rec_interface);
}