From 0ab14582419e59fe79129be5adb14a7cf081e751 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Tue, 4 Aug 2020 14:40:13 +1000 Subject: [PATCH] test: add some internal unit-tests to libei Similar in style to Rust where the unit tests are in the same file. Let's see how far we can get with that in C. Auto-discovery of tests by forcing the respective suites into a special test section so we can collect it later from our unit runner. Signed-off-by: Peter Hutterer --- meson.build | 15 +++++- src/libei-device.c | 120 ++++++++++++++++++++++++++++++++++++++++- src/libei.c | 79 +++++++++++++++++++++++++++ src/libei.h | 2 +- src/libeis.c | 4 +- src/util-sources.c | 1 + test/libei-unit-test.c | 35 ++++++++++++ 7 files changed, 250 insertions(+), 6 deletions(-) create mode 100644 test/libei-unit-test.c diff --git a/meson.build b/meson.build index b4d2d0b..fe9bc43 100644 --- a/meson.build +++ b/meson.build @@ -33,13 +33,16 @@ lib_util = static_library('util', dep_libutil = declare_dependency(link_with: lib_util) - -lib_libei = shared_library('ei', +src_libei = [ 'src/libei.h', 'src/libei.c', 'src/libei-device.c', 'src/libei-socket.c', proto_headers, +] + +lib_libei = shared_library('ei', + src_libei, dependencies: [dep_libutil, dep_protobuf], install: true ) @@ -99,6 +102,14 @@ test('iotest', include_directories: 'src', dependencies: munit)) +test('libei-unit-test', + executable('libei-unit-test', + 'test/libei-unit-test.c', + src_libei, + include_directories: 'src', + c_args: ['-D_enable_tests_'], + dependencies: [munit, dep_libutil, dep_protobuf])) + valgrind = find_program('valgrind', required : false) if valgrind.found() add_test_setup('valgrind', diff --git a/src/libei-device.c b/src/libei-device.c index 9ac0ed4..9073489 100644 --- a/src/libei-device.c +++ b/src/libei-device.c @@ -25,8 +25,9 @@ #include -#include "util-macros.h" #include "util-bits.h" +#include "util-macros.h" +#include "util-mem.h" #include "libei-private.h" @@ -157,3 +158,120 @@ ei_device_keyboard_key(struct ei_device *device, ei_keyboard_key(device, key, is_press); } + + + +#ifdef _enable_tests_ +#include + +static MunitResult +test_device_new(const MunitParameter params[], void *user_data) +{ + struct ei ei = {0}; + struct ei_device *d = ei_device_new(&ei); + + munit_assert_int(d->id, >, 0); + munit_assert_int(d->capabilities, ==, 0); + munit_assert_int(d->state, ==, EI_DEVICE_STATE_NEW); + + struct ei_device *unrefd = ei_device_unref(d); + munit_assert_ptr_null(unrefd); + return MUNIT_OK; +} + +static MunitResult +test_device_ids(const MunitParameter params[], void *user_data) +{ + struct ei ei = {0}; + _cleanup_(ei_device_cleanup) struct ei_device *d1 = ei_device_new(&ei); + _cleanup_(ei_device_cleanup) struct ei_device *d2 = ei_device_new(&ei); + _cleanup_(ei_device_cleanup) struct ei_device *d3 = ei_device_new(&ei); + + munit_assert_int(d1->id, <, d2->id); + munit_assert_int(d1->id, <, d3->id); + munit_assert_int(d2->id, <, d3->id); + + return MUNIT_OK; +} + +static MunitResult +test_device_ref_unref(const MunitParameter params[], void *user_data) +{ + struct ei ei = {0}; + struct ei_device *d = ei_device_new(&ei); + + munit_assert_int(d->object.refcount, ==, 1); + + struct ei_device *refd = ei_device_ref(d); + munit_assert_ptr_equal(d, refd); + munit_assert_int(d->object.refcount, ==, 2); + + struct ei_device *unrefd = ei_device_unref(d); + munit_assert_ptr_null(unrefd); + munit_assert_int(d->object.refcount, ==, 1); + + unrefd = ei_device_unref(d); + munit_assert_ptr_null(unrefd); + + return MUNIT_OK; +} + +static MunitResult +test_device_cap(const MunitParameter params[], void *user_data) +{ + struct ei ei = {0}; + _cleanup_(ei_device_cleanup) struct ei_device *d = ei_device_new(&ei); + + munit_assert(ei_device_configure_capability(d, EI_DEVICE_CAP_POINTER)); + /* twice is fine */ + munit_assert(ei_device_configure_capability(d, EI_DEVICE_CAP_POINTER)); + munit_assert(ei_device_has_capability(d, EI_DEVICE_CAP_POINTER)); + + munit_assert(ei_device_configure_capability(d, EI_DEVICE_CAP_POINTER_ABSOLUTE)); + munit_assert(ei_device_has_capability(d, EI_DEVICE_CAP_POINTER_ABSOLUTE)); + + munit_assert(ei_device_configure_capability(d, EI_DEVICE_CAP_KEYBOARD)); + munit_assert(ei_device_has_capability(d, EI_DEVICE_CAP_KEYBOARD)); + + munit_assert(ei_device_configure_capability(d, EI_DEVICE_CAP_TOUCH)); + munit_assert(ei_device_has_capability(d, EI_DEVICE_CAP_TOUCH)); + + /* Invalid caps */ + munit_assert(!ei_device_configure_capability(d, 0)); + munit_assert(!ei_device_has_capability(d, 0)); + munit_assert(!ei_device_configure_capability(d, EI_DEVICE_CAP_TOUCH + 1)); + munit_assert(!ei_device_has_capability(d, EI_DEVICE_CAP_TOUCH + 1)); + + return MUNIT_OK; +} + +static MunitResult +test_device_context(const MunitParameter params[], void *user_data) +{ + struct ei ei = {0}; + _cleanup_(ei_device_cleanup) struct ei_device *d = ei_device_new(&ei); + + munit_assert_ptr_equal(d->object.parent, &ei); + + return MUNIT_OK; +} + +static MunitTest ei_device_tests[] = { + { "/new", test_device_new, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL}, + { "/ids", test_device_ids, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL}, + { "/ref", test_device_ref_unref, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL}, + { "/capability", test_device_cap, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL}, + { "/context", test_device_context, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL}, + { NULL }, +}; + +static const MunitSuite libei_device_suite +__attribute__((used)) +__attribute__((section("test_section"))) = { + "/device", + ei_device_tests, + NULL, + 1, + MUNIT_SUITE_OPTION_NONE, +}; +#endif diff --git a/src/libei.c b/src/libei.c index d31dc4a..8a4ea6c 100644 --- a/src/libei.c +++ b/src/libei.c @@ -708,3 +708,82 @@ ei_configure_name(struct ei *ei, const char *name) free(ei->name); ei->name = xstrdup(name); } + +#ifdef _enable_tests_ +#include + +static MunitResult +test_init_unref(const MunitParameter params[], void *user_data) +{ + /* need to alloc here so unref can free */ + struct ei *ei = xalloc(sizeof(*ei)); + + ei_init(ei); + + munit_assert_int(ei->state, ==, EI_STATE_NEW); + munit_assert(list_empty(&ei->event_queue)); + munit_assert(list_empty(&ei->devices)); + + munit_assert_not_null(ei->sink); + munit_assert_not_null(ei->logger); + + struct ei *refd = ei_ref(ei); + munit_assert_ptr_equal(ei, refd); + munit_assert_int(ei->object.refcount, ==, 2); + + + struct ei *unrefd = ei_unref(ei); + munit_assert_null(unrefd); + + unrefd = ei_unref(ei); + munit_assert_null(unrefd); + + return MUNIT_OK; +} + +static MunitResult +test_configure_name(const MunitParameter params[], void *user_data) +{ + struct ei ei = { + .state = EI_STATE_NEW, + }; + + ei_configure_name(&ei, "foo"); + munit_assert_string_equal(ei.name, "foo"); + ei_configure_name(&ei, "bar"); + munit_assert_string_equal(ei.name, "bar"); + + /* ignore names that are too long */ + char buf[1200] = {0}; + memset(buf, 'a', sizeof(buf) - 1); + ei_configure_name(&ei, buf); + munit_assert_string_equal(ei.name, "bar"); + + /* ignore names in all other states */ + for (enum ei_state state = EI_STATE_NEW + 1; + state <= EI_STATE_DISCONNECTED; + state++) { + ei.state = state; + ei_configure_name(&ei, "expect ignored"); + munit_assert_string_equal(ei.name, "bar"); + } + + return MUNIT_OK; +} + +static MunitTest ei_tests[] = { + { "/init_unref", test_init_unref, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL}, + { "/name", test_configure_name, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL}, + { NULL }, +}; + +static const MunitSuite libei_suite +__attribute__((used)) +__attribute__((section("test_section"))) = { + "", + ei_tests, + NULL, + 1, + MUNIT_SUITE_OPTION_NONE, +}; +#endif diff --git a/src/libei.h b/src/libei.h index 58b490a..86a61b0 100644 --- a/src/libei.h +++ b/src/libei.h @@ -99,7 +99,7 @@ enum ei_event_type { }; struct ei * -ei_new(void); +ei_new(void *user_data); /** * Set the name for this client. This is a suggestion to the diff --git a/src/libeis.c b/src/libeis.c index e968177..0dc277d 100644 --- a/src/libeis.c +++ b/src/libeis.c @@ -51,8 +51,8 @@ eis_event_destroy(struct eis_event *event) default: abort(); /* not yet implemented */ } - eis_device_unref(event->device); - eis_client_unref(event->client); + event->device = eis_device_unref(event->device); + event->client = eis_client_unref(event->client); } static diff --git a/src/util-sources.c b/src/util-sources.c index 955c0a9..52c2c87 100644 --- a/src/util-sources.c +++ b/src/util-sources.c @@ -145,6 +145,7 @@ OBJECT_IMPLEMENT_CREATE(sink); int sink_get_fd(struct sink *sink) { + assert(sink); return sink->epollfd; } diff --git a/test/libei-unit-test.c b/test/libei-unit-test.c new file mode 100644 index 0000000..a2db95d --- /dev/null +++ b/test/libei-unit-test.c @@ -0,0 +1,35 @@ +#include "config.h" + +#include +#include +#include +#include + +extern const MunitSuite __start_test_section, __stop_test_section; + +int +main(int argc, char* argv[MUNIT_ARRAY_PARAM(argc + 1)]) +{ + size_t sz = 10; + size_t count = 0; + MunitSuite *suites = calloc(sz, sizeof(*suites)); + + for (const MunitSuite *s = &__start_test_section; + s < &__stop_test_section; + s++) { + assert(count < sz - 1); + + suites[count] = *s; + count++; + } + + const MunitSuite suite = { + "/ei", + NULL, + suites, + 1, + MUNIT_SUITE_OPTION_NONE, + }; + + return munit_suite_main(&suite, NULL, argc, argv); +}