diff options
author | Guilherme Lepsch <lepsch@expertisesolutions.com.br> | 2015-07-31 11:27:21 -0300 |
---|---|---|
committer | Guilherme Lepsch <lepsch@expertisesolutions.com.br> | 2015-08-03 11:30:59 -0300 |
commit | 802cddc8d3a9564f42ff2973a475eb8a9e7014eb (patch) | |
tree | 4b6293189dc0ea543502319b08c528770be2d9bd | |
parent | 258ced1b386b63392ab5e84fd09b0bedd3d38898 (diff) | |
download | efl-802cddc8d3a9564f42ff2973a475eb8a9e7014eb.tar.gz |
eflat_xml_model: "Flat" Xml Model implementation
-rw-r--r-- | Makefile.am | 16 | ||||
-rw-r--r-- | cmakeconfig/EflatXmlModelConfig.cmake.in | 32 | ||||
-rw-r--r-- | cmakeconfig/EflatXmlModelCxxConfig.cmake.in | 30 | ||||
-rw-r--r-- | configure.ac | 51 | ||||
-rw-r--r-- | pc/eflat_xml_model-cxx.pc.in | 12 | ||||
-rw-r--r-- | pc/eflat_xml_model.pc.in | 12 | ||||
-rw-r--r-- | src/Makefile.am | 2 | ||||
-rw-r--r-- | src/Makefile_EflatXmlModel.am | 84 | ||||
-rw-r--r-- | src/Makefile_EflatXmlModel_Cxx.am | 22 | ||||
-rw-r--r-- | src/lib/eflat_xml_model/Eflat_Xml_Model.h | 62 | ||||
-rw-r--r-- | src/lib/eflat_xml_model/eflat_xml_model.c | 1049 | ||||
-rw-r--r-- | src/lib/eflat_xml_model/eflat_xml_model.eo | 34 | ||||
-rw-r--r-- | src/lib/eflat_xml_model/eflat_xml_model_private.h | 34 | ||||
-rw-r--r-- | src/tests/eflat_xml_model/eflat_xml_model_suite.c | 121 | ||||
-rw-r--r-- | src/tests/eflat_xml_model/eflat_xml_model_suite.h | 16 | ||||
-rw-r--r-- | src/tests/eflat_xml_model/eflat_xml_model_test_eflat_xml_model.c | 503 | ||||
-rw-r--r-- | src/tests/eflat_xml_model/eflat_xml_model_test_eflat_xml_model.h | 6 |
17 files changed, 2083 insertions, 3 deletions
diff --git a/Makefile.am b/Makefile.am index 8d2425b01c..1fc5897382 100644 --- a/Makefile.am +++ b/Makefile.am @@ -151,7 +151,8 @@ pc/edje.pc \ pc/emotion.pc \ pc/ethumb.pc \ pc/ethumb_client.pc \ -pc/elocation.pc +pc/elocation.pc \ +pc/eflat_xml_model.pc if HAVE_CXX11 pkgconfig_DATA += \ @@ -163,7 +164,8 @@ pc/eolian-cxx.pc \ pc/edje-cxx.pc \ pc/eet-cxx.pc \ pc/eo-cxx.pc \ -pc/eio-cxx.pc +pc/eio-cxx.pc \ +pc/eflat_xml_model-cxx.pc endif if HAVE_ELUA @@ -382,6 +384,16 @@ emile_cmakeconfig_DATA = \ cmakeconfig/EmileConfig.cmake \ cmakeconfig/EmileConfigVersion.cmake +eflat_xml_model_cxx_cmakeconfigdir = $(libdir)/cmake/EflatXmlModelCxx/ +eflat_xml_model_cxx_cmakeconfig_DATA = \ +cmakeconfig/EflatXmlModelCxxConfig.cmake \ +cmakeconfig/EflatXmlModelCxxConfigVersion.cmake + +eflat_xml_model_cmakeconfigdir = $(libdir)/cmake/EflatXmlModel/ +eflat_xml_model_cmakeconfig_DATA = \ +cmakeconfig/EflatXmlModelConfig.cmake \ +cmakeconfig/EflatXmlModelConfigVersion.cmake + # D-Bus services: servicedir = @dbusservicedir@ diff --git a/cmakeconfig/EflatXmlModelConfig.cmake.in b/cmakeconfig/EflatXmlModelConfig.cmake.in new file mode 100644 index 0000000000..95a307d57f --- /dev/null +++ b/cmakeconfig/EflatXmlModelConfig.cmake.in @@ -0,0 +1,32 @@ +# - Try to find eflat_xml_model +# Once done this will define +# EFLAT_XML_MODEL_FOUND - System has eflat_xml_model +# EFLAT_XML_MODEL_INCLUDE_DIRS - The eflat_xml_model include directories +# EFLAT_XML_MODEL_LIBRARIES - The libraries needed to use eflat_xml_model +# EFLAT_XML_MODEL_DEFINITIONS - Compiler switches required for using eflat_xml_model + +set(MY_PKG eflat_xml_model) + +find_package(PkgConfig) +if ("${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}.${CMAKE_PATCH_VERSION}" VERSION_GREATER "2.8.1") + # "QUIET" was introduced in 2.8.2 + set(_QUIET QUIET) +endif () +pkg_check_modules(PC_LIBEFLAT_XML_MODEL ${_QUIET} ${MY_PKG}) + +find_library(EFLAT_XML_MODEL_LIBRARY + NAMES ${PC_LIBEFLAT_XML_MODEL_LIBRARIES} + HINTS ${PC_LIBEFLAT_XML_MODEL_LIBDIR} ${PC_LIBEFLAT_XML_MODEL_LIBRARY_DIRS} ) + +set(EFLAT_XML_MODEL_DEFINITIONS ${PC_LIBEFLAT_XML_MODEL_CFLAGS_OTHER}) +set(EFLAT_XML_MODEL_LIBRARIES ${EFLAT_XML_MODEL_LIBRARY}) +set(EFLAT_XML_MODEL_INCLUDE_DIRS ${PC_LIBEFLAT_XML_MODEL_INCLUDE_DIRS}) + +include(FindPackageHandleStandardArgs) +# handle the QUIETLY and REQUIRED arguments and set EFLAT_XML_MODEL_FOUND to TRUE +# if all listed variables are TRUE +find_package_handle_standard_args(${MY_PKG} DEFAULT_MSG + EFLAT_XML_MODEL_LIBRARIES EFLAT_XML_MODEL_INCLUDE_DIRS) + +mark_as_advanced(EFLAT_XML_MODEL_INCLUDE_DIRS EFLAT_XML_MODEL_LIBRARY EFLAT_XML_MODEL_LIBRARIES EFLAT_XML_MODEL_DEFINITIONS) + diff --git a/cmakeconfig/EflatXmlModelCxxConfig.cmake.in b/cmakeconfig/EflatXmlModelCxxConfig.cmake.in new file mode 100644 index 0000000000..c51ebff515 --- /dev/null +++ b/cmakeconfig/EflatXmlModelCxxConfig.cmake.in @@ -0,0 +1,30 @@ +# - Try to find eflat_xml_model +# Once done this will define +# EFLAT_XML_MODEL_CXX_FOUND - System has eflat_xml_model +# EFLAT_XML_MODEL_CXX_INCLUDE_DIRS - The eflat_xml_model include directories +# EFLAT_XML_MODEL_CXX_LIBRARIES - The libraries needed to use eflat_xml_model +# EFLAT_XML_MODEL_CXX_DEFINITIONS - Compiler switches required for using eflat_xml_model + +set(MY_PKG eflat_xml_model_cxx) + +find_package(PkgConfig) +if ("${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}.${CMAKE_PATCH_VERSION}" VERSION_GREATER "2.8.1") + # "QUIET" was introduced in 2.8.2 + set(_QUIET QUIET) +endif () +pkg_check_modules(PC_EFLAT_XML_MODEL_CXX ${_QUIET} ${MY_PKG}) +find_library(EFLAT_XML_MODEL_CXX_LIBRARY + NAMES ${PC_EFLAT_XML_MODEL_CXX_LIBRARIES} + HINTS ${PC_EFLAT_XML_MODEL_CXX_LIBDIR} ${PC_EFLAT_XML_MODEL_CXX_LIBRARY_DIRS} ) + +set(EFLAT_XML_MODEL_CXX_DEFINITIONS ${PC_EFLAT_XML_MODEL_CXX_CFLAGS_OTHER}) +set(EFLAT_XML_MODEL_CXX_LIBRARIES ${EFLAT_XML_MODEL_CXX_LIBRARY}) +set(EFLAT_XML_MODEL_CXX_INCLUDE_DIRS ${PC_EFLAT_XML_MODEL_CXX_INCLUDE_DIRS}) + +include(FindPackageHandleStandardArgs) +# handle the QUIETLY and REQUIRED arguments and set EFLAT_XML_MODEL_CXX_FOUND to TRUE +# if all listed variables are TRUE +find_package_handle_standard_args(${MY_PKG} DEFAULT_MSG + EFLAT_XML_MODEL_CXX_LIBRARIES EFLAT_XML_MODEL_CXX_INCLUDE_DIRS) + +mark_as_advanced(EFLAT_XML_MODEL_CXX_INCLUDE_DIRS EFLAT_XML_MODEL_CXX_LIBRARY EFLAT_XML_MODEL_CXX_LIBRARIES EFLAT_XML_MODEL_CXX_DEFINITIONS) diff --git a/configure.ac b/configure.ac index 7975e55755..3937baaa9e 100644 --- a/configure.ac +++ b/configure.ac @@ -3917,7 +3917,7 @@ EFL_INTERNAL_DEPEND_PKG([ECORE_EVAS], [emile]) ECORE_EVAS_MODULE([extn], [${want_ecore_evas_extn}]) ECORE_EVAS_MODULE([ews], [yes]) ECORE_EVAS_MODULE([fb], [${want_fb}]) -ECORE_EVAS_MODULE([drm], [${want_drm}], +ECORE_EVAS_MODULE([drm], [${want_drm}], [EFL_OPTIONAL_INTERNAL_DEPEND_PKG([ECORE_EVAS], [${want_drm}], [ecore-drm])]) ECORE_EVAS_MODULE([gl-drm], [${want_gl_drm}], [EFL_OPTIONAL_INTERNAL_DEPEND_PKG([ECORE_EVAS], [${want_gl_drm}], [ecore-drm])]) @@ -4566,6 +4566,48 @@ EFL_ADD_LIBS([ELOCATION], [-lm]) EFL_LIB_END([Elocation]) #### End of Elocation + + +#### Eflat_Xml_Model +EFL_LIB_START([Eflat_Xml_Model]) + +### Additional options to configure + +### Default values + +### Checks for programs + +### Checks for libraries +EFL_INTERNAL_DEPEND_PKG([EFLAT_XML_MODEL], [eo]) +EFL_INTERNAL_DEPEND_PKG([EFLAT_XML_MODEL], [efl]) +EFL_INTERNAL_DEPEND_PKG([EFLAT_XML_MODEL], [ecore]) + +EFL_EVAL_PKGS([EFLAT_XML_MODEL]) + +### Checks for header files + +### Checks for types + +### Checks for structures + +### Checks for compiler characteristics + +### Checks for linker characteristics + +### Checks for library functions + +EFL_LIB_END([Eflat_Xml_Model]) +#### End of Eflat_Xml_Model + +#### Eflat_Xml_Model CXX +EFL_LIB_START([Eflat_Xml_Model_Cxx]) + +EFL_EVAL_PKGS([EFLAT_XML_MODEL_CXX]) + +EFL_LIB_END([Eflat_Xml_Model_Cxx]) +#### End of Eflat_Xml_Model CXX + + ### Add Wayland server library if test is enabled if test "x${want_tests}" = "xyes" -a "x${want_wayland}" = "xyes"; then EFL_DEPEND_PKG([ECORE_WAYLAND_SRV], [WAYLAND], [wayland-server >= 1.8.0]) @@ -4754,6 +4796,8 @@ pc/ethumb.pc pc/ethumb_client.pc pc/elocation.pc pc/elua.pc +pc/eflat_xml_model.pc +pc/eflat_xml_model-cxx.pc dbus-services/org.enlightenment.Ethumb.service systemd-services/ethumb.service $po_makefile_in @@ -4803,6 +4847,10 @@ cmakeconfig/EluaConfig.cmake cmakeconfig/EluaConfigVersion.cmake:cmakeconfig/EFLConfigVersion.cmake.in cmakeconfig/EmileConfig.cmake cmakeconfig/EmileConfigVersion.cmake:cmakeconfig/EFLConfigVersion.cmake.in +cmakeconfig/EflatXmlModelConfig.cmake +cmakeconfig/EflatXmlModelConfigVersion.cmake:cmakeconfig/EFLConfigVersion.cmake.in +cmakeconfig/EflatXmlModelCxxConfig.cmake +cmakeconfig/EflatXmlModelCxxConfigVersion.cmake:cmakeconfig/EFLConfigVersion.cmake.in ]) AC_OUTPUT @@ -4916,6 +4964,7 @@ echo "Emotion.........: yes (${features_emotion})" echo "Ethumb..........: yes" echo "Ethumb_Client...: yes" echo "Elua............: $have_elua" +echo "Eflat_Xml_Model.: yes" if test "${build_tests}" = "none"; then echo "Tests...........: no" elif test "${build_tests}" = "auto"; then diff --git a/pc/eflat_xml_model-cxx.pc.in b/pc/eflat_xml_model-cxx.pc.in new file mode 100644 index 0000000000..7e80346e4f --- /dev/null +++ b/pc/eflat_xml_model-cxx.pc.in @@ -0,0 +1,12 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: Eflat_xml_model C++ +Description: "Flat" XML model for EFL +Requires.private: @requirements_pc_eflat_xml_model@ @requirements_pc_eo@ +Version: @VERSION@ +Libs: -L${libdir} -leflat_xml_model @requirements_public_libs_eflat_xml_model@ @requirements_public_libs_eo@ +Libs.private: @requirements_libs_eflat_xml_model@ @requirements_libs_eo@ +Cflags: -I${includedir}/efl-@VMAJ@ -I${includedir}/eo-@VMAJ@ -I${includedir}/eflat_xml_model-@VMAJ@ -I${includedir}/eflat_xml_model-cxx-@VMAJ@ diff --git a/pc/eflat_xml_model.pc.in b/pc/eflat_xml_model.pc.in new file mode 100644 index 0000000000..a7c8e236c8 --- /dev/null +++ b/pc/eflat_xml_model.pc.in @@ -0,0 +1,12 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: Eflat_xml_model +Description: "Flat" XML model for EFL +Requires.private: @requirements_pc_eflat_xml_model@ +Version: @VERSION@ +Libs: -L${libdir} -leflat_xml_model @requirements_public_libs_eflat_xml_model@ +Libs.private: @requirements_libs_eflat_xml_model@ +Cflags: -I${includedir}/efl-@VMAJ@ -I${includedir}/eflat_xml_model-@VMAJ@ diff --git a/src/Makefile.am b/src/Makefile.am index dccc538af2..964dc531f0 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -60,6 +60,7 @@ include Makefile_Edje.am include Makefile_Emotion.am include Makefile_Ethumb.am include Makefile_Ethumb_Client.am +include Makefile_EflatXmlModel.am include Makefile_Eina_Cxx.am include Makefile_Ecore_Cxx.am @@ -71,6 +72,7 @@ include Makefile_Efl_Cxx.am include Makefile_Edje_Cxx.am include Makefile_Evas_Cxx.am include Makefile_Eio_Cxx.am +include Makefile_EflatXmlModel_Cxx.am include Makefile_Elua.am include Makefile_Elocation.am diff --git a/src/Makefile_EflatXmlModel.am b/src/Makefile_EflatXmlModel.am new file mode 100644 index 0000000000..27c9bacf40 --- /dev/null +++ b/src/Makefile_EflatXmlModel.am @@ -0,0 +1,84 @@ +### Library + +eflat_xml_model_eolian_files = \ +lib/eflat_xml_model/eflat_xml_model.eo + +eflat_xml_model_eolian_c = $(eflat_xml_model_eolian_files:%.eo=%.eo.c) +eflat_xml_model_eolian_h = $(eflat_xml_model_eolian_files:%.eo=%.eo.h) + +BUILT_SOURCES += \ + $(eflat_xml_model_eolian_c) \ + $(eflat_xml_model_eolian_h) + +CLEANFILES += \ + $(eflat_xml_model_eolian_c) \ + $(eflat_xml_model_eolian_h) + +eflat_xml_modeleolianfilesdir = $(datadir)/eolian/include/eflat_xml_model-@VMAJ@ +eflat_xml_modeleolianfiles_DATA = \ + $(eflat_xml_model_eolian_files) + +EXTRA_DIST += \ + ${eflat_xml_modeleolianfiles_DATA} + +lib_LTLIBRARIES += lib/eflat_xml_model/libeflat_xml_model.la + +installed_eflat_xml_modelmainheadersdir = $(includedir)/eflat_xml_model-@VMAJ@ +dist_installed_eflat_xml_modelmainheaders_DATA = \ +lib/eflat_xml_model/Eflat_Xml_Model.h + +nodist_installed_eflat_xml_modelmainheaders_DATA = \ + $(eflat_xml_model_eolian_h) + +lib_eflat_xml_model_libeflat_xml_model_la_SOURCES = \ +lib/eflat_xml_model/eflat_xml_model_private.h \ +lib/eflat_xml_model/eflat_xml_model.c + +lib_eflat_xml_model_libeflat_xml_model_la_CPPFLAGS = -I$(top_builddir)/src/lib/efl @EFLAT_XML_MODEL_CFLAGS@ @EFL_CFLAGS@ +lib_eflat_xml_model_libeflat_xml_model_la_LIBADD = @EFLAT_XML_MODEL_LIBS@ @EFL_LIBS@ +lib_eflat_xml_model_libeflat_xml_model_la_DEPENDENCIES = @EFLAT_XML_MODEL_INTERNAL_LIBS@ @EFL_INTERNAL_LIBS@ +lib_eflat_xml_model_libeflat_xml_model_la_LDFLAGS = @EFL_LTLIBRARY_FLAGS@ + +### Unit tests + +if EFL_ENABLE_TESTS + +check_PROGRAMS += tests/eflat_xml_model/eflat_xml_model_suite +TESTS += tests/eflat_xml_model/eflat_xml_model_suite + +tests_eflat_xml_model_eflat_xml_model_suite_SOURCES = \ +tests/eflat_xml_model/eflat_xml_model_suite.c \ +tests/eflat_xml_model/eflat_xml_model_suite.h \ +tests/eflat_xml_model/eflat_xml_model_test_eflat_xml_model.c \ +tests/eflat_xml_model/eflat_xml_model_test_eflat_xml_model.h + +tests_eflat_xml_model_eflat_xml_model_suite_CPPFLAGS = -I$(top_builddir)/src/lib/efl \ +-DTESTS_SRC_DIR=\"$(abs_top_srcdir)/src/tests/eflat_xml_model\" \ +-DTESTS_BUILD_DIR=\"$(abs_top_builddir)/src/tests/eflat_xml_model\" \ +@CHECK_CFLAGS@ \ +@EFLAT_XML_MODEL_CFLAGS@ @EFL_CFLAGS@ + +tests_eflat_xml_model_eflat_xml_model_suite_LDADD = \ +@CHECK_LIBS@ \ +@USE_EFLAT_XML_MODEL_LIBS@ \ +@USE_EFL_LIBS@ + +tests_eflat_xml_model_eflat_xml_model_suite_DEPENDENCIES = \ +@USE_EFLAT_XML_MODEL_INTERNAL_LIBS@ + +endif + +EXTRA_DIST += $(EFLAT_XML_MODEL_DATA_FILES) + +if HAVE_ELUA + +eflat_xml_model_eolian_lua = $(eflat_xml_model_eolian_files:%.eo=%.eo.lua) + +generated_eflat_xml_model_lua_all = $(eflat_xml_model_eolian_lua) + +CLEANFILES += $(generated_eflat_xml_model_lua_all) + +installed_eflat_xml_modelluadir = $(datadir)/elua/modules/eflat_xml_model +nodist_installed_eflat_xml_modellua_DATA = $(generated_eflat_xml_model_lua_all) + +endif diff --git a/src/Makefile_EflatXmlModel_Cxx.am b/src/Makefile_EflatXmlModel_Cxx.am new file mode 100644 index 0000000000..ea5b451a01 --- /dev/null +++ b/src/Makefile_EflatXmlModel_Cxx.am @@ -0,0 +1,22 @@ +if HAVE_CXX11 + +### Generated headers + +generated_eflat_xml_model_cxx_bindings = $(eflat_xml_model_eolian_files:%.eo=%.eo.hh) + +lib/eflat_xml_model/Eflat_xml_model.hh: $(generated_eflat_xml_model_cxx_bindings) + @echo @ECHO_E@ "#ifndef EFL_CXX_EFLAT_XML_MODEL_HH\n#define EFL_CXX_EFLAT_XML_MODEL_HH\n" > $(top_builddir)/src/lib/eflat_xml_model/Eflat_xml_model.hh + @echo @ECHO_E@ "#ifdef EFL_BETA_API_SUPPORT" >> $(top_builddir)/src/lib/eflat_xml_model/Eflat_xml_model.hh + @for i in $(generated_eflat_xml_model_cxx_bindings); do echo "#include <$$(basename $$i)>" >> $(top_builddir)/src/lib/eflat_xml_model/Eflat_xml_model.hh; done + @echo @ECHO_E@ "#endif\n\n#endif\n" >> $(top_builddir)/src/lib/eflat_xml_model/Eflat_xml_model.hh + +generated_eflat_xml_model_cxx_all = \ + $(generated_eflat_xml_model_cxx_bindings) \ + lib/eflat_xml_model/Eflat_xml_model.hh + +CLEANFILES += $(generated_eflat_xml_model_cxx_all) + +installed_eflat_xml_modelcxxmainheadersdir = $(includedir)/eflat_xml_model-cxx-@VMAJ@/ +nodist_installed_eflat_xml_modelcxxmainheaders_DATA = $(generated_eflat_xml_model_cxx_all) + +endif diff --git a/src/lib/eflat_xml_model/Eflat_Xml_Model.h b/src/lib/eflat_xml_model/Eflat_Xml_Model.h new file mode 100644 index 0000000000..19b17eb31a --- /dev/null +++ b/src/lib/eflat_xml_model/Eflat_Xml_Model.h @@ -0,0 +1,62 @@ +#ifndef EFLAT_XML_H +#define EFLAT_XML_H + +#include <Ecore.h> +#include <Efl.h> +#include <Efl_Config.h> + +#ifdef EAPI +# undef EAPI +#endif + +#ifdef _WIN32 +# ifdef EFL_EFLAT_XML_MODEL_BUILD +# ifdef DLL_EXPORT +# define EAPI __declspec(dllexport) +# else +# define EAPI +# endif /* ! DLL_EXPORT */ +# else +# define EAPI __declspec(dllimport) +# endif /* ! EFL_EFLAT_XML_MODEL_BUILD */ +#else +# ifdef __GNUC__ +# if __GNUC__ >= 4 +# define EAPI __attribute__ ((visibility("default"))) +# else +# define EAPI +# endif +# else +# define EAPI +# endif +#endif /* ! _WIN32 */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Initialize eflat_xml_model. + * + * @return 1 or greater on success, 0 otherwise + */ +EAPI int eflat_xml_model_init(void); +/** + * @brief Shutdown eflat_xml_model. + * + * @return 0 if eflat_xml_model shuts down, greater than 0 otherwise. + */ +EAPI int eflat_xml_model_shutdown(void); + +#ifdef EFL_EO_API_SUPPORT +# include <eflat_xml_model.eo.h> +#endif + +#ifdef __cplusplus +} +#endif + +#undef EAPI +#define EAPI + +#endif diff --git a/src/lib/eflat_xml_model/eflat_xml_model.c b/src/lib/eflat_xml_model/eflat_xml_model.c new file mode 100644 index 0000000000..0588f92e49 --- /dev/null +++ b/src/lib/eflat_xml_model/eflat_xml_model.c @@ -0,0 +1,1049 @@ +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include "eflat_xml_model_private.h" + +#include <stdbool.h> +#include <stdint.h> +#include <stdlib.h> + +#define MY_CLASS EFLAT_XML_MODEL_CLASS +#define MY_CLASS_NAME "Eflat_Xml_Model" + +typedef enum +{ + EFLAT_XML_MODEL_PATH_TYPE_DATA, + EFLAT_XML_MODEL_PATH_TYPE_ATTRIBUTE, + EFLAT_XML_MODEL_PATH_TYPE_PROCESSING, + EFLAT_XML_MODEL_PATH_TYPE_RAW_XML +} Eflat_Xml_Model_Path_Type; + +typedef struct +{ + Eina_Simple_XML_Node_Tag *node; + Eflat_Xml_Model_Path_Type type; + union + { + Eina_Simple_XML_Attribute *attribute; + Eina_Simple_XML_Node_Processing *processing; + }; +} Eflat_Xml_Model_Path_Data; + +static void _properties_load(Eflat_Xml_Model_Data *); +static void _children_load(Eflat_Xml_Model_Data *); +static bool _init(Eflat_Xml_Model_Data *); +static void _clear(Eflat_Xml_Model_Data *); +static void _properties_setup(Eflat_Xml_Model_Data *); +static Eina_Simple_XML_Node_Tag *_tag_find(Eina_Simple_XML_Node_Tag *, const char *); +static Eina_Simple_XML_Attribute *_attribute_find(Eina_Simple_XML_Node_Tag *, const char *); +static Eina_Simple_XML_Node_Tag *_node_from_path_new(Eina_Simple_XML_Node_Root *, const char *, Eflat_Xml_Model_Path_Data *); +static Eina_Simple_XML_Node_Tag *_node_from_path_get(Eina_Simple_XML_Node_Root *, const char *, Eflat_Xml_Model_Path_Data *); +static void _node_children_del(Eina_Simple_XML_Node_Tag *); +static char *_path_from_node_get(Eina_Simple_XML_Node_Tag *); +static char *_concatenate_path(const char *, const char *, char); +static void _node_children_properties_del(Eflat_Xml_Model_Data *, Eina_Simple_XML_Node_Tag *, const char *); +static void _node_attributes_properties_del(Eflat_Xml_Model_Data *, Eina_Simple_XML_Node_Tag *, const char *); +static void _property_del(Eflat_Xml_Model_Data *, const char *); +static void _property_add(Eflat_Xml_Model_Data *, const char *, const char *); +static void _node_clear(Eflat_Xml_Model_Data *, Eina_Simple_XML_Node_Tag *); +static void _generate_properties_from_node(Eflat_Xml_Model_Data *, Eina_Simple_XML_Node_Tag *); +static Eina_Simple_XML_Node_Data *_data_value_set(Eina_Simple_XML_Node_Tag *, Eina_Simple_XML_Node_Data *, const char *); +static char *_data_name_get(const Eina_Simple_XML_Node_Data *); +static void _stream_load(Eflat_Xml_Model_Data *, Eina_Simple_XML_Node_Tag *, const char *); + +static int _eflat_xml_model_init_count = 0; +int _eflat_xml_model_log_dom = -1; + +EAPI int +eflat_xml_model_init(void) +{ + if (_eflat_xml_model_init_count++ > 0) + return _eflat_xml_model_init_count; + + if (!eina_init()) + { + fputs("Eflat_Xml_Model: Unable to initialize eina\n", stderr); + return 0; + } + + _eflat_xml_model_log_dom = eina_log_domain_register("eflat_xml_model", + EINA_COLOR_CYAN); + if (_eflat_xml_model_log_dom < 0) + { + EINA_LOG_ERR("Unable to create an 'eflat_xml_model' log domain"); + _eflat_xml_model_log_dom = -1; + eina_shutdown(); + return 0; + } + + if (!ecore_init()) + { + ERR("Unable to initialize ecore"); + eina_log_domain_unregister(_eflat_xml_model_log_dom); + _eflat_xml_model_log_dom = -1; + eina_shutdown(); + return 0; + } + + // ... + + return _eflat_xml_model_init_count; +} + +EAPI int +eflat_xml_model_shutdown(void) +{ + if (_eflat_xml_model_init_count <= 0) + { + ERR("Init count not greater than 0 in shutdown."); + _eflat_xml_model_init_count = 0; + return 0; + } + + if (--_eflat_xml_model_init_count) + return _eflat_xml_model_init_count; + + // ... + + ecore_shutdown(); + eina_log_domain_unregister(_eflat_xml_model_log_dom); + _eflat_xml_model_log_dom = -1; + eina_shutdown(); + return 0; +} + +static void +_eflat_xml_model_hash_free(Eina_Value *value) +{ + eina_value_free(value); +} + +static Eo_Base * +_eflat_xml_model_eo_base_constructor(Eo *obj, Eflat_Xml_Model_Data *pd) +{ + DBG("(%p)", obj); + + pd->obj = obj; + pd->load.status = EFL_MODEL_LOAD_STATUS_UNLOADED; + pd->properties_array = NULL; + pd->properties_hash = eina_hash_string_superfast_new(EINA_FREE_CB(_eflat_xml_model_hash_free)); + pd->root = NULL; + pd->xml = NULL; + eina_value_setup(&pd->xml_value, EINA_VALUE_TYPE_STRING); + + return eo_do_super_ret(obj, MY_CLASS, obj, eo_constructor()); +} + +static void +_eflat_xml_model_constructor(Eo *obj EINA_UNUSED, + Eflat_Xml_Model_Data *pd EINA_UNUSED, + const char *xml) +{ + DBG("(%p)", obj); + pd->xml = strdup(xml ? xml : ""); +} + +static void +_eflat_xml_model_eo_base_destructor(Eo *obj, Eflat_Xml_Model_Data *pd) +{ + DBG("(%p)", obj); + + _clear(pd); + eina_hash_free(pd->properties_hash); + free(pd->xml); + eina_value_flush(&pd->xml_value); + + eo_do_super(obj, MY_CLASS, eo_destructor()); +} + +static Efl_Model_Load_Status +_eflat_xml_model_efl_model_base_properties_get(Eo *obj EINA_UNUSED, + Eflat_Xml_Model_Data *pd, + Eina_Array * const* properties_array) +{ + DBG("(%p)", obj); + EINA_SAFETY_ON_NULL_RETURN_VAL(pd, EFL_MODEL_LOAD_STATUS_ERROR); + EINA_SAFETY_ON_NULL_RETURN_VAL(pd->obj, EFL_MODEL_LOAD_STATUS_ERROR); + + *(Eina_Array**)properties_array = pd->properties_array; + return pd->load.status; +} + +static void +_eflat_xml_model_efl_model_base_properties_load(Eo *obj, Eflat_Xml_Model_Data *pd) +{ + DBG("(%p)", obj); + + if (pd->load.status & EFL_MODEL_LOAD_STATUS_LOADED_PROPERTIES) + return; + + if (!_init(pd)) + return; + + efl_model_load_set(obj, &pd->load, EFL_MODEL_LOAD_STATUS_LOADING_PROPERTIES); + + _properties_load(pd); + + efl_model_load_set(obj, &pd->load, EFL_MODEL_LOAD_STATUS_LOADED_PROPERTIES); +} + +static void +_properties_load(Eflat_Xml_Model_Data *pd) +{ + DBG("(%p)", pd->obj); + + _properties_setup(pd); + + if (!pd->xml) + return; + + _generate_properties_from_node(pd, pd->root); +} + +static Efl_Model_Load_Status +_eflat_xml_model_efl_model_base_property_set(Eo *obj, + Eflat_Xml_Model_Data *pd, + const char *property, + const Eina_Value *value) +{ + EINA_SAFETY_ON_NULL_RETURN_VAL(property, EFL_MODEL_LOAD_STATUS_ERROR); + EINA_SAFETY_ON_NULL_RETURN_VAL(value, EFL_MODEL_LOAD_STATUS_ERROR); + DBG("(%p): property=%s", obj, property); + + if (!(pd->load.status & EFL_MODEL_LOAD_STATUS_LOADED_PROPERTIES)) + return EFL_MODEL_LOAD_STATUS_ERROR; + + Eflat_Xml_Model_Path_Data data; + Eina_Simple_XML_Node_Tag *node = _node_from_path_new(pd->root, + property, + &data); + EINA_SAFETY_ON_NULL_RETURN_VAL(node, EFL_MODEL_LOAD_STATUS_ERROR); + DBG("(%p)", obj); + + char *value_str = eina_value_to_string(value); + EINA_SAFETY_ON_NULL_RETURN_VAL(value_str, EFL_MODEL_LOAD_STATUS_ERROR); + + switch (data.type) + { + case EFLAT_XML_MODEL_PATH_TYPE_ATTRIBUTE: + { + eina_stringshare_del(data.attribute->value); + data.attribute->value = eina_stringshare_add(value_str); + break; + } + case EFLAT_XML_MODEL_PATH_TYPE_RAW_XML: + { + _stream_load(pd, node, value_str); + break; + } + case EFLAT_XML_MODEL_PATH_TYPE_DATA: + { + _node_clear(pd, node); + + // checks if it's a empty tag + size_t len = strlen(value_str); + if (len) + eina_simple_xml_node_data_new(node, value_str, len); + break; + } + case EFLAT_XML_MODEL_PATH_TYPE_PROCESSING: + { + Eina_Simple_XML_Node_Data *processing = _data_value_set + (node, data.processing, value_str); + EINA_SAFETY_ON_NULL_GOTO(processing, on_error); + break; + } + } + + if (data.type != EFLAT_XML_MODEL_PATH_TYPE_RAW_XML) + { + // TODO: Check if the property exists instead of deleting it + _property_del(pd, property); + _property_add(pd, property, value_str); + } + + free(value_str); + + efl_model_property_changed_notify(obj, property); + + return pd->load.status; + +on_error: + free(value_str); + return EFL_MODEL_LOAD_STATUS_ERROR; +} + +static Efl_Model_Load_Status +_eflat_xml_model_efl_model_base_property_get(Eo *obj EINA_UNUSED, + Eflat_Xml_Model_Data *pd, + const char *property, + const Eina_Value **value) +{ + EINA_SAFETY_ON_NULL_RETURN_VAL(property, EFL_MODEL_LOAD_STATUS_ERROR); + EINA_SAFETY_ON_NULL_RETURN_VAL(value, EFL_MODEL_LOAD_STATUS_ERROR); + DBG("(%p): property=%s", obj, property); + + if (!(pd->load.status & EFL_MODEL_LOAD_STATUS_LOADED_PROPERTIES)) + return EFL_MODEL_LOAD_STATUS_ERROR; + + Eflat_Xml_Model_Path_Data data; + Eina_Simple_XML_Node_Tag *node = _node_from_path_get(pd->root, + property, + &data); + if (!node) + { + ERR("Property doesn't exists: %s", property); + return EFL_MODEL_LOAD_STATUS_ERROR; + }; + + if (data.type == EFLAT_XML_MODEL_PATH_TYPE_RAW_XML) + { + Eina_Strbuf *buf = eina_strbuf_new(); + EINA_SAFETY_ON_NULL_RETURN_VAL(buf, EFL_MODEL_LOAD_STATUS_ERROR); + + Eina_Simple_XML_Node *child; + EINA_INLIST_FOREACH(node->children, child) + { + char *dump = eina_simple_xml_node_dump(child, " "); + Eina_Bool ret = eina_strbuf_append(buf, dump); + free(dump); + EINA_SAFETY_ON_FALSE_RETURN_VAL(ret, EFL_MODEL_LOAD_STATUS_ERROR); + } + + Eina_Bool ret = eina_value_set(&pd->xml_value, eina_strbuf_string_get(buf)); + eina_strbuf_free(buf); + EINA_SAFETY_ON_FALSE_RETURN_VAL(ret, EFL_MODEL_LOAD_STATUS_ERROR); + + *value = &pd->xml_value; + return pd->load.status; + } + + *value = eina_hash_find(pd->properties_hash, property); + if (!(*value)) + { + ERR("Property doesn't exist: %s", property); + return EFL_MODEL_LOAD_STATUS_ERROR; + } + + return pd->load.status; +} + +static void +_eflat_xml_model_efl_model_base_load(Eo *obj, Eflat_Xml_Model_Data *pd) +{ + DBG("(%p)", obj); + + if ((pd->load.status & EFL_MODEL_LOAD_STATUS_LOADED) == EFL_MODEL_LOAD_STATUS_LOADED) + return; + + if (!_init(pd)) + return; + + if (!(pd->load.status & EFL_MODEL_LOAD_STATUS_LOADED_PROPERTIES)) + { + efl_model_load_set(obj, &pd->load, EFL_MODEL_LOAD_STATUS_LOADING_PROPERTIES); + _properties_load(pd); + } + + if (!(pd->load.status & EFL_MODEL_LOAD_STATUS_LOADED_CHILDREN)) + { + efl_model_load_set(obj, &pd->load, EFL_MODEL_LOAD_STATUS_LOADING_CHILDREN); + _children_load(pd); + } + + efl_model_load_set(obj, &pd->load, EFL_MODEL_LOAD_STATUS_LOADED); +} + +static Efl_Model_Load_Status +_eflat_xml_model_efl_model_base_load_status_get(Eo *obj EINA_UNUSED, + Eflat_Xml_Model_Data *pd) +{ + DBG("(%p)", obj); + return pd->load.status; +} + +static void +_eflat_xml_model_efl_model_base_unload(Eo *obj, Eflat_Xml_Model_Data *pd) +{ + DBG("(%p)", obj); + + _clear(pd); + + efl_model_load_set(obj, &pd->load, EFL_MODEL_LOAD_STATUS_UNLOADED); +} + +Eo * +_eflat_xml_model_efl_model_base_child_add(Eo *obj EINA_UNUSED, + Eflat_Xml_Model_Data *pd EINA_UNUSED) +{ + DBG("(%p)", obj); + return NULL; +} + +static Efl_Model_Load_Status +_eflat_xml_model_efl_model_base_child_del(Eo *obj EINA_UNUSED, + Eflat_Xml_Model_Data *pd EINA_UNUSED, + Eo *child EINA_UNUSED) +{ + DBG("(%p)", obj); + return EFL_MODEL_LOAD_STATUS_ERROR; +} + +static Efl_Model_Load_Status +_eflat_xml_model_efl_model_base_children_slice_get(Eo *obj EINA_UNUSED, + Eflat_Xml_Model_Data *pd, + unsigned start EINA_UNUSED, + unsigned count EINA_UNUSED, + Eina_Accessor **children_accessor) +{ + DBG("(%p)", obj); + *children_accessor = NULL; + return pd->load.status; +} + +static Efl_Model_Load_Status +_eflat_xml_model_efl_model_base_children_count_get(Eo *obj EINA_UNUSED, + Eflat_Xml_Model_Data *pd, + unsigned *children_count) +{ + DBG("(%p)", obj); + *children_count = 0; + return pd->load.status; +} + +static void +_eflat_xml_model_efl_model_base_children_load(Eo *obj, Eflat_Xml_Model_Data *pd) +{ + DBG("(%p)", obj); + + if (pd->load.status & EFL_MODEL_LOAD_STATUS_LOADED_CHILDREN) + return; + + if (!_init(pd)) + return; + + efl_model_load_set(obj, &pd->load, EFL_MODEL_LOAD_STATUS_LOADING_CHILDREN); + + _children_load(pd); + + efl_model_load_set(obj, &pd->load, EFL_MODEL_LOAD_STATUS_LOADED_CHILDREN); +} + +static void +_children_load(Eflat_Xml_Model_Data *pd) +{ + DBG("(%p)", pd->obj); +} + +static bool +_init(Eflat_Xml_Model_Data *pd) +{ + if (!pd->root) + pd->root = eina_simple_xml_node_load(pd->xml, strlen(pd->xml), EINA_TRUE); + return true; +} + +static void +_clear(Eflat_Xml_Model_Data *pd) +{ + EINA_SAFETY_ON_NULL_RETURN(pd); + + eina_hash_free_buckets(pd->properties_hash); + + if (pd->properties_array) + { + size_t i; + char *property; + Eina_Array_Iterator it; + EINA_ARRAY_ITER_NEXT(pd->properties_array, i, property, it) + free(property); + eina_array_free(pd->properties_array); + pd->properties_array = NULL; + } + + eina_simple_xml_node_root_free(pd->root); + pd->root = NULL; + + free(pd->xml); + pd->xml = strdup(""); + eina_value_set(&pd->xml_value, ""); +} + +static void +_properties_setup(Eflat_Xml_Model_Data *pd) +{ + DBG("(%p)", pd->obj); + + pd->properties_array = eina_array_new(1); +} + +static Eina_Simple_XML_Node_Tag * +_tag_find(Eina_Simple_XML_Node_Tag *node, const char *name) +{ + if (!node) return NULL; + + Eina_Simple_XML_Node *child; + EINA_INLIST_FOREACH(node->children, child) + { + if (EINA_SIMPLE_XML_NODE_TAG == child->type) + { + Eina_Simple_XML_Node_Tag *tag = (Eina_Simple_XML_Node_Tag*)child; + if (strcmp(name, tag->name) == 0) + return tag; + } + } + + return NULL; +} + +static bool +_space_is(char c) +{ + return '\x20' == c || '\x9' == c || '\xD' == c || '\xA' == c; +} + +static char * +_data_name_get(const Eina_Simple_XML_Node_Data *data) +{ + if (!data) return NULL; + + size_t name_length = data->length; + + const char *separator = NULL; + const char *pos = data->data; + const char *end = pos + name_length; + while (pos < end) + { + if (_space_is(*pos)) + { + separator = pos; + break; + } + ++pos; + } + if (separator) + name_length = (size_t)(ptrdiff_t)(separator - data->data); + + char *name = malloc(name_length + 1); + strncpy(name, data->data, name_length); + name[name_length] = '\0'; + return name; +} + +static Eina_Simple_XML_Node_Data * +_eflat_xml_model_data_find(Eina_Simple_XML_Node_Tag *node, + const char *name, + Eina_Simple_XML_Node_Type type) +{ + if (!node) return NULL; + + const size_t name_length = strlen(name); + + Eina_Simple_XML_Node *child; + EINA_INLIST_FOREACH(node->children, child) + { + if (type != child->type) + continue; + + Eina_Simple_XML_Node_Data *data = (Eina_Simple_XML_Node_Data*)child; + if (name_length > data->length) + continue; + + if (strncmp(data->data, name, name_length) != 0) + continue; + + if ((data->length > name_length) && !_space_is(data->data[name_length])) + continue; + + return data; + } + + return NULL; +} + +static Eina_Simple_XML_Attribute * +_attribute_find(Eina_Simple_XML_Node_Tag *node, const char *key) +{ + if (!node) return NULL; + + Eina_Simple_XML_Attribute *attr; + EINA_INLIST_FOREACH(node->attributes, attr) + { + if (strcmp(key, attr->key) == 0) + return attr; + } + + return NULL; +} + +static Eina_Simple_XML_Node_Tag * +_node_new(Eina_Simple_XML_Node_Tag *parent, const char *name) +{ + EINA_SAFETY_ON_NULL_RETURN_VAL(parent, NULL); + Eina_Simple_XML_Node_Tag *child = _tag_find(parent, name); + if (!child) + child = eina_simple_xml_node_tag_new(parent, name); + + return child; +} + +static Eina_Simple_XML_Attribute * +_attr_new(Eina_Simple_XML_Node_Tag *parent, const char *key) +{ + EINA_SAFETY_ON_NULL_RETURN_VAL(parent, NULL); + Eina_Simple_XML_Attribute *attr = _attribute_find(parent, key); + if (!attr) + attr = eina_simple_xml_attribute_new(parent, key, ""); + + return attr; +} + +static Eina_Simple_XML_Node_Data * +_data_new(Eina_Simple_XML_Node_Tag *parent, + const char *name, + Eina_Simple_XML_Node_Type type) +{ + EINA_SAFETY_ON_NULL_RETURN_VAL(parent, NULL); + Eina_Simple_XML_Node_Data *data = _eflat_xml_model_data_find(parent, name, type); + if (data) + return data; + + switch (type) + { + case EINA_SIMPLE_XML_NODE_PROCESSING: + return eina_simple_xml_node_processing_new(parent, name, strlen(name)); + default: + ERR("Node type not supported: %d", type); + return NULL; + } +} + +static const char * +_next_node_name(char **it, char c) +{ + char *separator = strchr(*it, c); + if (!separator) return NULL; + + *separator = '\0'; + char *node_name = *it; + *it = separator + 1; + return node_name; +} + +typedef struct +{ + Eina_Simple_XML_Node_Tag *(*node_find)(Eina_Simple_XML_Node_Tag *, const char *); + Eina_Simple_XML_Attribute *(*attr_find)(Eina_Simple_XML_Node_Tag *, const char *); + Eina_Simple_XML_Node_Data *(*data_find)(Eina_Simple_XML_Node_Tag *, const char *, Eina_Simple_XML_Node_Type); +} Eflat_Xml_Model_Path_Operators; + +static const Eflat_Xml_Model_Path_Operators +_const_path_operators = { + .node_find = _tag_find, + .attr_find = _attribute_find, + .data_find = _eflat_xml_model_data_find, +}; + +static const Eflat_Xml_Model_Path_Operators +_new_path_operators = { + .node_find = _node_new, + .attr_find = _attr_new, + .data_find = _data_new, +}; + +static Eina_Simple_XML_Node_Tag * +_node_path(Eina_Simple_XML_Node_Root *root, + const char *path, + Eflat_Xml_Model_Path_Data *data, + Eflat_Xml_Model_Path_Operators ops) +{ + EINA_SAFETY_ON_NULL_RETURN_VAL(root, NULL); + EINA_SAFETY_ON_NULL_RETURN_VAL(data, NULL); + + *data = (Eflat_Xml_Model_Path_Data){0}; + Eina_Simple_XML_Node_Tag *node = (Eina_Simple_XML_Node_Tag*)root; + + char *path_tmp = strdup(path); + char *it = path_tmp; + + const char *node_name; + while ((node_name = _next_node_name(&it, '/'))) + { + if (strlen(node_name)) + { + node = ops.node_find(node, node_name); + if (!node) goto on_error; + } + } + + if ((node_name = _next_node_name(&it, '@'))) + { + if (!strlen(node_name)) goto on_error; // attribute cannot be assigned to root + + node = ops.node_find(node, node_name); + if (!node) goto on_error; + + char *attr_key = it; + if (strlen(attr_key) == 0) + { + ERR("Attributes cannot have null key: %s", path); + goto on_error; + } + + data->attribute = ops.attr_find(node, attr_key); + if (!data->attribute) goto on_error; + data->type = EFLAT_XML_MODEL_PATH_TYPE_ATTRIBUTE; + } + else + if ((node_name = _next_node_name(&it, '?'))) + { + if (strlen(node_name)) + { + node = ops.node_find(node, node_name); + if (!node) goto on_error; + } + + char *processing_key = it; + if (strlen(processing_key) == 0) + { + ERR("Processing tags cannot have null name: %s", path); + goto on_error; + } + + data->processing = (Eina_Simple_XML_Node_Processing*) + ops.data_find(node, processing_key, EINA_SIMPLE_XML_NODE_PROCESSING); + if (!data->processing) goto on_error; + data->type = EFLAT_XML_MODEL_PATH_TYPE_PROCESSING; + } + else + { + node_name = it; + if (strlen(node_name) == 0) // terminating with '/' + data->type = EFLAT_XML_MODEL_PATH_TYPE_RAW_XML; + else + { + node = ops.node_find(node, node_name); + if (!node) goto on_error; + data->type = EFLAT_XML_MODEL_PATH_TYPE_DATA; + } + } + + free(path_tmp); + return node; + +on_error: + free(path_tmp); + return NULL; +} + +static Eina_Simple_XML_Node_Tag * +_node_from_path_new(Eina_Simple_XML_Node_Root *root, + const char *path, + Eflat_Xml_Model_Path_Data *data) +{ + return _node_path(root, path, data, _new_path_operators); +} + +static Eina_Simple_XML_Node_Tag * +_node_from_path_get(Eina_Simple_XML_Node_Root *root, + const char *path, + Eflat_Xml_Model_Path_Data *data) +{ + return _node_path(root, path, data, _const_path_operators); +} + +static void +_node_children_del(Eina_Simple_XML_Node_Tag *tag) +{ + while (tag->children) + { + Eina_Simple_XML_Node *node = EINA_INLIST_CONTAINER_GET(tag->children, + Eina_Simple_XML_Node); + if (EINA_SIMPLE_XML_NODE_TAG == node->type) + eina_simple_xml_node_tag_free((Eina_Simple_XML_Node_Tag*)node); + else + eina_simple_xml_node_data_free((Eina_Simple_XML_Node_Data*)node); + } +} + +static char * +_path_from_node_get(Eina_Simple_XML_Node_Tag *tag) +{ + EINA_SAFETY_ON_NULL_RETURN_VAL(tag, NULL); + + Eina_Strbuf *buf = eina_strbuf_new(); + EINA_SAFETY_ON_NULL_RETURN_VAL(buf, NULL); + + Eina_Bool ret = eina_strbuf_append(buf, tag->name ? tag->name : ""); + EINA_SAFETY_ON_FALSE_GOTO(ret, on_error); + + Eina_Simple_XML_Node_Tag *parent = tag; + while ((parent = parent->base.parent) && parent->name) + { + ret = eina_strbuf_prepend(buf, "/") + && eina_strbuf_prepend(buf, parent->name); + EINA_SAFETY_ON_FALSE_GOTO(ret, on_error); + } + + char *result = eina_strbuf_string_steal(buf); + eina_strbuf_free(buf); + return result; + +on_error: + eina_strbuf_free(buf); + return NULL; +} + +static char * +_concatenate_path(const char *path, const char *child, char separator) +{ + int len = strlen(path) + sizeof(separator) + strlen(child) + 1; + + char *child_path = malloc(len); + EINA_SAFETY_ON_NULL_RETURN_VAL(child_path, NULL); + + int written = snprintf(child_path, len, "%s%c%s", path, separator, child); + EINA_SAFETY_ON_FALSE_GOTO((written > 0) && (written < len), on_error); + + return child_path; + +on_error: + free(child_path); + return NULL; +} + +static void +_node_children_properties_del(Eflat_Xml_Model_Data *pd, + Eina_Simple_XML_Node_Tag *tag, + const char *path) +{ + DBG("(%p)", pd->obj); + Eina_Simple_XML_Node *child; + EINA_INLIST_FOREACH(tag->children, child) + { + switch (child->type) + { + case EINA_SIMPLE_XML_NODE_TAG: + { + Eina_Simple_XML_Node_Tag *child_tag = (Eina_Simple_XML_Node_Tag*)child; + + char *child_path = _concatenate_path(path, child_tag->name, '/'); + EINA_SAFETY_ON_NULL_RETURN(child_path); + + _property_del(pd, child_path); + _node_children_properties_del(pd, child_tag, child_path); + _node_attributes_properties_del(pd, child_tag, child_path); + + free(child_path); + break; + } + default: + break; + } + } +} + +static void +_node_attributes_properties_del(Eflat_Xml_Model_Data *pd, + Eina_Simple_XML_Node_Tag *tag, + const char *path) +{ + Eina_Simple_XML_Attribute *attr; + EINA_INLIST_FOREACH(tag->attributes, attr) + { + char *attr_path = _concatenate_path(path, attr->key, '@'); + _property_del(pd, attr_path); + free(attr_path); + } +} + +static Eina_Bool +_property_array_keep_cb(void *data, void *gdata) +{ + char *a = (char *)data; + const char *b = (char *)gdata; + + if (strcmp(a, b) != 0) return EINA_TRUE; + + free(a); + return EINA_FALSE; +} + +static void +_property_del(Eflat_Xml_Model_Data *pd, const char *property) +{ + DBG("(%p) deleting property %s", pd->obj, property); + eina_hash_del(pd->properties_hash, property, NULL); + + eina_array_remove(pd->properties_array, + _property_array_keep_cb, + (void*)property); +} + +static void +_property_add(Eflat_Xml_Model_Data *pd, const char *property, const char *value) +{ + EINA_SAFETY_ON_NULL_RETURN(property); + EINA_SAFETY_ON_NULL_RETURN(value); + + DBG("(%p) adding property %s=%s", pd->obj, property, value); + + char *property_copy = strdup(property); + EINA_SAFETY_ON_NULL_RETURN(property_copy); + + Eina_Bool ret = eina_array_push(pd->properties_array, property_copy); + EINA_SAFETY_ON_FALSE_RETURN(ret); + + Eina_Value *prop_value = eina_hash_find(pd->properties_hash, property); + if (!prop_value) + { + prop_value = eina_value_new(EINA_VALUE_TYPE_STRING); + EINA_SAFETY_ON_NULL_RETURN(prop_value); + + ret = eina_hash_add(pd->properties_hash, property, prop_value); + EINA_SAFETY_ON_FALSE_RETURN(ret); + } + + ret = eina_value_set(prop_value, value); + EINA_SAFETY_ON_FALSE_RETURN(ret); +} + +static void +_node_clear(Eflat_Xml_Model_Data *pd, Eina_Simple_XML_Node_Tag *node) +{ + DBG("(%p)", pd->obj); + EINA_SAFETY_ON_NULL_RETURN(node); + char *path = _path_from_node_get(node); + EINA_SAFETY_ON_NULL_RETURN(path); + + DBG("(%p)", pd->obj); + _node_children_properties_del(pd, node, path); + free(path); + + _node_children_del(node); +} + +static void +_generate_properties_from_node(Eflat_Xml_Model_Data *pd, + Eina_Simple_XML_Node_Tag *node) +{ + char *path = _path_from_node_get(node); + + Eina_Simple_XML_Attribute *attr; + EINA_INLIST_FOREACH(node->attributes, attr) + { + char *attr_path = _concatenate_path(path, attr->key, '@'); + _property_add(pd, attr_path, attr->value); + free(attr_path); + } + + size_t lines_count = 0; + Eina_Strbuf *buf = eina_strbuf_new(); + + Eina_Simple_XML_Node *child; + EINA_INLIST_FOREACH(node->children, child) + { + switch (child->type) + { + case EINA_SIMPLE_XML_NODE_TAG: + _generate_properties_from_node(pd, (Eina_Simple_XML_Node_Tag*)child); + break; + case EINA_SIMPLE_XML_NODE_DATA: + { + Eina_Simple_XML_Node_Data *data = (Eina_Simple_XML_Node_Data*)child; + if (!data->length) break; + eina_strbuf_append_length(buf, data->data, data->length); + if (lines_count > 0) + eina_strbuf_append(buf, "\n"); + ++lines_count; + break; + } + case EINA_SIMPLE_XML_NODE_PROCESSING: + { + const Eina_Simple_XML_Node_Processing *data = (Eina_Simple_XML_Node_Processing*)child; + + char *name = _data_name_get(data); + char *processing_path = _concatenate_path(path, name, '?'); + + size_t name_length = strlen(name); + if (data->length == name_length) + _property_add(pd, processing_path, ""); + else + _property_add(pd, processing_path, data->data + name_length + 1); + + free(processing_path); + free(name); + break; + } + default: + ERR("Node type not supported: %d", child->type); + break; + } + } + + if (lines_count) + _property_add(pd, path, eina_strbuf_string_get(buf)); + + eina_strbuf_free(buf); + free(path); +} + +static Eina_Simple_XML_Node_Data * +_data_value_set(Eina_Simple_XML_Node_Tag *node, + Eina_Simple_XML_Node_Data *data, + const char *value) +{ + Eina_Strbuf *buf = eina_strbuf_new(); + EINA_SAFETY_ON_NULL_RETURN_VAL(buf, NULL); + + char *name = _data_name_get(data); + EINA_SAFETY_ON_NULL_GOTO(name, on_error_1); + + Eina_Bool ret = eina_strbuf_append_printf(buf, "%s %s", name, value); + EINA_SAFETY_ON_FALSE_GOTO(ret, on_error_2); + + Eina_Simple_XML_Node_Data *processing = eina_simple_xml_node_processing_new + (node, eina_strbuf_string_get(buf), eina_strbuf_length_get(buf)); + + eina_simple_xml_node_processing_free(data); + free(name); + eina_strbuf_free(buf); + return processing; + +on_error_2: + free(name); +on_error_1: + eina_strbuf_free(buf); + return NULL; +} + +static void +_stream_load(Eflat_Xml_Model_Data *pd, + Eina_Simple_XML_Node_Tag *node, + const char *xml) +{ + _node_clear(pd, node); + + Eina_Simple_XML_Node_Root *root = eina_simple_xml_node_load(xml, + strlen(xml), + EINA_TRUE); + // steals root items + Eina_Simple_XML_Node *child; + EINA_INLIST_FOREACH(root->children, child) + child->parent = node; + node->children = root->children; + root->children = NULL; + + Eina_Simple_XML_Attribute *attr; + EINA_INLIST_FOREACH(root->attributes, attr) + attr->parent = node; + node->attributes = root->attributes; + root->attributes = NULL; + + eina_simple_xml_node_root_free(root); + + _generate_properties_from_node(pd, node); +} + +#include "eflat_xml_model.eo.c" diff --git a/src/lib/eflat_xml_model/eflat_xml_model.eo b/src/lib/eflat_xml_model/eflat_xml_model.eo new file mode 100644 index 0000000000..6cf9eebc7e --- /dev/null +++ b/src/lib/eflat_xml_model/eflat_xml_model.eo @@ -0,0 +1,34 @@ +class Eflat_Xml.Model (Eo.Base, Efl.Model.Base) { + legacy_prefix: null; + methods { + constructor { + [[Custom Eflat_Xml_Model constructor. + @.constructor + + @since 1.13 + ]] + params { + xml: const(char)*; [[The XML document]] + } + } + } + implements { + Eo.Base.constructor; + Eo.Base.destructor; + Efl.Model.Base.properties.get; + Efl.Model.Base.properties_load; + Efl.Model.Base.property.set; + Efl.Model.Base.property.get; + Efl.Model.Base.load; + Efl.Model.Base.load_status.get; + Efl.Model.Base.unload; + Efl.Model.Base.child_add; + Efl.Model.Base.child_del; + Efl.Model.Base.children_slice.get; + Efl.Model.Base.children_count.get; + Efl.Model.Base.children_load; + } + constructors { + .constructor; + } +} diff --git a/src/lib/eflat_xml_model/eflat_xml_model_private.h b/src/lib/eflat_xml_model/eflat_xml_model_private.h new file mode 100644 index 0000000000..f27837f5fe --- /dev/null +++ b/src/lib/eflat_xml_model/eflat_xml_model_private.h @@ -0,0 +1,34 @@ +#ifndef _EFLAT_XML_MODEL_PRIVATE_H +#define _EFLAT_XML_MODEL_PRIVATE_H + +#include "Eflat_Xml_Model.h" + +#include <stdbool.h> + +/* logging support */ +extern int _eflat_xml_model_log_dom; + +#define CRI(...) EINA_LOG_DOM_CRIT(_eflat_xml_model_log_dom, __VA_ARGS__) +#define ERR(...) EINA_LOG_DOM_ERR(_eflat_xml_model_log_dom, __VA_ARGS__) +#define WRN(...) EINA_LOG_DOM_WARN(_eflat_xml_model_log_dom, __VA_ARGS__) +#define INF(...) EINA_LOG_DOM_INFO(_eflat_xml_model_log_dom, __VA_ARGS__) +#define DBG(...) EINA_LOG_DOM_DBG(_eflat_xml_model_log_dom, __VA_ARGS__) + +typedef struct _Eflat_Xml_Model_Data Eflat_Xml_Model_Data; + +/** + * eflat_xml_model + */ +struct _Eflat_Xml_Model_Data +{ + Eo *obj; + Efl_Model_Load load; + Eina_Array *properties_array; + Eina_Hash *properties_hash; + Eina_Simple_XML_Node_Root *root; + char *xml; + Eina_Value xml_value; +}; + +#endif + diff --git a/src/tests/eflat_xml_model/eflat_xml_model_suite.c b/src/tests/eflat_xml_model/eflat_xml_model_suite.c new file mode 100644 index 0000000000..185a053c22 --- /dev/null +++ b/src/tests/eflat_xml_model/eflat_xml_model_suite.c @@ -0,0 +1,121 @@ +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include "eflat_xml_model_suite.h" + +#include <Eina.h> + +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> + +int _test_eflat_xml_model_log_dom = -1; + +typedef struct _Eflat_Xml_Test_Case Eflat_Xml_Test_Case; + +struct _Eflat_Xml_Test_Case +{ + const char *test_case; + void (*build)(TCase *tc); +}; + +static const Eflat_Xml_Test_Case etc[] = { + { "Eflat_Xml_Model", eflat_xml_test_eflat_xml_model }, + { NULL, NULL } +}; + +static void +_list_tests(void) +{ + const Eflat_Xml_Test_Case *it = etc; + fputs("Available Test Cases:\n", stderr); + for (; it->test_case; it++) + fprintf(stderr, "\t%s\n", it->test_case); +} + +static bool +_use_test(int argc, const char **argv, const char *test_case) +{ + if (argc < 1) + return true; + + for (; argc > 0; argc--, argv++) + if (strcmp(test_case, *argv) == 0) + return true; + return false; +} + +static Suite * +_eflat_xml_suite_build(int argc, const char **argv) +{ + Suite *s = suite_create("Eflat_Xml"); + + for (int i = 0; etc[i].test_case; ++i) + { + if (!_use_test(argc, argv, etc[i].test_case)) continue; + TCase *tc = tcase_create(etc[i].test_case); + + etc[i].build(tc); + + suite_add_tcase(s, tc); + //tcase_set_timeout(tc, 0); + } + + return s; +} + +static void +_init_logging(void) +{ + _test_eflat_xml_model_log_dom = eina_log_domain_register("test_eflat_xml_model", EINA_COLOR_LIGHTBLUE); + if (_test_eflat_xml_model_log_dom < 0) + ck_abort_msg("Could not register log domain: test_eflat_xml_model"); + + //eina_log_domain_level_set("esskyuehl", EINA_LOG_LEVEL_DBG); + //eina_log_domain_level_set("eflat_xml_model", EINA_LOG_LEVEL_DBG); + eina_log_domain_level_set("test_eflat_xml_model", EINA_LOG_LEVEL_DBG); +} + +static void +_shutdown_logging(void) +{ + eina_log_domain_unregister(_test_eflat_xml_model_log_dom); + _test_eflat_xml_model_log_dom = -1; +} + +int +main(int argc, char **argv) +{ + for (int i = 1; i < argc; ++i) + { + if ((strcmp(argv[i], "-h") == 0) || + (strcmp(argv[i], "--help") == 0)) + { + fprintf(stderr, "Usage:\n\t%s [test_case1 .. [test_caseN]]\n", argv[0]); + _list_tests(); + return 0; + } + else if ((strcmp(argv[i], "-l") == 0) || + (strcmp(argv[i], "--list") == 0)) + { + _list_tests(); + return 0; + } + } + + _init_logging(); + + Suite *s = _eflat_xml_suite_build(argc - 1, (const char **)argv + 1); + SRunner *sr = srunner_create(s); + + srunner_set_xml(sr, TESTS_BUILD_DIR "/check-results.xml"); + + srunner_run_all(sr, CK_ENV); + int failed_count = srunner_ntests_failed(sr); + srunner_free(sr); + + _shutdown_logging(); + + return (failed_count == 0) ? EXIT_SUCCESS : EXIT_FAILURE; +} diff --git a/src/tests/eflat_xml_model/eflat_xml_model_suite.h b/src/tests/eflat_xml_model/eflat_xml_model_suite.h new file mode 100644 index 0000000000..d90a2c5a6d --- /dev/null +++ b/src/tests/eflat_xml_model/eflat_xml_model_suite.h @@ -0,0 +1,16 @@ +#ifndef _EFLAT_XML_SUITE_H +#define _EFLAT_XML_SUITE_H + +#include <check.h> + +extern int _test_eflat_xml_model_log_dom; + +#define CRI(...) EINA_LOG_DOM_CRIT(_test_eflat_xml_model_log_dom, __VA_ARGS__) +#define ERR(...) EINA_LOG_DOM_ERR(_test_eflat_xml_model_log_dom, __VA_ARGS__) +#define WRN(...) EINA_LOG_DOM_WARN(_test_eflat_xml_model_log_dom, __VA_ARGS__) +#define INF(...) EINA_LOG_DOM_INFO(_test_eflat_xml_model_log_dom, __VA_ARGS__) +#define DBG(...) EINA_LOG_DOM_DBG(_test_eflat_xml_model_log_dom, __VA_ARGS__) + +void eflat_xml_test_eflat_xml_model(TCase *tc); + +#endif diff --git a/src/tests/eflat_xml_model/eflat_xml_model_test_eflat_xml_model.c b/src/tests/eflat_xml_model/eflat_xml_model_test_eflat_xml_model.c new file mode 100644 index 0000000000..2e05f1a511 --- /dev/null +++ b/src/tests/eflat_xml_model/eflat_xml_model_test_eflat_xml_model.c @@ -0,0 +1,503 @@ +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include "eflat_xml_model_test_eflat_xml_model.h" +#include "eflat_xml_model_suite.h" + +#include <Ecore.h> +#include <Eina.h> +#include <Eflat_Xml_Model.h> + +#include <stdbool.h> + +static void +_setup(void) +{ + int ret = eflat_xml_model_init(); + ck_assert_int_ge(ret, 1); +} + +static void +_teardown(void) +{ + int ret = eflat_xml_model_shutdown(); + ck_assert_int_eq(ret, 0); +} + +static Eina_Bool +_eo_event_load_status_cb(void *data, + Eo *obj EINA_UNUSED, + const Eo_Event_Description *desc EINA_UNUSED, + void *event_info EINA_UNUSED) +{ + Efl_Model_Load_Status expected_status = *((Efl_Model_Load_Status*)data); + Efl_Model_Load load = *((Efl_Model_Load*)event_info); + if ((load.status & expected_status) != expected_status) + return EINA_TRUE; + + ecore_main_loop_quit(); + return EINA_FALSE; +} + +static void +_wait_until_load_status(Efl_Model_Base *emodel, + Efl_Model_Load_Status expected_status) +{ + Efl_Model_Load_Status actual_status; + eo_do(emodel, actual_status = efl_model_load_status_get()); + if (expected_status == actual_status) return; + + eo_do(emodel, eo_event_callback_add(EFL_MODEL_BASE_EVENT_LOAD_STATUS, + _eo_event_load_status_cb, + &expected_status)); + ecore_main_loop_begin(); + eo_do(emodel, eo_event_callback_del(EFL_MODEL_BASE_EVENT_LOAD_STATUS, + _eo_event_load_status_cb, + &expected_status)); +} + +static void +_check_efl_model_property_str_eq(Efl_Model_Base *emodel, + const char *property, + const char *expected_value) +{ + const Eina_Value *value; + Efl_Model_Load_Status status; + eo_do(emodel, status = efl_model_property_get(property, &value)); + ck_assert_int_eq(EFL_MODEL_LOAD_STATUS_LOADED, status); + ck_assert_ptr_ne(NULL, value); + + const Eina_Value_Type *property_type = eina_value_type_get(value); + fail_if(EINA_VALUE_TYPE_STRING != property_type && + EINA_VALUE_TYPE_STRINGSHARE != property_type); + + const char *actual_value = NULL; + eina_value_get(value, &actual_value); + ck_assert_str_eq(expected_value, actual_value); +} + +static void +_check_efl_model_load(Efl_Model_Base *model) +{ + eo_do(model, efl_model_load()); + _wait_until_load_status(model, EFL_MODEL_LOAD_STATUS_LOADED); +} + +static void +_check_efl_model_properties(Efl_Model_Base *model, + const char *expected_properties[]) +{ + Eina_Array *properties = NULL; + Efl_Model_Load_Status status; + eo_do(model, status = efl_model_properties_get(&properties)); + ck_assert_int_eq(EFL_MODEL_LOAD_STATUS_LOADED, status); + ck_assert_ptr_ne(NULL, properties); + + unsigned int actual_properties_count = eina_array_count(properties); + + unsigned int expected_properties_count = 0; + const char *expected_property = NULL; + while ((expected_property = *expected_properties++)) + { + const char *actual_property = eina_array_data_get(properties, + expected_properties_count); + ck_assert_str_eq(expected_property, actual_property); + ++expected_properties_count; + ck_assert_int_le(expected_properties_count, actual_properties_count); + } + + ck_assert_int_eq(expected_properties_count, actual_properties_count); +} + +static Eflat_Xml_Model * +_create_flat_xml_model(void) +{ + Efl_Model_Base *xml_model = eo_add(EFLAT_XML_MODEL_CLASS, + NULL, + eflat_xml_model_constructor(NULL)); + ck_assert_ptr_ne(NULL, xml_model); + return xml_model; +} + +START_TEST(smoke) +{ + Efl_Model_Base *xml_model = _create_flat_xml_model(); + eo_unref(xml_model); +} +END_TEST + +static void +_check_string_property_set(Efl_Model_Base *model, + const char *property, + const char *v) +{ + Eina_Value value; + eina_value_setup(&value, EINA_VALUE_TYPE_STRING); + eina_value_set(&value, v); + Efl_Model_Load_Status status; + eo_do(model, status = efl_model_property_set(property, &value)); + eina_value_flush(&value); + ck_assert_int_eq(EFL_MODEL_LOAD_STATUS_LOADED, status); +} + +static void +_check_xml_string(Efl_Model_Base *model, const char *expected_xml_string) +{ + _check_efl_model_property_str_eq(model, "/", expected_xml_string); +} + +static const char *SAMPLE_XML = + "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n" + "<soap:Envelope xmlns:soap=\"http://www.w3.org/2001/12/soap-envelope\" soap:encodingStyle=\"http://www.w3.org/2001/12/soap-encoding\">\n" + " <soap:Header>\n" + " <m:Trans xmlns:m=\"http://my.namespace/header\" soap:mustUnderstand=\"1\">\n" + " 1234\n" + " </m:Trans>\n" + " </soap:Header>\n" + " <soap:Body>\n" + " <m:MethodName xmlns:m=\"http://my.namespece/body\">\n" + " <m:Item>\n" + " Value\n" + " </m:Item>\n" + " </m:MethodName>\n" + " </soap:Body>\n" + "</soap:Envelope>\n"; + +static void +_check_sample_xml_properties_names(Efl_Model_Base *xml_model) +{ + _check_efl_model_properties(xml_model, (const char*[]){ + "?xml", + "soap:Envelope@xmlns:soap", + "soap:Envelope@soap:encodingStyle", + "soap:Envelope/soap:Header/m:Trans@xmlns:m", + "soap:Envelope/soap:Header/m:Trans@soap:mustUnderstand", + "soap:Envelope/soap:Header/m:Trans", + "soap:Envelope/soap:Body/m:MethodName@xmlns:m", + "soap:Envelope/soap:Body/m:MethodName/m:Item", + NULL}); +} + +static void +_check_sample_xml_properties_values(Efl_Model_Base *xml_model) +{ + _check_efl_model_property_str_eq(xml_model, "?xml", "version=\"1.0\" encoding=\"UTF-8\""); + _check_efl_model_property_str_eq(xml_model, "soap:Envelope@xmlns:soap", "http://www.w3.org/2001/12/soap-envelope"); + _check_efl_model_property_str_eq(xml_model, "soap:Envelope@soap:encodingStyle", "http://www.w3.org/2001/12/soap-encoding"); + _check_efl_model_property_str_eq(xml_model, "soap:Envelope/soap:Header/m:Trans@xmlns:m", "http://my.namespace/header"); + _check_efl_model_property_str_eq(xml_model, "soap:Envelope/soap:Header/m:Trans@soap:mustUnderstand", "1"); + _check_efl_model_property_str_eq(xml_model, "soap:Envelope/soap:Header/m:Trans", "1234"); + _check_efl_model_property_str_eq(xml_model, "soap:Envelope/soap:Body/m:MethodName@xmlns:m", "http://my.namespece/body"); + _check_efl_model_property_str_eq(xml_model, "soap:Envelope/soap:Body/m:MethodName/m:Item", "Value"); +} + +static void +_check_property_set(Efl_Model_Base *xml_model) +{ + _check_string_property_set(xml_model, "?xml", "version=\"1.0\" encoding=\"UTF-8\""); + _check_string_property_set(xml_model, "soap:Envelope@xmlns:soap", "http://www.w3.org/2001/12/soap-envelope"); + _check_string_property_set(xml_model, "soap:Envelope@soap:encodingStyle", "http://www.w3.org/2001/12/soap-encoding"); + _check_string_property_set(xml_model, "soap:Envelope/soap:Header/m:Trans@xmlns:m", "http://my.namespace/header"); + _check_string_property_set(xml_model, "soap:Envelope/soap:Header/m:Trans@soap:mustUnderstand", "1"); + _check_string_property_set(xml_model, "soap:Envelope/soap:Header/m:Trans", "1234"); + _check_string_property_set(xml_model, "soap:Envelope/soap:Body/m:MethodName@xmlns:m", "http://my.namespece/body"); + _check_string_property_set(xml_model, "soap:Envelope/soap:Body/m:MethodName/m:Item", "Value"); + + _check_xml_string(xml_model, SAMPLE_XML); + + _check_sample_xml_properties_names(xml_model); + + _check_efl_model_property_str_eq(xml_model, "?xml", "version=\"1.0\" encoding=\"UTF-8\""); +} + +START_TEST(property_set_basic) +{ + Efl_Model_Base *xml_model = _create_flat_xml_model(); + + _check_efl_model_load(xml_model); + + _check_property_set(xml_model); + + eo_unref(xml_model); +} +END_TEST + +static void +_check_property_not_exists(Efl_Model_Base *model, const char *property) +{ + const Eina_Value *value; + Efl_Model_Load_Status status; + eo_do(model, status = efl_model_property_get(property, &value)); + ck_assert_int_eq(EFL_MODEL_LOAD_STATUS_ERROR, status); + + Eina_Array *properties = NULL; + eo_do(model, status = efl_model_properties_get(&properties)); + ck_assert_int_eq(EFL_MODEL_LOAD_STATUS_LOADED, status); + ck_assert_ptr_ne(NULL, properties); + + unsigned int i; + char *item; + Eina_Array_Iterator it; + EINA_ARRAY_ITER_NEXT(properties, i, item, it) + ck_assert_str_ne(property, item); +} + +START_TEST(property_set_existing) +{ + Efl_Model_Base *xml_model = _create_flat_xml_model(); + + _check_efl_model_load(xml_model); + + _check_property_set(xml_model); + + // replaces an attribute + _check_string_property_set(xml_model, "soap:Envelope/soap:Header/m:Trans@xmlns:m", "http://other.namespace/header"); + + _check_efl_model_properties(xml_model, (const char*[]){ + "?xml", + "soap:Envelope@xmlns:soap", + "soap:Envelope@soap:encodingStyle", + "soap:Envelope/soap:Header/m:Trans@soap:mustUnderstand", + "soap:Envelope/soap:Header/m:Trans", + "soap:Envelope/soap:Body/m:MethodName@xmlns:m", + "soap:Envelope/soap:Body/m:MethodName/m:Item", + "soap:Envelope/soap:Header/m:Trans@xmlns:m", + NULL}); + + // replaces a value + _check_string_property_set(xml_model, "soap:Envelope/soap:Header/m:Trans", "4321"); + + _check_efl_model_properties(xml_model, (const char*[]){ + "?xml", + "soap:Envelope@xmlns:soap", + "soap:Envelope@soap:encodingStyle", + "soap:Envelope/soap:Header/m:Trans@soap:mustUnderstand", + "soap:Envelope/soap:Body/m:MethodName@xmlns:m", + "soap:Envelope/soap:Body/m:MethodName/m:Item", + "soap:Envelope/soap:Header/m:Trans@xmlns:m", + "soap:Envelope/soap:Header/m:Trans", + NULL}); + + // clears a value + _check_string_property_set(xml_model, "soap:Envelope/soap:Body/m:MethodName/m:Item", ""); + + _check_xml_string(xml_model, + "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n" + "<soap:Envelope xmlns:soap=\"http://www.w3.org/2001/12/soap-envelope\" soap:encodingStyle=\"http://www.w3.org/2001/12/soap-encoding\">\n" + " <soap:Header>\n" + " <m:Trans xmlns:m=\"http://other.namespace/header\" soap:mustUnderstand=\"1\">\n" + " 4321\n" + " </m:Trans>\n" + " </soap:Header>\n" + " <soap:Body>\n" + " <m:MethodName xmlns:m=\"http://my.namespece/body\">\n" + " <m:Item/>\n" + " </m:MethodName>\n" + " </soap:Body>\n" + "</soap:Envelope>\n" + ); + + _check_efl_model_properties(xml_model, (const char*[]){ + "?xml", + "soap:Envelope@xmlns:soap", + "soap:Envelope@soap:encodingStyle", + "soap:Envelope/soap:Header/m:Trans@soap:mustUnderstand", + "soap:Envelope/soap:Body/m:MethodName@xmlns:m", + "soap:Envelope/soap:Header/m:Trans@xmlns:m", + "soap:Envelope/soap:Header/m:Trans", + "soap:Envelope/soap:Body/m:MethodName/m:Item", + NULL}); + + // clearing a value clears its children too + _check_string_property_set(xml_model, "soap:Envelope/soap:Body", ""); + + _check_property_not_exists(xml_model, "soap:Envelope/soap:Body/m:MethodName/m:Item"); + _check_property_not_exists(xml_model, "soap:Envelope/soap:Body/m:MethodName@xmlns:m"); + + _check_xml_string(xml_model, + "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n" + "<soap:Envelope xmlns:soap=\"http://www.w3.org/2001/12/soap-envelope\" soap:encodingStyle=\"http://www.w3.org/2001/12/soap-encoding\">\n" + " <soap:Header>\n" + " <m:Trans xmlns:m=\"http://other.namespace/header\" soap:mustUnderstand=\"1\">\n" + " 4321\n" + " </m:Trans>\n" + " </soap:Header>\n" + " <soap:Body/>\n" + "</soap:Envelope>\n" + ); + + _check_efl_model_properties(xml_model, (const char*[]){ + "?xml", + "soap:Envelope@xmlns:soap", + "soap:Envelope@soap:encodingStyle", + "soap:Envelope/soap:Header/m:Trans@soap:mustUnderstand", + "soap:Envelope/soap:Header/m:Trans@xmlns:m", + "soap:Envelope/soap:Header/m:Trans", + "soap:Envelope/soap:Body", + NULL}); + + eo_unref(xml_model); +} +END_TEST + +START_TEST(property_set_stream) +{ + Efl_Model_Base *xml_model = _create_flat_xml_model(); + + _check_efl_model_load(xml_model); + + // root level + _check_string_property_set(xml_model, "/", SAMPLE_XML); + _check_sample_xml_properties_names(xml_model); + _check_sample_xml_properties_values(xml_model); + + _check_string_property_set(xml_model, "soap:Envelope/soap:Body/", + " <m:OtherMethod xmlns:m=\"http://my.namespece/body\">\n" + " <m:OtherItem>\n" + " OtherValue\n" + " </m:OtherItem>\n" + " </m:OtherMethod>\n" + ); + + _check_efl_model_properties(xml_model, (const char*[]){ + "?xml", + "soap:Envelope@xmlns:soap", + "soap:Envelope@soap:encodingStyle", + "soap:Envelope/soap:Header/m:Trans@xmlns:m", + "soap:Envelope/soap:Header/m:Trans@soap:mustUnderstand", + "soap:Envelope/soap:Header/m:Trans", + "soap:Envelope/soap:Body/m:OtherMethod@xmlns:m", + "soap:Envelope/soap:Body/m:OtherMethod/m:OtherItem", + NULL}); + + + _check_xml_string(xml_model, + "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n" + "<soap:Envelope xmlns:soap=\"http://www.w3.org/2001/12/soap-envelope\" soap:encodingStyle=\"http://www.w3.org/2001/12/soap-encoding\">\n" + " <soap:Header>\n" + " <m:Trans xmlns:m=\"http://my.namespace/header\" soap:mustUnderstand=\"1\">\n" + " 1234\n" + " </m:Trans>\n" + " </soap:Header>\n" + " <soap:Body>\n" + " <m:OtherMethod xmlns:m=\"http://my.namespece/body\">\n" + " <m:OtherItem>\n" + " OtherValue\n" + " </m:OtherItem>\n" + " </m:OtherMethod>\n" + " </soap:Body>\n" + "</soap:Envelope>\n" + ); + + eo_unref(xml_model); +} +END_TEST + +START_TEST(property_get_stream) +{ + Efl_Model_Base *xml_model = _create_flat_xml_model(); + + _check_efl_model_load(xml_model); + + _check_property_set(xml_model); + + // sublevel + _check_efl_model_property_str_eq(xml_model, "soap:Envelope/", + "<soap:Header>\n" + " <m:Trans xmlns:m=\"http://my.namespace/header\" soap:mustUnderstand=\"1\">\n" + " 1234\n" + " </m:Trans>\n" + "</soap:Header>\n" + "<soap:Body>\n" + " <m:MethodName xmlns:m=\"http://my.namespece/body\">\n" + " <m:Item>\n" + " Value\n" + " </m:Item>\n" + " </m:MethodName>\n" + "</soap:Body>\n" + ); + + // sublevel + _check_efl_model_property_str_eq(xml_model, "soap:Envelope/soap:Header/", + "<m:Trans xmlns:m=\"http://my.namespace/header\" soap:mustUnderstand=\"1\">\n" + " 1234\n" + "</m:Trans>\n" + ); + + // sublevel data + _check_efl_model_property_str_eq(xml_model, "soap:Envelope/soap:Header/m:Trans/", + "1234\n" + ); + + eo_unref(xml_model); +} +END_TEST + +START_TEST(load_status_get) +{ + Efl_Model_Base *xml_model = _create_flat_xml_model(); + + Efl_Model_Load_Status status; + eo_do(xml_model, status = efl_model_load_status_get()); + ck_assert_int_eq(EFL_MODEL_LOAD_STATUS_UNLOADED, status); + + _check_efl_model_load(xml_model); + + eo_do(xml_model, status = efl_model_load_status_get()); + ck_assert_int_eq(EFL_MODEL_LOAD_STATUS_LOADED, status); + + eo_unref(xml_model); +} +END_TEST + +START_TEST(unload) +{ + Efl_Model_Base *xml_model = _create_flat_xml_model(); + + _check_efl_model_load(xml_model); + _check_property_set(xml_model); + + eo_do(xml_model, efl_model_unload()); + + // status must be unloaded now + Efl_Model_Load_Status status; + eo_do(xml_model, status = efl_model_load_status_get()); + ck_assert_int_eq(EFL_MODEL_LOAD_STATUS_UNLOADED, status); + + // reload and manipulate content + _check_efl_model_load(xml_model); + _check_property_set(xml_model); + + eo_unref(xml_model); +} +END_TEST + +START_TEST(xml_load) +{ + Efl_Model_Base *xml_model = eo_add(EFLAT_XML_MODEL_CLASS, + NULL, + eflat_xml_model_constructor(SAMPLE_XML)); + ck_assert_ptr_ne(NULL, xml_model); + + _check_efl_model_load(xml_model); + _check_sample_xml_properties_names(xml_model); + _check_sample_xml_properties_values(xml_model); + + eo_unref(xml_model); +} +END_TEST + +void +eflat_xml_test_eflat_xml_model(TCase *tc) +{ + tcase_add_checked_fixture(tc, _setup, _teardown); + tcase_add_test(tc, smoke); + tcase_add_test(tc, property_set_basic); + tcase_add_test(tc, property_set_existing); + tcase_add_test(tc, property_set_stream); + tcase_add_test(tc, property_get_stream); + tcase_add_test(tc, load_status_get); + tcase_add_test(tc, unload); + tcase_add_test(tc, xml_load); +} diff --git a/src/tests/eflat_xml_model/eflat_xml_model_test_eflat_xml_model.h b/src/tests/eflat_xml_model/eflat_xml_model_test_eflat_xml_model.h new file mode 100644 index 0000000000..b9c836363b --- /dev/null +++ b/src/tests/eflat_xml_model/eflat_xml_model_test_eflat_xml_model.h @@ -0,0 +1,6 @@ +#ifndef _EFLAT_XML_MODEL_TEST_EFLAT_XML_MODEL_H +#define _EFLAT_XML_MODEL_TEST_EFLAT_XML_MODEL_H + +#include <Eflat_Xml_Model.h> + +#endif |