/* EFL - EFL library * Copyright (C) 2018 Cedric Bail * * 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 "efl_ui_suite.h" static const int child_number = 3; static const int base_ints[] = { 41, 42, 43 }; static const char *_efl_test_view_model_label_format = "Index %i."; static const char *dependences[] = { "test_p_int" }; static Eina_Value * _efl_test_view_model_label_get(void *data, const Efl_Ui_View_Model *mv, Eina_Stringshare *property) { Eina_Strbuf *buf; Eina_Value *r; Eina_Value *p_int; int v_int; const char *format = data; ck_assert(strcmp(property, "label") == 0); p_int = efl_model_property_get(mv, "test_p_int"); ck_assert(eina_value_int_get(p_int, &v_int) == EINA_TRUE); buf = eina_strbuf_new(); eina_strbuf_append_printf(buf, format, v_int); r = eina_value_string_new(eina_strbuf_string_get(buf)); eina_strbuf_free(buf); return r; } static Eina_Future * _efl_test_view_model_label_set(void *data EINA_UNUSED, Efl_Ui_View_Model *mv, Eina_Stringshare *property EINA_UNUSED, Eina_Value *value EINA_UNUSED) { return efl_loop_future_rejected(mv, EFL_MODEL_ERROR_READ_ONLY); } static void _efl_test_view_model_label_clean(void *data) { ck_assert_ptr_eq(data, _efl_test_view_model_label_format); } static Eina_Value * _efl_test_view_model_color_get(void *data EINA_UNUSED, const Efl_Ui_View_Model *mv, Eina_Stringshare *property) { Eina_Strbuf *buf; Eina_Value *r; Eina_Value *p_int; int v_int; ck_assert(strcmp(property, "color") == 0); p_int = efl_model_property_get(mv, "test_p_int"); ck_assert(eina_value_int_get(p_int, &v_int) == EINA_TRUE); buf = eina_strbuf_new(); eina_strbuf_append_printf(buf, "#%02x%02x%02x%02x", v_int, v_int, v_int, v_int); r = eina_value_string_new(eina_strbuf_string_get(buf)); eina_strbuf_free(buf); return r; } static Eina_Future * _efl_test_view_model_color_set(void *data EINA_UNUSED, Efl_Ui_View_Model *mv, Eina_Stringshare *property EINA_UNUSED, Eina_Value *value EINA_UNUSED) { return efl_loop_future_rejected(mv, EFL_MODEL_ERROR_READ_ONLY); } static void _efl_test_view_model_color_clean(void *data EINA_UNUSED) { } static Eina_Value _dummy(Eo *obj EINA_UNUSED, void *data EINA_UNUSED, const Eina_Value value) { ck_abort(); return value; } static Eina_Value _expected_fail(Eo *o EINA_UNUSED, void *data EINA_UNUSED, Eina_Error error) { ck_assert_int_eq(error, EFL_MODEL_ERROR_READ_ONLY); return eina_value_int_init(0); } static unsigned int counting = 0; typedef struct _Property_Change_Test Property_Change_Test; struct _Property_Change_Test { Eina_Bool checked; const char *name; }; static void _properties_changed(void *data, const Efl_Event *event) { Efl_Model_Property_Event *ev = event->info; unsigned int *count = data; const char *property; Eina_Array_Iterator iterator; unsigned int i, j; Property_Change_Test tests[] = { { EINA_FALSE, "test_p_int" }, { EINA_FALSE, "color" }, { EINA_FALSE, "label" }, { EINA_FALSE, "output" } }; EINA_ARRAY_ITER_NEXT(ev->changed_properties, i, property, iterator) { for (j = 0; j < EINA_C_ARRAY_LENGTH(tests); j++) if (!strcmp(tests[j].name, property)) { fail_if(tests[j].checked); tests[j].checked = EINA_TRUE; break; } } for (j = 0; j < EINA_C_ARRAY_LENGTH(tests); j++) { fail_if(!tests[j].checked); } *count += 1; } static Eina_Value _efl_test_view_model_child_get(Eo *obj EINA_UNUSED, void *data EINA_UNUSED, const Eina_Value v) { Efl_Model *child; Eina_Future **all = NULL; Eina_Future *r; unsigned int i, len; fail_if(eina_value_type_get(&v) != EINA_VALUE_TYPE_ARRAY); all = calloc(eina_value_array_count(&v) + 1, sizeof (Eina_Future*)); if (!all) return eina_value_error_init(ENOMEM); EINA_VALUE_ARRAY_FOREACH(&v, len, i, child) { Eina_Value *p_int = NULL; Eina_Value *p_color = NULL; Eina_Value *p_label = NULL; Eina_Value *p_deadend = NULL; Eina_Value *p_output = NULL; Eina_Value *p_broken = NULL; Eina_Value *p_weird = NULL; char *s_output; char *s_weird; char *s_broken; char *color; char *error; Eina_Error err = 0; int v_int = 0; int vindex = 0; int vindex2 = 0; int rindex = 0; p_int = efl_model_property_get(child, "test_p_int"); ck_assert(eina_value_int_get(p_int, &v_int)); p_color = efl_model_property_get(child, "color"); p_label = efl_model_property_get(child, "label"); p_deadend = efl_model_property_get(child, "deadend"); p_output = efl_model_property_get(child, "output"); p_weird = efl_model_property_get(child, "weird"); p_broken = efl_model_property_get(child, "broken"); s_output = eina_value_to_string(p_output); s_weird = eina_value_to_string(p_weird); s_broken = eina_value_to_string(p_broken); sscanf(s_output, "Index %i. has #%ms for index %i", &rindex, &color, &vindex); sscanf(s_broken, "%i in error with '%m[A-Za-z ]'", &vindex2, &error); ck_assert_ptr_eq(eina_value_type_get(p_output), EINA_VALUE_TYPE_STRING); ck_assert_int_eq(rindex, v_int); ck_assert_int_eq(vindex2, vindex); ck_assert_str_eq(error, "Value not found"); free(s_output); free(s_weird); free(s_broken); free(color); free(error); ck_assert_ptr_eq(eina_value_type_get(p_deadend), EINA_VALUE_TYPE_ERROR); eina_value_error_get(p_deadend, &err); ck_assert_int_eq(err, EFL_MODEL_ERROR_NOT_SUPPORTED); efl_event_callback_add(child, EFL_MODEL_EVENT_PROPERTIES_CHANGED, _properties_changed, &counting); efl_future_then(child, efl_model_property_set(child, "color", p_label), .success = _dummy, .error = _expected_fail); efl_future_then(child, efl_model_property_set(child, "color", p_color), .success = _dummy, .error = _expected_fail); efl_future_then(child, efl_model_property_set(child, "deadend", eina_value_int_new(42)), .success = _dummy, .error = _expected_fail); all[i] = efl_model_property_set(child, "test_p_int", eina_value_int_new(v_int+100)); eina_value_free(p_color); eina_value_free(p_label); eina_value_free(p_deadend); eina_value_free(p_output); } all[i] = EINA_FUTURE_SENTINEL; r = eina_future_all_array(all); return eina_future_as_value(r); } static Eina_Value _efl_test_view_model_child_fetch(Eo *mv, void *data EINA_UNUSED, const Eina_Value v EINA_UNUSED) { Eina_Future *r; r = efl_model_children_slice_get(mv, 0, efl_model_children_count_get(mv)); return eina_future_as_value(r); } static Eina_Value _efl_test_view_model_child_updated_get(Eo *obj EINA_UNUSED, void *data EINA_UNUSED, const Eina_Value v) { Efl_Model *child; unsigned int i, len; fail_if(eina_value_type_get(&v) != EINA_VALUE_TYPE_ARRAY); EINA_VALUE_ARRAY_FOREACH(&v, len, i, child) { Eina_Value *p_int = NULL; Eina_Value *p_color = NULL; Eina_Value *p_label = NULL; const char *s_color = NULL; const char *s_label = NULL; int v_int = 0; p_int = efl_model_property_get(child, "test_p_int"); ck_assert(eina_value_int_get(p_int, &v_int)); ck_assert_int_gt(v_int, 100); p_color = efl_model_property_get(child, "color"); p_label = efl_model_property_get(child, "label"); eina_value_string_get(p_color, &s_color); eina_value_string_get(p_label, &s_label); ck_assert_ptr_ne(s_color, NULL); ck_assert_ptr_ne(s_label, NULL); } return eina_value_int_init(0); } static Eina_Value _efl_test_view_model_tests_end(Eo *obj, void *data EINA_UNUSED, const Eina_Value v) { efl_loop_quit(efl_loop_get(obj), v); return v; } EFL_START_TEST(efl_test_view_model) { Efl_Generic_Model *base_model, *child, *mv; Eina_Future *f; int i; Eina_Value v; base_model = efl_add_ref(EFL_GENERIC_MODEL_CLASS, efl_main_loop_get()); ck_assert(!!base_model); for (i = 0; i < child_number; ++i) { child = efl_model_child_add(base_model); ck_assert(!!child); v = eina_value_int_init(base_ints[i]); efl_model_property_set(child, "test_p_int", &v); } mv = efl_add_ref(EFL_UI_VIEW_MODEL_CLASS, efl_main_loop_get(), efl_ui_view_model_set(efl_added, base_model)); ck_assert(!!mv); efl_ui_view_model_property_logic_add(mv, "label", (void*) _efl_test_view_model_label_format, _efl_test_view_model_label_get, _efl_test_view_model_label_clean, (void*) _efl_test_view_model_label_format, _efl_test_view_model_label_set, _efl_test_view_model_label_clean, EINA_C_ARRAY_ITERATOR_NEW(dependences)); efl_ui_view_model_property_logic_add(mv, "color", NULL, _efl_test_view_model_color_get, _efl_test_view_model_color_clean, NULL, _efl_test_view_model_color_set, _efl_test_view_model_color_clean, EINA_C_ARRAY_ITERATOR_NEW(dependences)); efl_ui_view_model_property_logic_add(mv, "deadend", NULL, NULL, NULL, NULL, NULL, NULL, NULL); efl_ui_view_model_property_string_add(mv, "output", "${label} has ${color} for index ${index}", "${index} not ready", "${index} in error"); efl_ui_view_model_property_string_add(mv, "broken", "${nope} has ${color} for index ${index}", "${index} not ready", "${index} in error with '${nope}'"); efl_ui_view_model_property_string_add(mv, "weird", "${} % { } has ${", NULL, NULL); f = efl_model_children_slice_get(mv, 0, efl_model_children_count_get(mv)); f = efl_future_then(mv, f, .success_type = EINA_VALUE_TYPE_ARRAY, .success = _efl_test_view_model_child_get); f = efl_future_then(mv, f, .success = _efl_test_view_model_child_fetch); f = efl_future_then(mv, f, .success_type = EINA_VALUE_TYPE_ARRAY, .success = _efl_test_view_model_child_updated_get); f = efl_future_then(mv, f, .success_type = EINA_VALUE_TYPE_INT, .success = _efl_test_view_model_tests_end); // And run ! ecore_main_loop_begin(); // We expect each child to have their property updated ck_assert_int_eq(counting, child_number); } EFL_END_TEST void efl_ui_test_view_model(TCase *tc) { tcase_add_test(tc, efl_test_view_model); }