It's nice to keep helper sources separately from tests sources. It's better for searching files as well as for extending the test-suite.
Also, there were no need to compile each test with test-*.c files so I used them to create noinst library and link the tests against it. Now we don't need to attach test-runner files to each test sources. --- configure.ac | 3 +- tests/Makefile.am | 46 ++++----- tests/test-helpers.c | 64 ------------ tests/test-runner.c | 207 --------------------------------------- tests/test-runner.h | 40 -------- tests/test-runner/Makefile.am | 13 +++ tests/test-runner/test-helpers.c | 64 ++++++++++++ tests/test-runner/test-runner.c | 207 +++++++++++++++++++++++++++++++++++++++ tests/test-runner/test-runner.h | 40 ++++++++ 9 files changed, 350 insertions(+), 334 deletions(-) delete mode 100644 tests/test-helpers.c delete mode 100644 tests/test-runner.c delete mode 100644 tests/test-runner.h create mode 100644 tests/test-runner/Makefile.am create mode 100644 tests/test-runner/test-helpers.c create mode 100644 tests/test-runner/test-runner.c create mode 100644 tests/test-runner/test-runner.h diff --git a/configure.ac b/configure.ac index f8be456..09db2e9 100644 --- a/configure.ac +++ b/configure.ac @@ -146,5 +146,6 @@ AC_CONFIG_FILES([Makefile src/wayland-scanner.pc src/wayland-version.h protocol/Makefile - tests/Makefile]) + tests/Makefile + tests/test-runner/Makefile]) AC_OUTPUT diff --git a/tests/Makefile.am b/tests/Makefile.am index 9c673ae..4a999b9 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -1,3 +1,6 @@ +SUBDIRS = test-runner +test_runner_dir = $(top_builddir)/tests/test-runner + TESTS = \ array-test \ client-test \ @@ -21,38 +24,37 @@ check_PROGRAMS = \ noinst_PROGRAMS = \ fixed-benchmark -test_runner_src = test-runner.c test-runner.h test-helpers.c - -array_test_SOURCES = array-test.c $(test_runner_src) -client_test_SOURCES = client-test.c $(test_runner_src) -display_test_SOURCES = display-test.c $(test_runner_src) -connection_test_SOURCES = connection-test.c $(test_runner_src) -event_loop_test_SOURCES = event-loop-test.c $(test_runner_src) -fixed_test_SOURCES = fixed-test.c $(test_runner_src) -list_test_SOURCES = list-test.c $(test_runner_src) -map_test_SOURCES = map-test.c $(test_runner_src) -sanity_test_SOURCES = sanity-test.c $(test_runner_src) -socket_test_SOURCES = socket-test.c $(test_runner_src) -queue_test_SOURCES = queue-test.c $(test_runner_src) -signal_test_SOURCES = signal-test.c $(test_runner_src) -resources_test_SOURCES = resources-test.c $(test_runner_src) +array_test_SOURCES = array-test.c +client_test_SOURCES = client-test.c +display_test_SOURCES = display-test.c +connection_test_SOURCES = connection-test.c +event_loop_test_SOURCES = event-loop-test.c +fixed_test_SOURCES = fixed-test.c +list_test_SOURCES = list-test.c +map_test_SOURCES = map-test.c +sanity_test_SOURCES = sanity-test.c +socket_test_SOURCES = socket-test.c +queue_test_SOURCES = queue-test.c +signal_test_SOURCES = signal-test.c +resources_test_SOURCES = resources-test.c fixed_benchmark_SOURCES = fixed-benchmark.c os_wrappers_test_SOURCES = \ os-wrappers-test.c \ - ../src/wayland-os.c \ - $(test_runner_src) + ../src/wayland-os.c -AM_CPPFLAGS = -I$(top_builddir)/src -I$(top_srcdir)/src +AM_CPPFLAGS = \ + -I$(top_builddir)/src \ + -I$(top_srcdir)/src \ + -I$(test_runner_dir) AM_CFLAGS = $(GCC_CFLAGS) $(FFI_CFLAGS) LDADD = $(top_builddir)/src/libwayland-util.la \ $(top_builddir)/src/libwayland-client.la \ $(top_builddir)/src/libwayland-server.la \ + $(test_runner_dir)/libtest-runner.la -lrt -ldl $(FFI_LIBS) exec_fd_leak_checker_SOURCES = \ - exec-fd-leak-checker.c \ - test-runner.h \ - test-helpers.c -exec_fd_leak_checker_LDADD = + exec-fd-leak-checker.c +exec_fd_leak_checker_LDADD = $(test_runner_dir)/libtest-helpers.la diff --git a/tests/test-helpers.c b/tests/test-helpers.c deleted file mode 100644 index 4761b09..0000000 --- a/tests/test-helpers.c +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright © 2012 Collabora, Ltd. - * - * Permission to use, copy, modify, distribute, and sell this software and its - * documentation for any purpose is hereby granted without fee, provided that - * the above copyright notice appear in all copies and that both that copyright - * notice and this permission notice appear in supporting documentation, and - * that the name of the copyright holders not be used in advertising or - * publicity pertaining to distribution of the software without specific, - * written prior permission. The copyright holders make no representations - * about the suitability of this software for any purpose. It is provided "as - * is" without express or implied warranty. - * - * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, - * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO - * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR - * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, - * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER - * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE - * OF THIS SOFTWARE. - */ - -#include <assert.h> -#include <errno.h> -#include <dirent.h> -#include <stdio.h> -#include <unistd.h> - -#include "test-runner.h" - -int -count_open_fds(void) -{ - DIR *dir; - struct dirent *ent; - int count = 0; - - dir = opendir("/proc/self/fd"); - assert(dir && "opening /proc/self/fd failed."); - - errno = 0; - while ((ent = readdir(dir))) { - const char *s = ent->d_name; - if (s[0] == '.' && (s[1] == 0 || (s[1] == '.' && s[2] == 0))) - continue; - count++; - } - assert(errno == 0 && "reading /proc/self/fd failed."); - - closedir(dir); - - return count; -} - -void -exec_fd_leak_check(int nr_expected_fds) -{ - const char *exe = "./exec-fd-leak-checker"; - char number[16] = { 0 }; - - snprintf(number, sizeof number - 1, "%d", nr_expected_fds); - execl(exe, exe, number, (char *)NULL); - assert(0 && "execing fd leak checker failed"); -} diff --git a/tests/test-runner.c b/tests/test-runner.c deleted file mode 100644 index 8f3d5d3..0000000 --- a/tests/test-runner.c +++ /dev/null @@ -1,207 +0,0 @@ -/* - * Copyright © 2012 Intel Corporation - * - * Permission to use, copy, modify, distribute, and sell this software and its - * documentation for any purpose is hereby granted without fee, provided that - * the above copyright notice appear in all copies and that both that copyright - * notice and this permission notice appear in supporting documentation, and - * that the name of the copyright holders not be used in advertising or - * publicity pertaining to distribution of the software without specific, - * written prior permission. The copyright holders make no representations - * about the suitability of this software for any purpose. It is provided "as - * is" without express or implied warranty. - * - * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, - * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO - * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR - * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, - * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER - * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE - * OF THIS SOFTWARE. - */ - -#define _GNU_SOURCE - -#include <unistd.h> -#include <stdio.h> -#include <stdlib.h> -#include <sys/types.h> -#include <sys/wait.h> -#include <string.h> -#include <assert.h> -#include <dlfcn.h> -#include <errno.h> -#include "test-runner.h" - -static int num_alloc; -static void* (*sys_malloc)(size_t); -static void (*sys_free)(void*); -static void* (*sys_realloc)(void*, size_t); -static void* (*sys_calloc)(size_t, size_t); - -int leak_check_enabled; - -extern const struct test __start_test_section, __stop_test_section; - -__attribute__ ((visibility("default"))) void * -malloc(size_t size) -{ - num_alloc++; - return sys_malloc(size); -} - -__attribute__ ((visibility("default"))) void -free(void* mem) -{ - if (mem != NULL) - num_alloc--; - sys_free(mem); -} - -__attribute__ ((visibility("default"))) void * -realloc(void* mem, size_t size) -{ - if (mem == NULL) - num_alloc++; - return sys_realloc(mem, size); -} - -__attribute__ ((visibility("default"))) void * -calloc(size_t nmemb, size_t size) -{ - if (sys_calloc == NULL) - return NULL; - - num_alloc++; - - return sys_calloc(nmemb, size); -} - -static const struct test * -find_test(const char *name) -{ - const struct test *t; - - for (t = &__start_test_section; t < &__stop_test_section; t++) - if (strcmp(t->name, name) == 0) - return t; - - return NULL; -} - -static void -usage(const char *name, int status) -{ - const struct test *t; - - fprintf(stderr, "Usage: %s [TEST]\n\n" - "With no arguments, run all test. Specify test case to run\n" - "only that test without forking. Available tests:\n\n", - name); - - for (t = &__start_test_section; t < &__stop_test_section; t++) - fprintf(stderr, " %s\n", t->name); - - fprintf(stderr, "\n"); - - exit(status); -} - -static void -run_test(const struct test *t) -{ - int cur_alloc = num_alloc; - int cur_fds, num_fds; - - cur_fds = count_open_fds(); - t->run(); - if (leak_check_enabled) { - if (cur_alloc != num_alloc) { - fprintf(stderr, "Memory leak detected in test. " - "Allocated %d blocks, unfreed %d\n", num_alloc, - num_alloc - cur_alloc); - abort(); - } - num_fds = count_open_fds(); - if (cur_fds != num_fds) { - fprintf(stderr, "fd leak detected in test. " - "Opened %d files, unclosed %d\n", num_fds, - num_fds - cur_fds); - abort(); - } - } - exit(EXIT_SUCCESS); -} - -int main(int argc, char *argv[]) -{ - const struct test *t; - pid_t pid; - int total, pass; - siginfo_t info; - - /* Load system malloc, free, and realloc */ - sys_calloc = dlsym(RTLD_NEXT, "calloc"); - sys_realloc = dlsym(RTLD_NEXT, "realloc"); - sys_malloc = dlsym(RTLD_NEXT, "malloc"); - sys_free = dlsym(RTLD_NEXT, "free"); - - leak_check_enabled = !getenv("NO_ASSERT_LEAK_CHECK"); - - if (argc == 2 && strcmp(argv[1], "--help") == 0) - usage(argv[0], EXIT_SUCCESS); - - if (argc == 2) { - t = find_test(argv[1]); - if (t == NULL) { - fprintf(stderr, "unknown test: \"%s\"\n", argv[1]); - usage(argv[0], EXIT_FAILURE); - } - - run_test(t); - } - - pass = 0; - for (t = &__start_test_section; t < &__stop_test_section; t++) { - int success = 0; - - pid = fork(); - assert(pid >= 0); - - if (pid == 0) - run_test(t); /* never returns */ - - if (waitid(P_ALL, 0, &info, WEXITED)) { - fprintf(stderr, "waitid failed: %m\n"); - abort(); - } - - fprintf(stderr, "test \"%s\":\t", t->name); - switch (info.si_code) { - case CLD_EXITED: - fprintf(stderr, "exit status %d", info.si_status); - if (info.si_status == EXIT_SUCCESS) - success = 1; - break; - case CLD_KILLED: - case CLD_DUMPED: - fprintf(stderr, "signal %d", info.si_status); - break; - } - - if (t->must_fail) - success = !success; - - if (success) { - pass++; - fprintf(stderr, ", pass.\n"); - } else - fprintf(stderr, ", fail.\n"); - } - - total = &__stop_test_section - &__start_test_section; - fprintf(stderr, "%d tests, %d pass, %d fail\n", - total, pass, total - pass); - - return pass == total ? EXIT_SUCCESS : EXIT_FAILURE; -} diff --git a/tests/test-runner.h b/tests/test-runner.h deleted file mode 100644 index 707504c..0000000 --- a/tests/test-runner.h +++ /dev/null @@ -1,40 +0,0 @@ -#ifndef _TEST_RUNNER_H_ -#define _TEST_RUNNER_H_ - -#ifdef NDEBUG -#error "Tests must not be built with NDEBUG defined, they rely on assert()." -#endif - -struct test { - const char *name; - void (*run)(void); - int must_fail; -} __attribute__ ((aligned (16))); - -#define TEST(name) \ - static void name(void); \ - \ - const struct test test##name \ - __attribute__ ((section ("test_section"))) = { \ - #name, name, 0 \ - }; \ - \ - static void name(void) - -#define FAIL_TEST(name) \ - static void name(void); \ - \ - const struct test test##name \ - __attribute__ ((section ("test_section"))) = { \ - #name, name, 1 \ - }; \ - \ - static void name(void) - -int -count_open_fds(void); - -void -exec_fd_leak_check(int nr_expected_fds); /* never returns */ - -#endif diff --git a/tests/test-runner/Makefile.am b/tests/test-runner/Makefile.am new file mode 100644 index 0000000..b8f1e76 --- /dev/null +++ b/tests/test-runner/Makefile.am @@ -0,0 +1,13 @@ +noinst_LTLIBRARIES = libtest-runner.la libtest-helpers.la + +libtest_runner_la_LDFLAGS = -ldl +libtest_runner_la_LIBADD = libtest-helpers.la +libtest_runner_la_SOURCES = \ + test-runner.c \ + test-runner.h + +libtest_helpers_la_SOURCES = \ + test-helpers.c + +AM_CPPFLAGS = -I$(top_builddir)/src -I$(top_srcdir)/src +AM_CFLAGS = $(GCC_CFLAGS) diff --git a/tests/test-runner/test-helpers.c b/tests/test-runner/test-helpers.c new file mode 100644 index 0000000..4761b09 --- /dev/null +++ b/tests/test-runner/test-helpers.c @@ -0,0 +1,64 @@ +/* + * Copyright © 2012 Collabora, Ltd. + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that copyright + * notice and this permission notice appear in supporting documentation, and + * that the name of the copyright holders not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. The copyright holders make no representations + * about the suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +#include <assert.h> +#include <errno.h> +#include <dirent.h> +#include <stdio.h> +#include <unistd.h> + +#include "test-runner.h" + +int +count_open_fds(void) +{ + DIR *dir; + struct dirent *ent; + int count = 0; + + dir = opendir("/proc/self/fd"); + assert(dir && "opening /proc/self/fd failed."); + + errno = 0; + while ((ent = readdir(dir))) { + const char *s = ent->d_name; + if (s[0] == '.' && (s[1] == 0 || (s[1] == '.' && s[2] == 0))) + continue; + count++; + } + assert(errno == 0 && "reading /proc/self/fd failed."); + + closedir(dir); + + return count; +} + +void +exec_fd_leak_check(int nr_expected_fds) +{ + const char *exe = "./exec-fd-leak-checker"; + char number[16] = { 0 }; + + snprintf(number, sizeof number - 1, "%d", nr_expected_fds); + execl(exe, exe, number, (char *)NULL); + assert(0 && "execing fd leak checker failed"); +} diff --git a/tests/test-runner/test-runner.c b/tests/test-runner/test-runner.c new file mode 100644 index 0000000..8f3d5d3 --- /dev/null +++ b/tests/test-runner/test-runner.c @@ -0,0 +1,207 @@ +/* + * Copyright © 2012 Intel Corporation + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that copyright + * notice and this permission notice appear in supporting documentation, and + * that the name of the copyright holders not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. The copyright holders make no representations + * about the suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +#define _GNU_SOURCE + +#include <unistd.h> +#include <stdio.h> +#include <stdlib.h> +#include <sys/types.h> +#include <sys/wait.h> +#include <string.h> +#include <assert.h> +#include <dlfcn.h> +#include <errno.h> +#include "test-runner.h" + +static int num_alloc; +static void* (*sys_malloc)(size_t); +static void (*sys_free)(void*); +static void* (*sys_realloc)(void*, size_t); +static void* (*sys_calloc)(size_t, size_t); + +int leak_check_enabled; + +extern const struct test __start_test_section, __stop_test_section; + +__attribute__ ((visibility("default"))) void * +malloc(size_t size) +{ + num_alloc++; + return sys_malloc(size); +} + +__attribute__ ((visibility("default"))) void +free(void* mem) +{ + if (mem != NULL) + num_alloc--; + sys_free(mem); +} + +__attribute__ ((visibility("default"))) void * +realloc(void* mem, size_t size) +{ + if (mem == NULL) + num_alloc++; + return sys_realloc(mem, size); +} + +__attribute__ ((visibility("default"))) void * +calloc(size_t nmemb, size_t size) +{ + if (sys_calloc == NULL) + return NULL; + + num_alloc++; + + return sys_calloc(nmemb, size); +} + +static const struct test * +find_test(const char *name) +{ + const struct test *t; + + for (t = &__start_test_section; t < &__stop_test_section; t++) + if (strcmp(t->name, name) == 0) + return t; + + return NULL; +} + +static void +usage(const char *name, int status) +{ + const struct test *t; + + fprintf(stderr, "Usage: %s [TEST]\n\n" + "With no arguments, run all test. Specify test case to run\n" + "only that test without forking. Available tests:\n\n", + name); + + for (t = &__start_test_section; t < &__stop_test_section; t++) + fprintf(stderr, " %s\n", t->name); + + fprintf(stderr, "\n"); + + exit(status); +} + +static void +run_test(const struct test *t) +{ + int cur_alloc = num_alloc; + int cur_fds, num_fds; + + cur_fds = count_open_fds(); + t->run(); + if (leak_check_enabled) { + if (cur_alloc != num_alloc) { + fprintf(stderr, "Memory leak detected in test. " + "Allocated %d blocks, unfreed %d\n", num_alloc, + num_alloc - cur_alloc); + abort(); + } + num_fds = count_open_fds(); + if (cur_fds != num_fds) { + fprintf(stderr, "fd leak detected in test. " + "Opened %d files, unclosed %d\n", num_fds, + num_fds - cur_fds); + abort(); + } + } + exit(EXIT_SUCCESS); +} + +int main(int argc, char *argv[]) +{ + const struct test *t; + pid_t pid; + int total, pass; + siginfo_t info; + + /* Load system malloc, free, and realloc */ + sys_calloc = dlsym(RTLD_NEXT, "calloc"); + sys_realloc = dlsym(RTLD_NEXT, "realloc"); + sys_malloc = dlsym(RTLD_NEXT, "malloc"); + sys_free = dlsym(RTLD_NEXT, "free"); + + leak_check_enabled = !getenv("NO_ASSERT_LEAK_CHECK"); + + if (argc == 2 && strcmp(argv[1], "--help") == 0) + usage(argv[0], EXIT_SUCCESS); + + if (argc == 2) { + t = find_test(argv[1]); + if (t == NULL) { + fprintf(stderr, "unknown test: \"%s\"\n", argv[1]); + usage(argv[0], EXIT_FAILURE); + } + + run_test(t); + } + + pass = 0; + for (t = &__start_test_section; t < &__stop_test_section; t++) { + int success = 0; + + pid = fork(); + assert(pid >= 0); + + if (pid == 0) + run_test(t); /* never returns */ + + if (waitid(P_ALL, 0, &info, WEXITED)) { + fprintf(stderr, "waitid failed: %m\n"); + abort(); + } + + fprintf(stderr, "test \"%s\":\t", t->name); + switch (info.si_code) { + case CLD_EXITED: + fprintf(stderr, "exit status %d", info.si_status); + if (info.si_status == EXIT_SUCCESS) + success = 1; + break; + case CLD_KILLED: + case CLD_DUMPED: + fprintf(stderr, "signal %d", info.si_status); + break; + } + + if (t->must_fail) + success = !success; + + if (success) { + pass++; + fprintf(stderr, ", pass.\n"); + } else + fprintf(stderr, ", fail.\n"); + } + + total = &__stop_test_section - &__start_test_section; + fprintf(stderr, "%d tests, %d pass, %d fail\n", + total, pass, total - pass); + + return pass == total ? EXIT_SUCCESS : EXIT_FAILURE; +} diff --git a/tests/test-runner/test-runner.h b/tests/test-runner/test-runner.h new file mode 100644 index 0000000..707504c --- /dev/null +++ b/tests/test-runner/test-runner.h @@ -0,0 +1,40 @@ +#ifndef _TEST_RUNNER_H_ +#define _TEST_RUNNER_H_ + +#ifdef NDEBUG +#error "Tests must not be built with NDEBUG defined, they rely on assert()." +#endif + +struct test { + const char *name; + void (*run)(void); + int must_fail; +} __attribute__ ((aligned (16))); + +#define TEST(name) \ + static void name(void); \ + \ + const struct test test##name \ + __attribute__ ((section ("test_section"))) = { \ + #name, name, 0 \ + }; \ + \ + static void name(void) + +#define FAIL_TEST(name) \ + static void name(void); \ + \ + const struct test test##name \ + __attribute__ ((section ("test_section"))) = { \ + #name, name, 1 \ + }; \ + \ + static void name(void) + +int +count_open_fds(void); + +void +exec_fd_leak_check(int nr_expected_fds); /* never returns */ + +#endif -- 1.8.4.2 _______________________________________________ wayland-devel mailing list wayland-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/wayland-devel