add cmocka based unit testing framework to the build process 52/216252/7
authorMaciej Slodczyk <m.slodczyk2@partner.samsung.com>
Tue, 12 Nov 2019 13:16:41 +0000 (14:16 +0100)
committerMichal Bloch <m.bloch@partner.samsung.com>
Wed, 4 Dec 2019 13:43:16 +0000 (14:43 +0100)
Contains a notifier test as a working example.

Change-Id: I545406edad50763d9687abf4c418c2e6b0f94b0d
Signed-off-by: Maciej Slodczyk <m.slodczyk2@partner.samsung.com>
CMakeLists.txt
packaging/resourced.spec
src/CMakeLists.txt
src/common/macro.h
tests/CMakeLists.txt
tests/cmocka-core.c [new file with mode: 0644]

index 94e406a..3555cdd 100644 (file)
@@ -55,5 +55,6 @@ INSTALL(FILES ${CMAKE_SOURCE_DIR}/resourced.conf DESTINATION /etc/dbus-1/system.
 
 ADD_SUBDIRECTORY(src)
 IF(DEFINED RD_TESTS_PATH)
+  ENABLE_TESTING()
   ADD_SUBDIRECTORY(tests)
 ENDIF(DEFINED RD_TESTS_PATH)
index ea2f1e1..7d9342d 100644 (file)
@@ -43,6 +43,7 @@ BuildRequires:  pkgconfig(libtzplatform-config)
 BuildRequires:  pkgconfig(storage)
 BuildRequires:  pkgconfig(libgum)
 BuildRequires:  pkgconfig(capi-system-device)
+BuildRequires:  pkgconfig(cmocka)
 
 #only for data types
 BuildRequires:  pkgconfig(tapi)
index 4c54ad6..07d0828 100644 (file)
@@ -153,6 +153,30 @@ ADD_EXECUTABLE(${RD_BINARY_NAME}
   ${RESOURCED_SOURCE_DIR}/init.c
   ${RESOURCED_SOURCE_DIR}/main.c
   ${SOURCES})
+
+SET(SAVE_EXTRA_CFLAGS ${EXTRA_CFLAGS})
+SET(SAVE_CMAKE_C_FLAGS ${CMAKE_C_FLAGS})
+SET(SAVE_CMAKE_C_FLAGS_RELEASE ${CMAKE_C_FLAGS_RELEASE})
+SET(EXTRA_CFLAGS "")
+SET(EXTRA_CFLAGS_RELEASE "")
+SET(CMAKE_C_FLAGS "")
+SET(CMAKE_CXX_FLAGS "")
+SET(CMAKE_CXX_FLAGS_RELEASE "")
+SET(CMAKE_C_FLAGS_RELEASE "-D_UNIT_TEST -Wp,-U_FORTIFY_SOURCE -U_FORTIFY_SOURCE -O0 -g")
+ADD_LIBRARY(resourced_shared_test STATIC
+  ${RESOURCED_INCLUDE_HEADERS}
+  ${RESOURCED_SHARED_SOURCES}
+  ${RESOURCED_SHARED_HEADERS}
+  )
+
+SET_TARGET_PROPERTIES(resourced_shared_test
+       PROPERTIES COMPILE_FLAGS ${CMAKE_C_FLAGS_RELEASE})
+TARGET_LINK_LIBRARIES(resourced_shared_test ${RESOURCED_REQUIRE_PKGS_LDFLAGS})
+
+SET(EXTRA_CFLAGS ${SAVE_EXTRA_CFLAGS})
+SET(CMAKE_C_FLAGS ${SAVE_CMAKE_C_FLAGS})
+SET(CMAKE_C_FLAGS_RELEASE ${SAVE_CMAKE_C_FLAGS_RELEASE})
+
 TARGET_LINK_LIBRARIES(${RD_BINARY_NAME}
   resourced-private-api ${RESOURCED_REQUIRE_PKGS_LDFLAGS} "-pie -ldl -lm -Wl,-rpath=${RD_PLUGIN_PATH}")
 SET_TARGET_PROPERTIES(${RD_BINARY_NAME} PROPERTIES COMPILE_FLAGS "-fvisibility=default")
index f67a94d..c8e9a51 100644 (file)
             elem && ((node = elem->data) != NULL);                     \
             elem = elem_next, elem_next = g_slist_next(elem), node = NULL)
 
+#ifndef _UNIT_TEST
 #define MODULE_REGISTER(module)                                                \
        static void __attribute__ ((constructor)) module_init(void)     \
        {                                                               \
        {                                                               \
                remove_module(module);                                  \
        }
+#else
+/* module is declared in all modules as static struct and the resourced
+ * codebase is compiled with -Wall so we need to use 'module' pionter
+ * somehow to prevent from breaking the build process */
+#define MODULE_REGISTER(module)  \
+       static void __attribute__ ((constructor)) placeholder(void)     \
+       {                                                               \
+               ((void)(module));                                       \
+       }
+#endif
 
 /* Overlap definition to consider three strings as a string */
 #define STRING_FORMAT_SPECIFIER_WITH_MACRO(macro) "%"#macro"s"
index f44c951..2576482 100644 (file)
@@ -18,6 +18,34 @@ TARGET_LINK_LIBRARIES(watchdog-test
   "${GLIB2_LDFLAGS}"
   "${GIO2_LDFLAGS}")
 
+# run unit tests autimatically whenever building resourced
+ADD_CUSTOM_TARGET(do-test ALL make test
+  WORKING_DIRECTORY ./
+  USES_TERMINAL)
+
+# build unit test
+ADD_EXECUTABLE(cmocka-core cmocka-core.c)
+
+PKG_CHECK_MODULES(CMOCKA REQUIRED cmocka)
+
+SET(EXTRA_CFLAGS "")
+SET(RESOURCED_REQUIRE_PKGS_LDFLAGS "")
+SET(CMAKE_C_FLAGS "")
+SET(CMAKE_C_FLAGS_RELEASE "")
+SET(CMAKE_LDFLAGS "")
+SET(CMAKE_LDFLAGS_RELEASE "")
+
+SET(UNIT_TESTS_CFLAGS "-O0 -D_UNIT_TEST -D_GNU_SOURCE")
+
+SET_TARGET_PROPERTIES(cmocka-core PROPERTIES COMPILE_FLAGS
+       "-I${COMMON_SOURCE_DIR} -I/usr/include/dlog -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include ${UNIT_TESTS_CFLAGS}")
+TARGET_LINK_LIBRARIES(cmocka-core resourced_shared_test cmocka dlog gio-2.0 gobject-2.0 glib-2.0
+       "-Wl,--wrap=malloc,--wrap=free,--wrap=g_slist_append,--wrap=g_slist_remove,--wrap=strdup,--wrap=strndup -O0")
+
+# add unit test to test target
+ADD_TEST(core cmocka-core)
+ADD_DEPENDENCIES(do-test cmocka-core)
+
 INSTALL(TARGETS watchdog-test
   DESTINATION ${RD_TESTS_PATH})
 INSTALL(FILES run_tests.sh
diff --git a/tests/cmocka-core.c b/tests/cmocka-core.c
new file mode 100644 (file)
index 0000000..0793cae
--- /dev/null
@@ -0,0 +1,146 @@
+#include <stdarg.h>
+#include <setjmp.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <cmocka.h>
+#include <assert.h>
+#include <glib.h>
+#include <errno.h>
+#include <stdbool.h>
+#include "notifier.h"
+#include "config-parser.h"
+
+typedef int (*noti_cb)(void *data);
+
+void *__real_malloc(size_t size);
+void __real_free(void *ptr);
+GSList *__real_g_slist_append(GSList *list, gpointer data);
+GSList *__real_g_slist_remove(GSList *list, gconstpointer data);
+
+struct resourced_notifier {
+       enum notifier_type status;
+       noti_cb func;
+};
+
+struct resourced_notifier *notifier;
+
+int test_notifier_cb(void *data)
+{
+       check_expected_ptr(data);
+       return 0;
+}
+
+void __wrap_free(void *ptr)
+{
+       bool check = mock_type(bool);
+       if (check)
+               check_expected_ptr(ptr);
+       __real_free(ptr);
+}
+
+void *__wrap_malloc(size_t size)
+{
+       bool fake = mock_type(bool);
+       if (fake)
+               return NULL;
+       return __real_malloc(size);
+}
+
+GSList *__wrap_g_slist_append(GSList *list, gpointer data)
+{
+       assert(data);
+       bool wrap_append =  mock_type(bool);
+       if (!wrap_append)
+               return __real_g_slist_append(list, data);
+
+       notifier = (struct resourced_notifier *)data;
+
+       if (!notifier->func)
+               return NULL;
+       int t = mock_type(int);
+       void *f = mock_ptr_type(void *);
+
+       assert(t == (int) notifier->status);
+       assert(f == (void*) notifier->func);
+
+       (void) t;
+       (void) f;
+
+       GSList *l = (GSList *)calloc(1, sizeof (GSList));
+       assert(l);
+       l->data = data;
+
+       return l;
+}
+
+GSList *__wrap_g_slist_remove(GSList *list, gconstpointer data)
+{
+       bool wrap_remove =  mock_type(bool);
+       if (!wrap_remove)
+               return __real_g_slist_remove(list, data);
+
+       if (!list)
+               return NULL;
+
+       struct resourced_notifier *n = (struct resourced_notifier *)data;
+       assert(n == notifier);
+       __real_free(list);
+
+       (void) n;
+       return NULL;
+}
+
+static void test_register_notifier(void **state)
+{
+       (void) state; /* unused */
+
+       void *fptr = test_notifier_cb;
+       assert_int_equal(register_notifier(1, NULL), -EINVAL);
+
+       will_return(__wrap_malloc, true);
+       assert_int_equal(register_notifier(1, fptr), -ENOMEM);
+       will_return_maybe(__wrap_malloc, false);
+
+       will_return(__wrap_g_slist_append, true);
+       will_return(__wrap_g_slist_append, 1);
+       will_return(__wrap_g_slist_append, cast_ptr_to_largest_integral_type(fptr));
+       assert_int_equal(register_notifier(1, fptr), 0);
+       assert_int_equal(register_notifier(1, fptr), -EINVAL);
+}
+
+static void test_notify(void **state)
+{
+       (void) state; /* unused */
+       const char *d = "xoxo";
+       expect_string(test_notifier_cb, data, d);
+       resourced_notify(1, (void *)d);
+}
+
+static void test_unregister_notifier(void **state)
+{
+       (void) state; /* unused */
+       void *fptr = test_notifier_cb;
+       assert_int_equal(unregister_notifier(1, NULL), -EINVAL);
+
+       will_return(__wrap_free, true);
+       expect_value(__wrap_free, ptr, cast_ptr_to_largest_integral_type(notifier));
+       will_return(__wrap_g_slist_remove, true);
+       assert_int_equal(unregister_notifier(1, fptr), 0);
+}
+
+static int test_setup(void **state)
+{
+       will_return_maybe(__wrap_malloc, false);
+       return 0;
+}
+
+int main(int argc, char* argv[])
+{
+       const struct CMUnitTest tests[] = {
+               cmocka_unit_test(test_register_notifier),
+               cmocka_unit_test(test_notify),
+               cmocka_unit_test(test_unregister_notifier),
+
+       };
+       return cmocka_run_group_tests(tests, test_setup, NULL);
+}