From 3ad3455551be0d7859ecb02290376206d5e66498 Mon Sep 17 00:00:00 2001 From: David Walter Seikel Date: Sun, 22 Apr 2012 09:20:32 +1000 Subject: And actually include new files, plus elementary libraries. --- libraries/eina/src/tests/eina_test_model.c | 1288 ++++++++++++++++++++++++++++ 1 file changed, 1288 insertions(+) create mode 100644 libraries/eina/src/tests/eina_test_model.c (limited to 'libraries/eina/src/tests/eina_test_model.c') diff --git a/libraries/eina/src/tests/eina_test_model.c b/libraries/eina/src/tests/eina_test_model.c new file mode 100644 index 0000000..54a2258 --- /dev/null +++ b/libraries/eina/src/tests/eina_test_model.c @@ -0,0 +1,1288 @@ +/* EINA - EFL data type library + * Copyright (C) 2012 ProFUSION embedded systems + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; + * if not, see . + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include +#include + +#include "eina_suite.h" +#include "Eina.h" + +static void +_eina_test_model_check_safety_null(const Eina_Log_Domain *d, Eina_Log_Level level, const char *file, const char *fnc, int line, const char *fmt, void *data, va_list args) +{ + Eina_Bool *ck = data; + + if ((level == EINA_LOG_LEVEL_ERR) && (strcmp(fmt, "%s") == 0)) + { + const char *str; + va_list cp_args; + + va_copy(cp_args, args); + str = va_arg(cp_args, const char *); + va_end(cp_args); + if (eina_str_has_prefix(str, "safety check failed: ") && + eina_str_has_suffix(str, " == NULL")) + { + *ck = EINA_TRUE; + return; + } + } + *ck = EINA_FALSE; + eina_log_print_cb_stderr(d, level, file, fnc, line, fmt, NULL, args); +} + +static void +_eina_test_model_check_safety_false(const Eina_Log_Domain *d, Eina_Log_Level level, const char *file, const char *fnc, int line, const char *fmt, void *data, va_list args) +{ + Eina_Bool *ck = data; + + if ((level == EINA_LOG_LEVEL_ERR) && (strcmp(fmt, "%s") == 0)) + { + const char *str; + va_list cp_args; + + va_copy(cp_args, args); + str = va_arg(cp_args, const char *); + va_end(cp_args); + if (eina_str_has_prefix(str, "safety check failed: ") && + eina_str_has_suffix(str, " is false")) + { + *ck = EINA_TRUE; + return; + } + } + *ck = EINA_FALSE; + eina_log_print_cb_stderr(d, level, file, fnc, line, fmt, NULL, args); +} + +static void +_eina_test_model_cb_count(void *data, Eina_Model *model, const Eina_Model_Event_Description *desc, void *event_info) +{ + unsigned *count = data; + (*count)++; +#if SHOW_LOG + if ((desc->type) && (strcmp(desc->type, "u") == 0)) + { + unsigned *pos = event_info; + printf("%2u %p %s at %u\n", *count, model, desc->name, *pos); + } + else + printf("%2u %p %s\n", *count, model, desc->name); +#else + (void)model; + (void)desc; + (void)event_info; +#endif +} + +START_TEST(eina_model_test_properties) +{ + unsigned int count_del = 0, count_pset = 0, count_pdel = 0; + Eina_Model *m; + Eina_Value inv, outv; + int i; + char *s; + Eina_List *lst; + Eina_Bool ck; + + eina_init(); + + m = eina_model_new(EINA_MODEL_TYPE_GENERIC); + fail_unless(m != NULL); + + eina_model_event_callback_add + (m, "deleted", _eina_test_model_cb_count, &count_del); + eina_model_event_callback_add + (m, "property,set", _eina_test_model_cb_count, &count_pset); + eina_model_event_callback_add + (m, "property,deleted", _eina_test_model_cb_count, &count_pdel); + + fail_unless(eina_value_setup(&inv, EINA_VALUE_TYPE_INT)); + fail_unless(eina_value_set(&inv, 1234)); + fail_unless(eina_value_get(&inv, &i)); + ck_assert_int_eq(i, 1234); + + fail_unless(eina_model_property_set(m, "abc", &inv)); + + fail_unless(eina_value_set(&inv, 5678)); + fail_unless(eina_model_property_set(m, "xyz", &inv)); + + fail_unless(eina_value_set(&inv, 171)); + fail_unless(eina_model_property_set(m, "value", &inv)); + + lst = eina_model_properties_names_list_get(m); + ck_assert_int_eq(eina_list_count(lst), 3); + + lst = eina_list_sort(lst, 0, EINA_COMPARE_CB(strcmp)); + ck_assert_str_eq("abc", eina_list_nth(lst, 0)); + ck_assert_str_eq("value", eina_list_nth(lst, 1)); + ck_assert_str_eq("xyz", eina_list_nth(lst, 2)); + + eina_model_properties_names_list_free(lst); + + fail_unless(eina_model_property_get(m, "abc", &outv)); + fail_unless(eina_value_get(&outv, &i)); + ck_assert_int_eq(i, 1234); + eina_value_flush(&outv); + + fail_unless(eina_model_property_get(m, "xyz", &outv)); + fail_unless(eina_value_get(&outv, &i)); + ck_assert_int_eq(i, 5678); + eina_value_flush(&outv); + + fail_unless(eina_model_property_get(m, "value", &outv)); + fail_unless(eina_value_get(&outv, &i)); + ck_assert_int_eq(i, 171); + eina_value_flush(&outv); + + fail_unless(eina_value_set(&inv, 666)); + fail_unless(eina_model_property_set(m, "value", &inv)); + fail_unless(eina_model_property_get(m, "value", &outv)); + fail_unless(eina_value_get(&outv, &i)); + ck_assert_int_eq(i, 666); + + eina_value_flush(&outv); + eina_value_flush(&inv); + + fail_unless(eina_value_setup(&inv, EINA_VALUE_TYPE_STRING)); + fail_unless(eina_value_set(&inv, "Hello world!")); + fail_unless(eina_model_property_set(m, "string", &inv)); + + fail_unless(eina_model_property_get(m, "string", &outv)); + fail_unless(eina_value_get(&outv, &s)); + fail_unless(s != NULL); + ck_assert_str_eq(s, "Hello world!"); + + eina_value_flush(&outv); + eina_value_flush(&inv); + + fail_unless(eina_value_setup(&inv, EINA_VALUE_TYPE_STRINGSHARE)); + fail_unless(eina_value_set(&inv, "Hello world-STRINGSHARED!")); + fail_unless(eina_model_property_set(m, "stringshare", &inv)); + /* set twice to see if references drop to zero before new add, shouldn't */ + fail_unless(eina_model_property_set(m, "stringshare", &inv)); + + fail_unless(eina_model_property_get(m, "stringshare", &outv)); + fail_unless(eina_value_get(&outv, &s)); + fail_unless(s != NULL); + ck_assert_str_eq(s, "Hello world-STRINGSHARED!"); + + eina_value_flush(&outv); + eina_value_flush(&inv); + + s = eina_model_to_string(m); + fail_unless(s != NULL); + ck_assert_str_eq(s, "Eina_Model_Type_Generic({abc: 1234, string: Hello world!, stringshare: Hello world-STRINGSHARED!, value: 666, xyz: 5678}, [])"); + free(s); + + fail_unless(eina_model_property_del(m, "value")); + + /* negative test (check safety was displayed by using print_cb) */ + eina_log_print_cb_set(_eina_test_model_check_safety_null, &ck); + + ck = EINA_FALSE; + fail_if(eina_model_property_get(m, "non-existent", &outv)); + fail_unless(ck == EINA_TRUE); + + ck = EINA_FALSE; + fail_if(eina_model_property_get(m, NULL, &outv)); + fail_unless(ck == EINA_TRUE); + + ck = EINA_FALSE; + fail_if(eina_model_property_del(m, "value")); + fail_unless(ck == EINA_TRUE); + + /* revert print_cb to default */ + eina_log_print_cb_set(eina_log_print_cb_stderr, NULL); + + ck_assert_int_eq(eina_model_refcount(m), 1); + + eina_model_unref(m); + ck_assert_int_eq(count_del, 1); + ck_assert_int_eq(count_pset, 7); + ck_assert_int_eq(count_pdel, 1); + eina_shutdown(); +} +END_TEST + +static int +eina_model_test_children_reverse_cmp(const Eina_Model *a, const Eina_Model *b) +{ + return - eina_model_compare(a, b); +} + +START_TEST(eina_model_test_children) +{ + unsigned int count_del = 0, count_cset = 0, count_cins = 0, count_cdel = 0; + Eina_Model *m, *c; + char *s; + int i; + + eina_init(); + + m = eina_model_new(EINA_MODEL_TYPE_GENERIC); + fail_unless(m != NULL); + + eina_model_event_callback_add + (m, "deleted", _eina_test_model_cb_count, &count_del); + eina_model_event_callback_add + (m, "child,set", _eina_test_model_cb_count, &count_cset); + eina_model_event_callback_add + (m, "child,inserted", _eina_test_model_cb_count, &count_cins); + eina_model_event_callback_add + (m, "child,deleted", _eina_test_model_cb_count, &count_cdel); + + for (i = 0; i < 10; i++) + { + Eina_Value val; + + c = eina_model_new(EINA_MODEL_TYPE_GENERIC); + fail_unless(c != NULL); + + eina_model_event_callback_add + (c, "deleted", _eina_test_model_cb_count, &count_del); + eina_model_event_callback_add + (c, "child,set", _eina_test_model_cb_count, &count_cset); + eina_model_event_callback_add + (c, "child,inserted", _eina_test_model_cb_count, &count_cins); + eina_model_event_callback_add + (c, "child,deleted", _eina_test_model_cb_count, &count_cdel); + + fail_unless(eina_value_setup(&val, EINA_VALUE_TYPE_INT)); + fail_unless(eina_value_set(&val, i)); + fail_unless(eina_model_property_set(c, "value", &val)); + + fail_unless(eina_model_child_append(m, c) >= 0); + ck_assert_int_eq(eina_model_refcount(c), 2); + + eina_value_flush(&val); + eina_model_unref(c); + } + + ck_assert_int_eq(eina_model_child_count(m), 10); + + for (i = 0; i < 10; i++) + { + Eina_Value val; + int x; + + c = eina_model_child_get(m, i); + fail_unless(c != NULL); + ck_assert_int_eq(eina_model_refcount(c), 2); + + fail_unless(eina_model_property_get(c, "value", &val)); + fail_unless(eina_value_get(&val, &x)); + ck_assert_int_eq(x, i); + + eina_value_flush(&val); + eina_model_unref(c); + } + + eina_model_child_sort(m, EINA_COMPARE_CB(eina_model_test_children_reverse_cmp)); + + for (i = 0; i < 10; i++) + { + Eina_Value val; + int x; + + c = eina_model_child_get(m, i); + fail_unless(c != NULL); + ck_assert_int_eq(eina_model_refcount(c), 2); + + fail_unless(eina_model_property_get(c, "value", &val)); + fail_unless(eina_value_get(&val, &x)); + ck_assert_int_eq(x, 10 - i - 1); + + eina_value_flush(&val); + eina_model_unref(c); + } + + eina_model_child_sort(m, EINA_COMPARE_CB(eina_model_compare)); + + s = eina_model_to_string(m); + fail_unless(s != NULL); + ck_assert_str_eq(s, "Eina_Model_Type_Generic({}, [Eina_Model_Type_Generic({value: 0}, []), Eina_Model_Type_Generic({value: 1}, []), Eina_Model_Type_Generic({value: 2}, []), Eina_Model_Type_Generic({value: 3}, []), Eina_Model_Type_Generic({value: 4}, []), Eina_Model_Type_Generic({value: 5}, []), Eina_Model_Type_Generic({value: 6}, []), Eina_Model_Type_Generic({value: 7}, []), Eina_Model_Type_Generic({value: 8}, []), Eina_Model_Type_Generic({value: 9}, [])])"); + free(s); + + c = eina_model_child_get(m, 0); + eina_model_child_set(m, 1, c); + eina_model_unref(c); + + eina_model_child_del(m, 0); + eina_model_child_del(m, 8); + + s = eina_model_to_string(m); + fail_unless(s != NULL); + ck_assert_str_eq(s, "Eina_Model_Type_Generic({}, [Eina_Model_Type_Generic({value: 0}, []), Eina_Model_Type_Generic({value: 2}, []), Eina_Model_Type_Generic({value: 3}, []), Eina_Model_Type_Generic({value: 4}, []), Eina_Model_Type_Generic({value: 5}, []), Eina_Model_Type_Generic({value: 6}, []), Eina_Model_Type_Generic({value: 7}, []), Eina_Model_Type_Generic({value: 8}, [])])"); + free(s); + + ck_assert_int_eq(eina_model_refcount(m), 1); + eina_model_unref(m); + + ck_assert_int_eq(count_del, 11); + ck_assert_int_eq(count_cins, 10); + ck_assert_int_eq(count_cset, 1); + ck_assert_int_eq(count_cdel, 2); + + eina_shutdown(); +} +END_TEST + +START_TEST(eina_model_test_copy) +{ + unsigned int count_del = 0; + Eina_Model *m, *cp; + char *s1, *s2; + int i; + + eina_init(); + + m = eina_model_new(EINA_MODEL_TYPE_GENERIC); + fail_unless(m != NULL); + + eina_model_event_callback_add + (m, "deleted", _eina_test_model_cb_count, &count_del); + + for (i = 0; i < 5; i++) + { + Eina_Value val; + char name[2] = {'a'+ i, 0}; + fail_unless(eina_value_setup(&val, EINA_VALUE_TYPE_INT)); + fail_unless(eina_value_set(&val, i)); + fail_unless(eina_model_property_set(m, name, &val)); + eina_value_flush(&val); + } + + for (i = 0; i < 5; i++) + { + Eina_Value val; + Eina_Model *c = eina_model_new(EINA_MODEL_TYPE_GENERIC); + fail_unless(c != NULL); + fail_unless(eina_value_setup(&val, EINA_VALUE_TYPE_INT)); + fail_unless(eina_value_set(&val, i)); + fail_unless(eina_model_property_set(c, "x", &val)); + + eina_model_event_callback_add + (c, "deleted", _eina_test_model_cb_count, &count_del); + + fail_unless(eina_model_child_append(m, c) >= 0); + eina_model_unref(c); + eina_value_flush(&val); + } + + s1 = eina_model_to_string(m); + fail_unless(s1 != NULL); + ck_assert_str_eq(s1, "Eina_Model_Type_Generic({a: 0, b: 1, c: 2, d: 3, e: 4}, [Eina_Model_Type_Generic({x: 0}, []), Eina_Model_Type_Generic({x: 1}, []), Eina_Model_Type_Generic({x: 2}, []), Eina_Model_Type_Generic({x: 3}, []), Eina_Model_Type_Generic({x: 4}, [])])"); + + cp = eina_model_copy(m); + fail_unless(cp != NULL); + fail_unless(cp != m); + + eina_model_event_callback_add + (cp, "deleted", _eina_test_model_cb_count, &count_del); + + s2 = eina_model_to_string(cp); + fail_unless(s2 != NULL); + ck_assert_str_eq(s1, s2); + + for (i = 0; i < 5; i++) + { + Eina_Model *c1 = eina_model_child_get(m, i); + Eina_Model *c2 = eina_model_child_get(cp, i); + + fail_unless(c1 != NULL); + fail_unless(c1 == c2); + ck_assert_int_eq(eina_model_refcount(c1), 4); + + eina_model_unref(c1); + eina_model_unref(c2); + } + + free(s1); + free(s2); + + ck_assert_int_eq(eina_model_refcount(m), 1); + eina_model_unref(m); + + ck_assert_int_eq(eina_model_refcount(cp), 1); + eina_model_unref(cp); + + ck_assert_int_eq(count_del, 2 + 5); + + eina_shutdown(); +} +END_TEST + +START_TEST(eina_model_test_deep_copy) +{ + unsigned int count_del = 0; + Eina_Model *m, *cp; + char *s1, *s2; + int i; + + eina_init(); + + m = eina_model_new(EINA_MODEL_TYPE_GENERIC); + fail_unless(m != NULL); + + eina_model_event_callback_add + (m, "deleted", _eina_test_model_cb_count, &count_del); + + for (i = 0; i < 5; i++) + { + Eina_Value val; + char name[2] = {'a'+ i, 0}; + fail_unless(eina_value_setup(&val, EINA_VALUE_TYPE_INT)); + fail_unless(eina_value_set(&val, i)); + fail_unless(eina_model_property_set(m, name, &val)); + eina_value_flush(&val); + } + + for (i = 0; i < 5; i++) + { + Eina_Value val; + Eina_Model *c = eina_model_new(EINA_MODEL_TYPE_GENERIC); + fail_unless(c != NULL); + fail_unless(eina_value_setup(&val, EINA_VALUE_TYPE_INT)); + fail_unless(eina_value_set(&val, i)); + fail_unless(eina_model_property_set(c, "x", &val)); + + eina_model_event_callback_add + (c, "deleted", _eina_test_model_cb_count, &count_del); + + fail_unless(eina_model_child_append(m, c) >= 0); + eina_model_unref(c); + eina_value_flush(&val); + } + + s1 = eina_model_to_string(m); + fail_unless(s1 != NULL); + ck_assert_str_eq(s1, "Eina_Model_Type_Generic({a: 0, b: 1, c: 2, d: 3, e: 4}, [Eina_Model_Type_Generic({x: 0}, []), Eina_Model_Type_Generic({x: 1}, []), Eina_Model_Type_Generic({x: 2}, []), Eina_Model_Type_Generic({x: 3}, []), Eina_Model_Type_Generic({x: 4}, [])])");; + + cp = eina_model_deep_copy(m); + fail_unless(cp != NULL); + fail_unless(cp != m); + + eina_model_event_callback_add + (cp, "deleted", _eina_test_model_cb_count, &count_del); + + s2 = eina_model_to_string(cp); + fail_unless(s2 != NULL); + ck_assert_str_eq(s1, s2); + + for (i = 0; i < 5; i++) + { + Eina_Model *c1 = eina_model_child_get(m, i); + Eina_Model *c2 = eina_model_child_get(cp, i); + + fail_unless(c1 != NULL); + fail_unless(c1 != c2); + ck_assert_int_eq(eina_model_refcount(c1), 2); + ck_assert_int_eq(eina_model_refcount(c2), 2); + + eina_model_event_callback_add + (c2, "deleted", _eina_test_model_cb_count, &count_del); + + eina_model_unref(c1); + eina_model_unref(c2); + } + + free(s1); + free(s2); + + ck_assert_int_eq(eina_model_refcount(m), 1); + eina_model_unref(m); + + ck_assert_int_eq(eina_model_refcount(cp), 1); + eina_model_unref(cp); + + ck_assert_int_eq(count_del, 2 + 10); + + eina_shutdown(); +} +END_TEST + +static Eina_Model * +eina_model_test_iterator_setup(unsigned int *count_del) +{ + Eina_Model *m; + int i; + + m = eina_model_new(EINA_MODEL_TYPE_GENERIC); + fail_unless(m != NULL); + + eina_model_event_callback_add + (m, "deleted", _eina_test_model_cb_count, count_del); + + for (i = 0; i < 5; i++) + { + Eina_Value val; + Eina_Model *c = eina_model_new(EINA_MODEL_TYPE_GENERIC); + fail_unless(c != NULL); + fail_unless(eina_value_setup(&val, EINA_VALUE_TYPE_INT)); + fail_unless(eina_value_set(&val, i)); + fail_unless(eina_model_property_set(c, "x", &val)); + + eina_model_event_callback_add + (c, "deleted", _eina_test_model_cb_count, count_del); + + fail_unless(eina_model_child_append(m, c) >= 0); + eina_model_unref(c); + eina_value_flush(&val); + } + + return m; +} + +START_TEST(eina_model_test_child_iterator) +{ + unsigned int count_del = 0; + Eina_Iterator *it; + Eina_Model *m, *c; + int i = 0; + + eina_init(); + + m = eina_model_test_iterator_setup(&count_del); + + it = eina_model_child_iterator_get(m); + fail_unless(it != NULL); + EINA_ITERATOR_FOREACH(it, c) + { + Eina_Value tmp; + int x; + + ck_assert_int_eq(eina_model_refcount(c), 2); + fail_unless(eina_model_property_get(c, "x", &tmp)); + fail_unless(eina_value_get(&tmp, &x)); + ck_assert_int_eq(x, i); + + eina_model_unref(c); + i++; + } + ck_assert_int_eq(i, 5); + eina_iterator_free(it); + + ck_assert_int_eq(eina_model_refcount(m), 1); + eina_model_unref(m); + ck_assert_int_eq(count_del, 6); + eina_shutdown(); +} +END_TEST + +START_TEST(eina_model_test_child_reversed_iterator) +{ + unsigned int count_del = 0; + Eina_Iterator *it; + Eina_Model *m, *c; + int i = 4; + + eina_init(); + + m = eina_model_test_iterator_setup(&count_del); + + it = eina_model_child_reversed_iterator_get(m); + fail_unless(it != NULL); + EINA_ITERATOR_FOREACH(it, c) + { + Eina_Value tmp; + int x; + + ck_assert_int_eq(eina_model_refcount(c), 2); + fail_unless(eina_model_property_get(c, "x", &tmp)); + fail_unless(eina_value_get(&tmp, &x)); + ck_assert_int_eq(x, i); + + eina_model_unref(c); + i--; + } + ck_assert_int_eq(i, -1); + eina_iterator_free(it); + + ck_assert_int_eq(eina_model_refcount(m), 1); + eina_model_unref(m); + ck_assert_int_eq(count_del, 6); + eina_shutdown(); +} +END_TEST + +START_TEST(eina_model_test_child_sorted_iterator) +{ + unsigned int count_del = 0; + Eina_Iterator *it; + Eina_Model *m, *c; + int i = 4; + + eina_init(); + + m = eina_model_test_iterator_setup(&count_del); + + it = eina_model_child_sorted_iterator_get + (m, EINA_COMPARE_CB(eina_model_test_children_reverse_cmp)); + fail_unless(it != NULL); + EINA_ITERATOR_FOREACH(it, c) + { + Eina_Value tmp; + int x; + + /* 3 because sort takes an extra reference for its temp array */ + ck_assert_int_eq(eina_model_refcount(c), 3); + fail_unless(eina_model_property_get(c, "x", &tmp)); + fail_unless(eina_value_get(&tmp, &x)); + ck_assert_int_eq(x, i); + + eina_model_unref(c); + i--; + } + ck_assert_int_eq(i, -1); + eina_iterator_free(it); + + it = eina_model_child_sorted_iterator_get + (m, EINA_COMPARE_CB(eina_model_compare)); + fail_unless(it != NULL); + i = 0; + EINA_ITERATOR_FOREACH(it, c) + { + Eina_Value tmp; + int x; + + /* 3 because sort takes an extra reference for its temp array */ + ck_assert_int_eq(eina_model_refcount(c), 3); + fail_unless(eina_model_property_get(c, "x", &tmp)); + fail_unless(eina_value_get(&tmp, &x)); + ck_assert_int_eq(x, i); + + eina_model_unref(c); + i++; + } + ck_assert_int_eq(i, 5); + eina_iterator_free(it); + + ck_assert_int_eq(eina_model_refcount(m), 1); + eina_model_unref(m); + ck_assert_int_eq(count_del, 6); + eina_shutdown(); +} +END_TEST + +static Eina_Bool +eina_model_test_filter_event(const void *m, void *c, void *fdata) +{ + Eina_Value tmp; + int x; + fail_unless(m == fdata); + fail_unless(eina_model_property_get(c, "x", &tmp)); + fail_unless(eina_value_get(&tmp, &x)); + eina_value_flush(&tmp); + return x % 2 == 0; +} + +START_TEST(eina_model_test_child_filtered_iterator) +{ + unsigned int count_del = 0; + Eina_Iterator *it; + Eina_Model *m; + int i = 0, idx; + + eina_init(); + + m = eina_model_test_iterator_setup(&count_del); + + it = eina_model_child_filtered_iterator_get + (m, eina_model_test_filter_event, m); + fail_unless(it != NULL); + EINA_ITERATOR_FOREACH(it, idx) + { + Eina_Model *c; + Eina_Value tmp; + int x; + + ck_assert_int_eq(idx % 2, 0); + ck_assert_int_eq(idx, i); + + c = eina_model_child_get(m, idx); + fail_unless(c != NULL); + ck_assert_int_eq(eina_model_refcount(c), 2); + fail_unless(eina_model_property_get(c, "x", &tmp)); + fail_unless(eina_value_get(&tmp, &x)); + ck_assert_int_eq(x, i); + + eina_model_unref(c); + i += 2; + } + ck_assert_int_eq(i, 6); + eina_iterator_free(it); + + ck_assert_int_eq(eina_model_refcount(m), 1); + eina_model_unref(m); + ck_assert_int_eq(count_del, 6); + eina_shutdown(); +} +END_TEST + +START_TEST(eina_model_test_struct) +{ + unsigned int count_del = 0, count_pset = 0, count_pdel = 0; + Eina_Model *m; + struct myst { + int i; + char c; + }; + const Eina_Value_Struct_Member myst_members[] = { + EINA_VALUE_STRUCT_MEMBER(EINA_VALUE_TYPE_INT, struct myst, i), + EINA_VALUE_STRUCT_MEMBER(EINA_VALUE_TYPE_CHAR, struct myst, c) + }; + const Eina_Value_Struct_Desc myst_desc = { + EINA_VALUE_STRUCT_DESC_VERSION, + NULL, myst_members, EINA_C_ARRAY_LENGTH(myst_members), sizeof(struct myst) + }; + Eina_Value inv, outv; + int i; + char c, *s; + Eina_List *lst; + Eina_Bool ck; + + eina_init(); + + m = eina_model_struct_new(&myst_desc); + fail_unless(m != NULL); + + eina_model_event_callback_add + (m, "deleted", _eina_test_model_cb_count, &count_del); + eina_model_event_callback_add + (m, "property,set", _eina_test_model_cb_count, &count_pset); + eina_model_event_callback_add + (m, "property,deleted", _eina_test_model_cb_count, &count_pdel); + + fail_unless(eina_value_setup(&inv, EINA_VALUE_TYPE_INT)); + fail_unless(eina_value_set(&inv, 1234)); + fail_unless(eina_value_get(&inv, &i)); + ck_assert_int_eq(i, 1234); + fail_unless(eina_model_property_set(m, "i", &inv)); + + eina_value_flush(&inv); + fail_unless(eina_value_setup(&inv, EINA_VALUE_TYPE_CHAR)); + fail_unless(eina_value_set(&inv, 33)); + fail_unless(eina_value_get(&inv, &c)); + ck_assert_int_eq(c, 33); + fail_unless(eina_model_property_set(m, "c", &inv)); + + lst = eina_model_properties_names_list_get(m); + ck_assert_int_eq(eina_list_count(lst), 2); + + lst = eina_list_sort(lst, 0, EINA_COMPARE_CB(strcmp)); + ck_assert_str_eq("c", eina_list_nth(lst, 0)); + ck_assert_str_eq("i", eina_list_nth(lst, 1)); + + eina_model_properties_names_list_free(lst); + + fail_unless(eina_model_property_get(m, "i", &outv)); + fail_unless(outv.type == EINA_VALUE_TYPE_INT); + fail_unless(eina_value_get(&outv, &i)); + ck_assert_int_eq(i, 1234); + eina_value_flush(&outv); + + fail_unless(eina_model_property_get(m, "c", &outv)); + fail_unless(outv.type == EINA_VALUE_TYPE_CHAR); + fail_unless(eina_value_get(&outv, &c)); + ck_assert_int_eq(c, 33); + eina_value_flush(&outv); + + eina_value_flush(&inv); + + /* negative test (check safety was displayed by using print_cb) */ + eina_log_print_cb_set(_eina_test_model_check_safety_null, &ck); + + fail_if(eina_model_property_get(m, "non-existent", &outv)); + + ck = EINA_FALSE; + fail_if(eina_model_property_get(m, NULL, &outv)); + fail_unless(ck == EINA_TRUE); + + fail_unless(eina_value_setup(&inv, EINA_VALUE_TYPE_STRING)); + fail_unless(eina_value_set(&inv, "hello world")); + + eina_log_print_cb_set(_eina_test_model_check_safety_false, &ck); + + ck = EINA_FALSE; + fail_if(eina_model_property_set(m, "i", &inv)); + fail_unless(ck == EINA_TRUE); + + ck = EINA_FALSE; + fail_if(eina_model_property_set(m, "c", &inv)); + fail_unless(ck == EINA_TRUE); + + /* revert print_cb to default */ + eina_log_print_cb_set(eina_log_print_cb_stderr, NULL); + + fail_if(eina_model_property_del(m, "value")); + fail_if(eina_model_property_del(m, "i")); + fail_if(eina_model_property_del(m, "c")); + + eina_value_flush(&inv); + + s = eina_model_to_string(m); + fail_unless(s != NULL); + ck_assert_str_eq(s, "Eina_Model_Type_Struct({c: 33, i: 1234}, [])"); + free(s); + + ck_assert_int_eq(eina_model_refcount(m), 1); + + eina_model_unref(m); + ck_assert_int_eq(count_del, 1); + ck_assert_int_eq(count_pset, 2); + ck_assert_int_eq(count_pdel, 0); + eina_shutdown(); +} +END_TEST + +static Eina_Bool +_struct_complex_members_constructor(Eina_Model *m) +{ + struct myst { + Eina_Value_Array a; + Eina_Value_List l; + Eina_Value_Hash h; + Eina_Value_Struct s; + } st; + struct subst { + int i, j; + }; + static Eina_Value_Struct_Member myst_members[] = { + EINA_VALUE_STRUCT_MEMBER(NULL, struct myst, a), + EINA_VALUE_STRUCT_MEMBER(NULL, struct myst, l), + EINA_VALUE_STRUCT_MEMBER(NULL, struct myst, h), + EINA_VALUE_STRUCT_MEMBER(NULL, struct myst, s) + }; + static Eina_Value_Struct_Desc myst_desc = { + EINA_VALUE_STRUCT_DESC_VERSION, + NULL, myst_members, EINA_C_ARRAY_LENGTH(myst_members), sizeof(struct myst) + }; + static Eina_Value_Struct_Member subst_members[] = { + EINA_VALUE_STRUCT_MEMBER(NULL, struct subst, i), + EINA_VALUE_STRUCT_MEMBER(NULL, struct subst, j) + }; + static Eina_Value_Struct_Desc subst_desc = { + EINA_VALUE_STRUCT_DESC_VERSION, + NULL, subst_members, EINA_C_ARRAY_LENGTH(subst_members), + sizeof(struct subst) + }; + + if (!myst_members[0].type) + { + myst_members[0].type = EINA_VALUE_TYPE_ARRAY; + myst_members[1].type = EINA_VALUE_TYPE_LIST; + myst_members[2].type = EINA_VALUE_TYPE_HASH; + myst_members[3].type = EINA_VALUE_TYPE_STRUCT; + } + + if (!subst_members[0].type) + { + subst_members[0].type = EINA_VALUE_TYPE_INT; + subst_members[1].type = EINA_VALUE_TYPE_INT; + } + + if (!eina_model_type_constructor(EINA_MODEL_TYPE_STRUCT, m)) + return EINA_FALSE; + + memset(&st, 0, sizeof(st)); + + st.a.subtype = EINA_VALUE_TYPE_STRING; + st.l.subtype = EINA_VALUE_TYPE_STRING; + st.h.subtype = EINA_VALUE_TYPE_STRING; + st.s.desc = &subst_desc; + if (!eina_model_struct_set(m, &myst_desc, &st)) + return EINA_FALSE; + + return EINA_TRUE; +} + +START_TEST(eina_model_test_struct_complex_members) +{ + Eina_Model *m; + Eina_Value outv; + char *s; + Eina_Model_Type type = EINA_MODEL_TYPE_INIT_NOPRIVATE + ("struct_complex_members", Eina_Model_Type, NULL, NULL, NULL); + + eina_init(); + + type.constructor = _struct_complex_members_constructor; + type.parent = EINA_MODEL_TYPE_STRUCT; + + m = eina_model_new(&type); + fail_unless(m != NULL); + + fail_unless(eina_model_property_get(m, "a", &outv)); + fail_unless(eina_value_array_append(&outv, "Hello")); + fail_unless(eina_value_array_append(&outv, "World")); + fail_unless(eina_model_property_set(m, "a", &outv)); + eina_value_flush(&outv); + + fail_unless(eina_model_property_get(m, "l", &outv)); + fail_unless(eina_value_list_append(&outv, "Some")); + fail_unless(eina_value_list_append(&outv, "Thing")); + fail_unless(eina_model_property_set(m, "l", &outv)); + eina_value_flush(&outv); + + fail_unless(eina_model_property_get(m, "h", &outv)); + fail_unless(eina_value_hash_set(&outv, "key", "value")); + fail_unless(eina_model_property_set(m, "h", &outv)); + eina_value_flush(&outv); + + fail_unless(eina_model_property_get(m, "s", &outv)); + fail_unless(eina_value_struct_set(&outv, "i", 1234)); + fail_unless(eina_value_struct_set(&outv, "j", 44)); + fail_unless(eina_model_property_set(m, "s", &outv)); + eina_value_flush(&outv); + + s = eina_model_to_string(m); + fail_unless(s != NULL); + ck_assert_str_eq(s, "struct_complex_members({a: [Hello, World], h: {key: value}, l: [Some, Thing], s: {i: 1234, j: 44}}, [])"); + free(s); + + ck_assert_int_eq(eina_model_refcount(m), 1); + + eina_model_unref(m); + eina_shutdown(); +} +END_TEST + +typedef struct _Animal_Type +{ + Eina_Model_Type parent_class; + void (*eat)(Eina_Model *mdl); +} Animal_Type; + +typedef struct _Human_Type +{ + Animal_Type parent_class; + void (*talk)(Eina_Model *mdl); +} Human_Type; + +typedef struct _Pooper_Interface +{ + Eina_Model_Interface base_interface; + void (*poop)(Eina_Model *mdl); +} Pooper_Interface; + +#define ANIMAL_TYPE(x) ((Animal_Type *) x) +#define HUMAN_TYPE(x) ((Human_Type *) x) +#define POOPER_IFACE(x) ((Pooper_Interface *) x) +#define POOPER_IFACE_NAME "Pooper_Interace" + +#define INHER_CB_COUNT(prefix) \ +static int prefix ## _count = 0; \ +static void \ +prefix (Eina_Model *mdl) \ +{ \ + (void) mdl; \ + (prefix ## _count)++; \ +} + +static void +animal_eat(Eina_Model *mdl) +{ + void (*pf)(Eina_Model *mdl); + pf = eina_model_method_resolve(mdl, Animal_Type, eat); + EINA_SAFETY_ON_NULL_RETURN(pf); + pf(mdl); +} + +static void +pooper_poop(Eina_Model *mdl) +{ + const Eina_Model_Interface *iface = NULL; + iface = eina_model_interface_get(mdl, POOPER_IFACE_NAME); + + EINA_SAFETY_ON_NULL_RETURN(iface); + + void (*pf)(Eina_Model *); + + pf = eina_model_interface_method_resolve(iface, mdl, Pooper_Interface, poop); + EINA_SAFETY_ON_NULL_RETURN(pf); + pf(mdl); +} + +INHER_CB_COUNT(_animal_poop); +INHER_CB_COUNT(_human_poop); +INHER_CB_COUNT(_animal_eat); +INHER_CB_COUNT(_human_eat); + +START_TEST(eina_model_test_inheritance) +{ + eina_init(); + + Pooper_Interface _ANIMAL_POOPER_IFACE; + Eina_Model_Interface *ANIMAL_POOPER_IFACE = (Eina_Model_Interface *) &_ANIMAL_POOPER_IFACE; + memset(&_ANIMAL_POOPER_IFACE, 0, sizeof(_ANIMAL_POOPER_IFACE)); + ANIMAL_POOPER_IFACE->version = EINA_MODEL_INTERFACE_VERSION; + ANIMAL_POOPER_IFACE->interface_size = sizeof(Pooper_Interface); + ANIMAL_POOPER_IFACE->name = POOPER_IFACE_NAME; + POOPER_IFACE(ANIMAL_POOPER_IFACE)->poop = _animal_poop; + + Pooper_Interface _HUMAN_POOPER_IFACE; + Eina_Model_Interface *HUMAN_POOPER_IFACE = (Eina_Model_Interface *) &_HUMAN_POOPER_IFACE; + const Eina_Model_Interface *HUMAN_POOPER_IFACES[] = { + ANIMAL_POOPER_IFACE, NULL + }; + memset(&_HUMAN_POOPER_IFACE, 0, sizeof(_HUMAN_POOPER_IFACE)); + HUMAN_POOPER_IFACE->version = EINA_MODEL_INTERFACE_VERSION; + HUMAN_POOPER_IFACE->interface_size = sizeof(Pooper_Interface); + HUMAN_POOPER_IFACE->name = POOPER_IFACE_NAME; + HUMAN_POOPER_IFACE->interfaces = HUMAN_POOPER_IFACES; + POOPER_IFACE(HUMAN_POOPER_IFACE)->poop = _human_poop; + + const Eina_Model_Interface *ANIMAL_IFACES[] = {ANIMAL_POOPER_IFACE, NULL}; + const Eina_Model_Interface *HUMAN_IFACES[] = {HUMAN_POOPER_IFACE, NULL}; + + /* Init Animal Type */ + Animal_Type _ANIMAL_TYPE; + Eina_Model_Type *ANIMAL_TYPE = (Eina_Model_Type *) &_ANIMAL_TYPE; + + memset(&_ANIMAL_TYPE, 0, sizeof(_ANIMAL_TYPE)); + Eina_Model_Type *type = (Eina_Model_Type *) &_ANIMAL_TYPE; + type->version = EINA_MODEL_TYPE_VERSION; + type->parent = EINA_MODEL_TYPE_BASE; + type->type_size = sizeof(Animal_Type); + type->name = "Animal_Type"; + type->parent = EINA_MODEL_TYPE_GENERIC; + type->interfaces = ANIMAL_IFACES; + + ANIMAL_TYPE(type)->eat = _animal_eat; + + /* Init Human Type */ + Animal_Type _HUMAN_TYPE; + Eina_Model_Type *HUMAN_TYPE = (Eina_Model_Type *) &_HUMAN_TYPE; + memset(&_HUMAN_TYPE, 0, sizeof(_HUMAN_TYPE)); + type = (Eina_Model_Type *) &_HUMAN_TYPE; + type->version = EINA_MODEL_TYPE_VERSION; + type->parent = ANIMAL_TYPE; + type->type_size = sizeof(Human_Type); + type->name = "Human_Type"; + type->interfaces = HUMAN_IFACES; + + ANIMAL_TYPE(type)->eat = _human_eat; + + Eina_Model *hm, *am; + am = eina_model_new(ANIMAL_TYPE); + hm = eina_model_new(HUMAN_TYPE); + + animal_eat(am); + ck_assert_int_eq(_animal_eat_count, 1); + animal_eat(hm); + ck_assert_int_eq(_human_eat_count, 1); + + pooper_poop(am); + ck_assert_int_eq(_animal_poop_count, 1); + pooper_poop(hm); + ck_assert_int_eq(_human_poop_count, 1); + + ck_assert_int_eq(_animal_eat_count, 1); + ck_assert_int_eq(_human_eat_count, 1); + ck_assert_int_eq(_animal_poop_count, 1); + ck_assert_int_eq(_human_poop_count, 1); + + ck_assert_int_eq(eina_model_refcount(am), 1); + ck_assert_int_eq(eina_model_refcount(hm), 1); + + eina_model_unref(am); + eina_model_unref(hm); + + eina_shutdown(); +} +END_TEST + +static Eina_Bool +_myproperties_load(Eina_Model *m) +{ + Eina_Value v; + Eina_Bool ret; + int count; + + if (!eina_model_property_get(m, "load_count", &v)) + return EINA_FALSE; + + eina_value_get(&v, &count); + count++; + eina_value_set(&v, count); + + ret = eina_model_property_set(m, "load_count", &v); + eina_value_flush(&v); + + return ret; +} + +static Eina_Bool +_myproperties_unload(Eina_Model *m) +{ + Eina_Value v; + Eina_Bool ret; + int count; + + if (!eina_model_property_get(m, "load_count", &v)) + return EINA_FALSE; + + eina_value_get(&v, &count); + count--; + eina_value_set(&v, count); + + ret = eina_model_property_set(m, "load_count", &v); + eina_value_flush(&v); + + return ret; +} + +static Eina_Bool +_mychildren_load(Eina_Model *m) +{ + Eina_Model *c = eina_model_new(EINA_MODEL_TYPE_GENERIC); + int ret = eina_model_child_append(m, c); + eina_model_unref(c); + return ret >= 0; +} + +static Eina_Bool +_mychildren_unload(Eina_Model *m) +{ + int count = eina_model_child_count(m); + EINA_SAFETY_ON_FALSE_RETURN_VAL(count > 0, EINA_FALSE); + return eina_model_child_del(m, count - 1); +} + +START_TEST(eina_model_test_ifaces_load_unload) +{ + unsigned int count_loaded = 0, count_unloaded = 0; + unsigned int count_ploaded = 0, count_punloaded = 0; + unsigned int count_cloaded = 0, count_cunloaded = 0; + static Eina_Model_Interface_Properties piface; + static Eina_Model_Interface_Children ciface; + static const Eina_Model_Interface *piface_parents[2] = {NULL, NULL}; + static const Eina_Model_Interface *ciface_parents[2] = {NULL, NULL}; + static const Eina_Model_Interface *type_ifaces[3] = { + &piface.base, &ciface.base, NULL + }; + static Eina_Model_Type type; + Eina_Model *m; + Eina_Value v; + int count; + + eina_init(); + + /* do after eina_init() otherwise interfaces are not set */ + piface_parents[0] = EINA_MODEL_INTERFACE_PROPERTIES_HASH; + ciface_parents[0] = EINA_MODEL_INTERFACE_CHILDREN_INARRAY; + + memset(&piface, 0, sizeof(piface)); + piface.base.version = EINA_MODEL_INTERFACE_VERSION; + piface.base.interface_size = sizeof(piface); + piface.base.name = EINA_MODEL_INTERFACE_NAME_PROPERTIES; + piface.base.interfaces = piface_parents; + piface.load = _myproperties_load; + piface.unload = _myproperties_unload; + + memset(&ciface, 0, sizeof(ciface)); + ciface.base.version = EINA_MODEL_INTERFACE_VERSION; + ciface.base.interface_size = sizeof(ciface); + ciface.base.name = EINA_MODEL_INTERFACE_NAME_CHILDREN; + ciface.base.interfaces = ciface_parents; + ciface.load = _mychildren_load; + ciface.unload = _mychildren_unload; + + type.version = EINA_MODEL_TYPE_VERSION; + type.private_size = 0; + type.name = "MyType"; + eina_model_type_subclass_setup(&type, EINA_MODEL_TYPE_GENERIC); + type.interfaces = type_ifaces; + + m = eina_model_new(&type); + fail_unless(m != NULL); + + eina_model_event_callback_add + (m, "loaded", _eina_test_model_cb_count, &count_loaded); + eina_model_event_callback_add + (m, "unloaded", _eina_test_model_cb_count, &count_unloaded); + + eina_model_event_callback_add + (m, "properties,loaded", _eina_test_model_cb_count, &count_ploaded); + eina_model_event_callback_add + (m, "properties,unloaded", _eina_test_model_cb_count, &count_punloaded); + + eina_model_event_callback_add + (m, "children,loaded", _eina_test_model_cb_count, &count_cloaded); + eina_model_event_callback_add + (m, "children,unloaded", _eina_test_model_cb_count, &count_cunloaded); + + fail_unless(eina_value_setup(&v, EINA_VALUE_TYPE_INT)); + fail_unless(eina_value_set(&v, 0)); + fail_unless(eina_model_property_set(m, "load_count", &v)); + eina_value_flush(&v); + + fail_unless(eina_model_load(m)); + fail_unless(eina_model_load(m)); + fail_unless(eina_model_load(m)); + + /* each load increments one for load_count property */ + fail_unless(eina_model_property_get(m, "load_count", &v)); + fail_unless(eina_value_pget(&v, &count)); + ck_assert_int_eq(count, 3); + eina_value_flush(&v); + + /* each load adds one child */ + ck_assert_int_eq(eina_model_child_count(m), 3); + + fail_unless(eina_model_unload(m)); + fail_unless(eina_model_unload(m)); + fail_unless(eina_model_unload(m)); + + ck_assert_int_eq(count_loaded, 3); + ck_assert_int_eq(count_unloaded, 3); + + ck_assert_int_eq(count_ploaded, 3); + ck_assert_int_eq(count_punloaded, 3); + + ck_assert_int_eq(count_cloaded, 3); + ck_assert_int_eq(count_cunloaded, 3); + + ck_assert_int_eq(eina_model_refcount(m), 1); + eina_model_unref(m); + + eina_shutdown(); +} +END_TEST + +void +eina_test_model(TCase *tc) +{ + tcase_add_test(tc, eina_model_test_properties); + tcase_add_test(tc, eina_model_test_children); + tcase_add_test(tc, eina_model_test_copy); + tcase_add_test(tc, eina_model_test_deep_copy); + tcase_add_test(tc, eina_model_test_child_iterator); + tcase_add_test(tc, eina_model_test_child_reversed_iterator); + tcase_add_test(tc, eina_model_test_child_sorted_iterator); + tcase_add_test(tc, eina_model_test_child_filtered_iterator); + tcase_add_test(tc, eina_model_test_struct); + tcase_add_test(tc, eina_model_test_struct_complex_members); + tcase_add_test(tc, eina_model_test_inheritance); + tcase_add_test(tc, eina_model_test_ifaces_load_unload); +} -- cgit v1.1