diff --git a/meson.build b/meson.build index 60224f9..29978a9 100644 --- a/meson.build +++ b/meson.build @@ -127,24 +127,35 @@ subproject('munit') munit = dependency('munit', fallback: ['munit', 'munit_dep']) +lib_unittest = static_library('unittest', + 'src/util-munit.h', + 'src/util-munit.c', + dependencies: munit, +) + +dep_unittest = declare_dependency( + link_with: lib_unittest, + dependencies: munit +) + test('iotest', executable('iotest', 'test/iotest.c', include_directories: 'src', - dependencies: munit)) + dependencies: dep_unittest)) test('sourcestest', executable('sourcestest', 'test/sourcestest.c', include_directories: 'src', - dependencies: [munit, dep_libutil])) + dependencies: [dep_unittest, dep_libutil])) -test('libei-unit-test', - executable('libei-unit-test', - 'test/libei-unit-test.c', +test('unit-tests', + executable('unit-tests', + 'test/unit-tests.c', src_libei, include_directories: 'src', c_args: ['-D_enable_tests_'], - dependencies: [munit, dep_libutil, dep_protobuf])) + dependencies: [dep_unittest, dep_libutil, dep_protobuf])) lib_eierpecken = static_library('eierpecken', 'test/eierpecken.h', @@ -157,13 +168,13 @@ test('libei-integration-test', executable('eitest', 'test/test-ei.c', link_with: lib_eierpecken, - dependencies: [munit, dep_libei, dep_libeis])) + dependencies: [dep_unittest, dep_libei, dep_libeis])) test('libeis-integration-test', executable('eistest', 'test/test-eis.c', link_with: lib_eierpecken, - dependencies: [munit, dep_libei, dep_libeis])) + dependencies: [dep_unittest, dep_libei, dep_libeis])) valgrind = find_program('valgrind', required : false) diff --git a/src/brei-shared.c b/src/brei-shared.c index bde0a87..ac68a74 100644 --- a/src/brei-shared.c +++ b/src/brei-shared.c @@ -124,10 +124,9 @@ error: #ifdef _enable_tests_ -#include +#include "src/util-munit.h" -static MunitResult -test_proto_next_message(const MunitParameter params[], void *user_data) +MUNIT_TEST(test_proto_next_message) { char data[64]; @@ -192,8 +191,7 @@ send_data(int fd, const char *data, size_t data_size) munit_assert_int(rc, ==, framelen + data_size); } -static MunitResult -test_brei_dispatch(const MunitParameter params[], void *user_data) +MUNIT_TEST(test_brei_dispatch) { int sv[2]; int rc = socketpair(AF_UNIX, SOCK_STREAM|SOCK_NONBLOCK|SOCK_CLOEXEC, 0, sv); @@ -231,23 +229,4 @@ test_brei_dispatch(const MunitParameter params[], void *user_data) return MUNIT_OK; } - -#define TEST(_func) \ - { .name = #_func, .test = _func } - -static MunitTest ei_tests[] = { - TEST(test_proto_next_message), - TEST(test_brei_dispatch), - { NULL }, -}; - -static const MunitSuite libei_suite -__attribute__((used)) -__attribute__((section("test_section"))) = { - "/brei/", - ei_tests, - NULL, - 1, - MUNIT_SUITE_OPTION_NONE, -}; #endif diff --git a/src/libei.c b/src/libei.c index 3d51105..dc591b0 100644 --- a/src/libei.c +++ b/src/libei.c @@ -565,10 +565,9 @@ ei_configure_name(struct ei *ei, const char *name) } #ifdef _enable_tests_ -#include +#include "util-munit.h" -static MunitResult -test_init_unref(const MunitParameter params[], void *user_data) +MUNIT_TEST(test_init_unref) { struct ei *ei = ei_new(NULL); @@ -592,8 +591,7 @@ test_init_unref(const MunitParameter params[], void *user_data) return MUNIT_OK; } -static MunitResult -test_configure_name(const MunitParameter params[], void *user_data) +MUNIT_TEST(test_configure_name) { struct ei *ei = ei_new(NULL); @@ -621,23 +619,4 @@ test_configure_name(const MunitParameter params[], void *user_data) return MUNIT_OK; } - -#define TEST(_func) \ - { .name = #_func, .test = _func } - -static MunitTest ei_tests[] = { - TEST(test_init_unref), - TEST(test_configure_name), - { 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/util-munit.c b/src/util-munit.c new file mode 100644 index 0000000..c8f06ab --- /dev/null +++ b/src/util-munit.c @@ -0,0 +1,72 @@ +/* + * Copyright © 2020 Red Hat, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include "config.h" + +#include "util-munit.h" +#include "util-mem.h" +#include "util-strings.h" + +/* All MUNIT_TEST functions are in the test_functions_section ELF section. + * __start and __stop point to the start and end of that section. See the + * __attribute__(section) documentation. + */ +extern const struct test_function __start_test_functions_section, __stop_test_functions_section; + +int +munit_tests_run(int argc, char **argv) +{ + size_t count = 1; /* For NULL-terminated entry */ + + for (const struct test_function *t = &__start_test_functions_section; + t < &__stop_test_functions_section; + t++) + count++; + + _cleanup_free_ MunitTest *tests = calloc(count, sizeof(*tests)); + size_t idx = 0; + for (const struct test_function *t = &__start_test_functions_section; + t < &__stop_test_functions_section; + t++) { + MunitTest test = { + .name = xaprintf("%s", t->name), + .test = t->func, + }; + tests[idx++] = test; + } + + MunitSuite suite = { + "", + tests, + NULL, + 1, + MUNIT_SUITE_OPTION_NONE, + }; + + int rc = munit_suite_main(&suite, NULL, argc, argv); + + for (idx = 0; idx < count; idx++) + free(tests[idx].name); + + return rc; +} diff --git a/src/util-munit.h b/src/util-munit.h new file mode 100644 index 0000000..74dc24a --- /dev/null +++ b/src/util-munit.h @@ -0,0 +1,68 @@ +/* + * Copyright © 2020 Red Hat, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +/* This is a wrapper around munit to make it faster to use for the simple + * type of test cases. + * + * Use with the MUNIT_TEST macro like this: + * + * MUNIT_TEST(some_test) { + * return MUNIT_OK; + * } + * + * int main(int argc, char **argv) { + * return munit_tests_run(argc, argv); + * } + * + */ + +#pragma once + +#include + +typedef MunitResult (*munit_test_func_t)(const MunitParameter params[], void *user_data); + +struct test_function { + const char *name; /* function name */ + const char *file; /* file name */ + munit_test_func_t func; /* test function */ +} __attribute__((aligned(16))); + +/** + * Defines a struct test_function in a custom ELF section that we can then + * loop over in munit_tests_run() to extract the tests. This removes the + * need of manually adding the tests to a suite or listing them somewhere. + */ +#define MUNIT_TEST(_func) \ +static MunitResult _func(const MunitParameter params[], void *user_data); \ +static const struct test_function _test_##_func \ +__attribute__((used)) \ +__attribute__((section("test_functions_section"))) = { \ + .name = #_func, \ + .func = _func, \ + .file = __FILE__, \ +}; \ +static MunitResult _func(const MunitParameter params[], void *user_data) + +int +munit_tests_run(int argc, char **argv); diff --git a/test/iotest.c b/test/iotest.c index a338649..89d32d7 100644 --- a/test/iotest.c +++ b/test/iotest.c @@ -1,14 +1,35 @@ +/* + * Copyright © 2020 Red Hat, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + #include "config.h" #include #include -#include #include "util-io.h" +#include "util-munit.h" - -static MunitResult -test_iobuf_new(const MunitParameter params[], void *user_data) +MUNIT_TEST(test_iobuf_new) { /* test allocation and freeing a buffer */ struct iobuf *buf = iobuf_new(10); @@ -23,8 +44,7 @@ test_iobuf_new(const MunitParameter params[], void *user_data) return MUNIT_OK; } -static MunitResult -test_iobuf_cleanup(const MunitParameter params[], void *user_data) +MUNIT_TEST(test_iobuf_cleanup) { /* Test the attribute(cleanup) define. This test needs to run in * valgrind --leak-check=full to be really useful */ @@ -34,8 +54,7 @@ test_iobuf_cleanup(const MunitParameter params[], void *user_data) return MUNIT_OK; } -static MunitResult -test_iobuf_append(const MunitParameter params[], void *user_data) +MUNIT_TEST(test_iobuf_append) { /* Test appending data */ _cleanup_iobuf_ struct iobuf *buf = iobuf_new(10); @@ -68,8 +87,7 @@ test_iobuf_append(const MunitParameter params[], void *user_data) return MUNIT_OK; } -static MunitResult -test_iobuf_append_short(const MunitParameter params[], void *user_data) +MUNIT_TEST(test_iobuf_append_short) { _cleanup_iobuf_ struct iobuf *buf = iobuf_new(10); @@ -89,8 +107,7 @@ test_iobuf_append_short(const MunitParameter params[], void *user_data) return MUNIT_OK; } -static MunitResult -test_iobuf_append_fd(const MunitParameter params[], void *user_data) +MUNIT_TEST(test_iobuf_append_fd) { _cleanup_iobuf_ struct iobuf *buf = iobuf_new(10); int fds[2]; @@ -148,25 +165,8 @@ test_iobuf_append_fd(const MunitParameter params[], void *user_data) return MUNIT_OK; } -static MunitTest iotest_tests[] = { - { "iobuf/new", test_iobuf_new, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL}, - { "iobuf/cleanup", test_iobuf_cleanup, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL}, - { "iobuf/append", test_iobuf_append, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL}, - { "iobuf/append_short", test_iobuf_append_short, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL}, - { "iobuf/append_fd", test_iobuf_append_fd, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL}, - { NULL }, -}; - -static const MunitSuite iotest_suite = { - "iotest", - iotest_tests, - NULL, - 1, - MUNIT_SUITE_OPTION_NONE, -}; - int main(int argc, char* argv[MUNIT_ARRAY_PARAM(argc + 1)]) { - return munit_suite_main(&iotest_suite, NULL, argc, argv); + return munit_tests_run(argc, argv); } diff --git a/test/libei-unit-test.c b/test/libei-unit-test.c deleted file mode 100644 index 8f15afb..0000000 --- a/test/libei-unit-test.c +++ /dev/null @@ -1,37 +0,0 @@ -#include "config.h" - -#include -#include -#include -#include - -#include "util-mem.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; - _cleanup_free_ 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); -} diff --git a/test/sourcestest.c b/test/sourcestest.c index 1fa75d0..efdd4a3 100644 --- a/test/sourcestest.c +++ b/test/sourcestest.c @@ -29,10 +29,9 @@ #include #include -#include - #include "util-macros.h" #include "util-mem.h" +#include "util-munit.h" #include "util-sources.h" DEFINE_TRIVIAL_CLEANUP_FUNC(struct sink *, sink_unref); @@ -40,8 +39,8 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(struct sink *, sink_unref); DEFINE_TRIVIAL_CLEANUP_FUNC(struct source *, source_unref); #define _cleanup_source_ _cleanup_(source_unrefp) -static MunitResult -test_sink(const MunitParameter params[], void *user_data) + +MUNIT_TEST(test_sink) { struct sink *sink = sink_new(); sink_dispatch(sink); @@ -76,8 +75,7 @@ read_buffer(struct source *source, void *user_data) buffer->len = nread; } -static MunitResult -test_source(const MunitParameter params[], void *user_data) +MUNIT_TEST(test_source) { _cleanup_sink_ struct sink *sink = sink_new(); @@ -136,8 +134,7 @@ drain_data(struct source *source, void *user_data) read(source_get_fd(source), buf, sizeof(buf)); } -static MunitResult -test_source_readd(const MunitParameter params[], void *user_data) +MUNIT_TEST(test_source_readd) { _cleanup_sink_ struct sink *sink = sink_new(); @@ -156,23 +153,8 @@ test_source_readd(const MunitParameter params[], void *user_data) return MUNIT_OK; } -static MunitTest iotest_tests[] = { - { .name = "/sink", .test = test_sink}, - { .name = "/source", .test = test_source}, - { .name = "/source/readd", .test = test_source_readd}, - { NULL }, -}; - -static const MunitSuite iotest_suite = { - "/sources", - iotest_tests, - NULL, - 1, - MUNIT_SUITE_OPTION_NONE, -}; - int -main(int argc, char* argv[MUNIT_ARRAY_PARAM(argc + 1)]) +main(int argc, char **argv) { - return munit_suite_main(&iotest_suite, NULL, argc, argv); + return munit_tests_run(argc, argv); } diff --git a/test/test-ei.c b/test/test-ei.c index 7bdc878..ea99509 100644 --- a/test/test-ei.c +++ b/test/test-ei.c @@ -3,13 +3,12 @@ #include #include -#include +#include "util-munit.h" #include "libei.h" #include "eierpecken.h" -static MunitResult -test_ei_ref_unref(const MunitParameter params[], void *user_data) +MUNIT_TEST(test_ei_ref_unref) { struct ei *ei = ei_new(NULL); @@ -26,8 +25,7 @@ test_ei_ref_unref(const MunitParameter params[], void *user_data) return MUNIT_OK; } -static MunitResult -test_ei_reject(const MunitParameter params[], void *user_data) +MUNIT_TEST(test_ei_reject) { _cleanup_peck_ struct peck *peck = peck_new(); @@ -46,8 +44,7 @@ test_ei_reject(const MunitParameter params[], void *user_data) return MUNIT_OK; } -static MunitResult -test_ei_reject_after_connect(const MunitParameter params[], void *user_data) +MUNIT_TEST(test_ei_reject_after_connect) { _cleanup_peck_ struct peck *peck = peck_new(); _cleanup_eis_client_ struct eis_client *client = NULL; @@ -84,8 +81,7 @@ test_ei_reject_after_connect(const MunitParameter params[], void *user_data) return MUNIT_OK; } -static MunitResult -test_ei_device_basics(const MunitParameter params[], void *user_data) +MUNIT_TEST(test_ei_device_basics) { _cleanup_peck_ struct peck *peck = peck_new(); _cleanup_ei_device_ struct ei_device *device = NULL; @@ -131,8 +127,7 @@ test_ei_device_basics(const MunitParameter params[], void *user_data) return MUNIT_OK; } -static MunitResult -test_ei_device_add(const MunitParameter params[], void *user_data) +MUNIT_TEST(test_ei_device_add) { _cleanup_peck_ struct peck *peck = peck_new(); @@ -169,8 +164,7 @@ test_ei_device_add(const MunitParameter params[], void *user_data) return MUNIT_OK; } -static MunitResult -test_ei_device_add_drop_caps(const MunitParameter params[], void *user_data) +MUNIT_TEST(test_ei_device_add_drop_caps) { _cleanup_peck_ struct peck *peck = peck_new(); @@ -208,8 +202,7 @@ test_ei_device_add_drop_caps(const MunitParameter params[], void *user_data) return MUNIT_OK; } -static MunitResult -test_ei_device_add_zero_caps(const MunitParameter params[], void *user_data) +MUNIT_TEST(test_ei_device_add_zero_caps) { _cleanup_peck_ struct peck *peck = peck_new(); @@ -242,27 +235,8 @@ test_ei_device_add_zero_caps(const MunitParameter params[], void *user_data) return MUNIT_OK; } -static MunitTest ei_tests[] = { - { .name = "/ei/ref", .test = test_ei_ref_unref }, - { .name = "/ei/reject", .test = test_ei_reject }, - { .name = "/ei/reject_after_connect", .test = test_ei_reject_after_connect }, - { .name = "/device/basics", .test = test_ei_device_basics }, - { .name = "/device/add", .test = test_ei_device_add }, - { .name = "/device/add_drop_caps", .test = test_ei_device_add_drop_caps }, - { .name = "/device/add_zero_caps", .test = test_ei_device_add_zero_caps }, - { NULL }, -}; - -static const MunitSuite ei_suite = { - "/ei", - ei_tests, - NULL, - 1, - MUNIT_SUITE_OPTION_NONE, -}; - int -main(int argc, char* argv[MUNIT_ARRAY_PARAM(argc + 1)]) +main(int argc, char **argv) { - return munit_suite_main(&ei_suite, NULL, argc, argv); + return munit_tests_run(argc, argv); } diff --git a/test/test-eis.c b/test/test-eis.c index 322136f..91215df 100644 --- a/test/test-eis.c +++ b/test/test-eis.c @@ -23,12 +23,11 @@ #include "config.h" -#include +#include "util-munit.h" #include "eierpecken.h" -static MunitResult -eistest_ref_unref(const MunitParameter params[], void *user_data) +MUNIT_TEST(eistest_ref_unref) { struct eis *eis = eis_new(NULL); @@ -45,8 +44,7 @@ eistest_ref_unref(const MunitParameter params[], void *user_data) return MUNIT_OK; } -static MunitResult -eistest_name(const MunitParameter params[], void *user_data) +MUNIT_TEST(eistest_name) { _cleanup_peck_ struct peck *peck = peck_new(); @@ -76,8 +74,7 @@ eistest_name(const MunitParameter params[], void *user_data) return MUNIT_OK; } -static MunitResult -eistest_ranges(const MunitParameter params[], void *user_data) +MUNIT_TEST(eistest_ranges) { _cleanup_peck_ struct peck *peck = peck_new(); @@ -112,23 +109,8 @@ eistest_ranges(const MunitParameter params[], void *user_data) return MUNIT_OK; } -static MunitTest eis_tests[] = { - { .name = "/ref", .test = eistest_ref_unref }, - { .name = "/name", .test = eistest_name }, - { .name = "/ranges", .test = eistest_ranges }, - { NULL }, -}; - -static const MunitSuite eis_suite = { - "/eis", - eis_tests, - NULL, - 1, - MUNIT_SUITE_OPTION_NONE, -}; - int -main(int argc, char* argv[MUNIT_ARRAY_PARAM(argc + 1)]) +main(int argc, char **argv) { - return munit_suite_main(&eis_suite, NULL, argc, argv); + return munit_tests_run(argc, argv); } diff --git a/test/unit-tests.c b/test/unit-tests.c new file mode 100644 index 0000000..f27c676 --- /dev/null +++ b/test/unit-tests.c @@ -0,0 +1,32 @@ +/* + * Copyright © 2020 Red Hat, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include "config.h" + +#include "util-munit.h" + +int +main(int argc, char **argv) +{ + return munit_tests_run(argc, argv); +}