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 <peter.hutterer@who-t.net>
This commit is contained in:
Peter Hutterer 2020-08-04 14:40:13 +10:00
parent b4552374ca
commit 0ab1458241
7 changed files with 250 additions and 6 deletions

View file

@ -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',

View file

@ -25,8 +25,9 @@
#include <errno.h>
#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 <munit.h>
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

View file

@ -708,3 +708,82 @@ ei_configure_name(struct ei *ei, const char *name)
free(ei->name);
ei->name = xstrdup(name);
}
#ifdef _enable_tests_
#include <munit.h>
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

View file

@ -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

View file

@ -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

View file

@ -145,6 +145,7 @@ OBJECT_IMPLEMENT_CREATE(sink);
int
sink_get_fd(struct sink *sink)
{
assert(sink);
return sink->epollfd;
}

35
test/libei-unit-test.c Normal file
View file

@ -0,0 +1,35 @@
#include "config.h"
#include <assert.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <munit.h>
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);
}