From 7db8b3f413e1ea95fd89ce463f1b731f7ce810d0 Mon Sep 17 00:00:00 2001 From: Snaipe Date: Thu, 5 Feb 2015 18:09:21 +0100 Subject: [PATCH] Added event system to push reporting back to the parent process --- Makefile | 2 +- include/{ => criterion}/assert.h | 31 ++------------ include/{ => criterion}/common.h | 0 include/{ => criterion}/criterion.h | 0 include/criterion/event.h | 31 ++++++++++++++ include/{ => criterion}/hooks.h | 2 + include/criterion/stats.h | 43 +++++++++++++++++++ samples/simple.c | 20 +++++++-- src/event.c | 64 +++++++++++++++++++++++++++++ src/event.h | 36 ++++++++++++++++ src/report.c | 5 ++- src/report.h | 2 +- src/runner.c | 54 ++++++++++++++++++------ src/runner.h | 2 +- 14 files changed, 244 insertions(+), 48 deletions(-) rename include/{ => criterion}/assert.h (71%) rename include/{ => criterion}/common.h (100%) rename include/{ => criterion}/criterion.h (100%) create mode 100644 include/criterion/event.h rename include/{ => criterion}/hooks.h (98%) create mode 100644 include/criterion/stats.h create mode 100644 src/event.c create mode 100644 src/event.h diff --git a/Makefile b/Makefile index 909ad10..f733361 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ CC = gcc CFLAGS = -Wall -Wextra -std=gnu99 -Isrc/ -Iinclude/ -g -SRCS = runner.c report.c +SRCS = runner.c report.c event.c OBJS = $(addprefix src/,$(subst .c,.o,$(SRCS))) sample: samples/simple.o libcriterion.a diff --git a/include/assert.h b/include/criterion/assert.h similarity index 71% rename from include/assert.h rename to include/criterion/assert.h index be13d3c..a4bdd6a 100644 --- a/include/assert.h +++ b/include/criterion/assert.h @@ -27,49 +27,24 @@ # include # include # include "criterion.h" +# include "event.h" enum criterion_assert_kind { NORMAL, FATAL }; -struct criterion_assert_stat { - enum criterion_assert_kind kind; - const char *condition; - const char *message; - bool passed; - unsigned line; - - struct criterion_assert_stat *next; -}; - -struct criterion_test_stats { - struct criterion_test *test; - struct criterion_assert_stat *asserts; - unsigned failed; - unsigned passed; -}; - -extern struct criterion_test_stats g_current_test_stats; - # define assertImpl(Kind, Condition, ...) \ do { \ int passed = !!(Condition); \ - struct criterion_assert_stat *stat = \ - malloc(sizeof (struct criterion_assert_stat)); \ - *stat = (struct criterion_assert_stat) { \ + struct criterion_assert_stat stat = { \ .kind = Kind, \ .condition = #Condition, \ .message = "" __VA_ARGS__, \ .passed = passed, \ .line = __LINE__, \ - .next = g_current_test_stats.asserts, \ }; \ - g_current_test_stats.asserts = stat; \ - if (passed) \ - ++g_current_test_stats.passed; \ - else \ - ++g_current_test_stats.failed; \ + send_event(ASSERT, &stat, sizeof (stat)); \ if (!passed && Kind == FATAL) \ return; \ } while (0) diff --git a/include/common.h b/include/criterion/common.h similarity index 100% rename from include/common.h rename to include/criterion/common.h diff --git a/include/criterion.h b/include/criterion/criterion.h similarity index 100% rename from include/criterion.h rename to include/criterion/criterion.h diff --git a/include/criterion/event.h b/include/criterion/event.h new file mode 100644 index 0000000..d509a8d --- /dev/null +++ b/include/criterion/event.h @@ -0,0 +1,31 @@ +/* + * The MIT License (MIT) + * + * Copyright © 2015 Franklin "Snaipe" Mathieu + * + * 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 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. + */ +#ifndef CRITERION_EVENT_H_ +# define CRITERION_EVENT_H_ + +extern const int EVENT_PIPE; + +void send_event(int kind, void *data, size_t size); + +#endif /* !CRITERION_EVENT_H_ */ diff --git a/include/hooks.h b/include/criterion/hooks.h similarity index 98% rename from include/hooks.h rename to include/criterion/hooks.h index ab562aa..129e7c1 100644 --- a/include/hooks.h +++ b/include/criterion/hooks.h @@ -30,6 +30,8 @@ typedef enum { PRE_EVERYTHING, PRE_INIT, PRE_TEST, + ASSERT, + TEST_CRASH, POST_TEST, POST_FINI, POST_EVERYTHING, diff --git a/include/criterion/stats.h b/include/criterion/stats.h new file mode 100644 index 0000000..4f0cd58 --- /dev/null +++ b/include/criterion/stats.h @@ -0,0 +1,43 @@ +/* + * The MIT License (MIT) + * + * Copyright © 2015 Franklin "Snaipe" Mathieu + * + * 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 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. + */ +#ifndef CRITERION_STATS_H_ +# define CRITERION_STATS_H_ + +# include "criterion.h" + +struct criterion_assert_stat { + int kind; + const char *condition; + const char *message; + bool passed; + unsigned line; +}; + +struct criterion_test_stats { + struct criterion_test *test; + int passed; + int failed; +}; + +#endif /* !CRITERION_STATS_H_ */ diff --git a/samples/simple.c b/samples/simple.c index 01fb583..2f153df 100644 --- a/samples/simple.c +++ b/samples/simple.c @@ -1,8 +1,9 @@ #include #include -#include "criterion.h" -#include "report.h" -#include "assert.h" +#include +#include +#include +#include Test(misc, failing) { assert(1); @@ -13,6 +14,19 @@ Test(misc, simple) { expect(1); } +Test(aziezdcjn, simple) { + expect(1); +} +Test(aziezdcjn, abcd) { + expect(1); +} +Test(aziezdcjn, simplez) { + expect(1); +} +Test(aziezdcjn, simpl) { + expect(1); +} + ReportHook(PRE_INIT)(struct criterion_test *test) { printf("testing %s in category %s\n", test->name, test->category); } diff --git a/src/event.c b/src/event.c new file mode 100644 index 0000000..8736d8d --- /dev/null +++ b/src/event.c @@ -0,0 +1,64 @@ +/* + * The MIT License (MIT) + * + * Copyright © 2015 Franklin "Snaipe" Mathieu + * + * 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 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 "criterion/assert.h" +#undef assert + +#include +#include +#include +#include +#include "criterion/criterion.h" +#include "criterion/stats.h" +#include "criterion/hooks.h" +#include "event.h" + +const int EVENT_PIPE = 3; + +void destroy_event(void *ptr, UNUSED void *meta) { + struct event *ev = ptr; + free(ev->data); +} + +struct event *read_event(int fd) { + unsigned kind; + if (read(fd, &kind, sizeof (unsigned)) < (ssize_t) sizeof (unsigned)) + return NULL; + + if (kind != ASSERT) + return unique_ptr(struct event, ({ .kind = kind, .data = NULL })); + + const size_t assert_size = sizeof (struct criterion_assert_stat); + unsigned char *buf = malloc(assert_size); + if (read(fd, buf, assert_size) < (ssize_t) assert_size) + return NULL; + + return unique_ptr(struct event, ({ .kind = kind, .data = buf }), destroy_event); +} + +void send_event(int kind, void *data, size_t size) { + unsigned char buf[sizeof (int) + size]; + memcpy(buf, &kind, sizeof (int)); + memcpy(buf + sizeof (int), data, size); + write(EVENT_PIPE, buf, sizeof (buf)); +} diff --git a/src/event.h b/src/event.h new file mode 100644 index 0000000..405df73 --- /dev/null +++ b/src/event.h @@ -0,0 +1,36 @@ +/* + * The MIT License (MIT) + * + * Copyright © 2015 Franklin "Snaipe" Mathieu + * + * 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 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. + */ +#ifndef EVENT_H_ +# define EVENT_H_ + +# include "criterion/event.h" + +struct event { + int kind; + void *data; +}; + +struct event *read_event(int fd); + +#endif /* !EVENT_H_ */ diff --git a/src/report.c b/src/report.c index 19af069..37e6ab0 100644 --- a/src/report.c +++ b/src/report.c @@ -22,7 +22,8 @@ * THE SOFTWARE. */ #include -#include "criterion.h" +#include "criterion/criterion.h" +#include "criterion/stats.h" #include "report.h" #define IMPL_CALL_REPORT_HOOKS(Kind) \ @@ -60,3 +61,5 @@ ReportHook(POST_FINI)() {} ReportHook(PRE_EVERYTHING)() {} ReportHook(POST_EVERYTHING)() {} + + diff --git a/src/report.h b/src/report.h index 77c140d..e0c1b44 100644 --- a/src/report.h +++ b/src/report.h @@ -24,7 +24,7 @@ #ifndef REPORT_H_ # define REPORT_H_ -# include "hooks.h" +# include "criterion/hooks.h" # define report(Kind, Data) call_report_hooks_##Kind(Data) diff --git a/src/runner.c b/src/runner.c index 3a14d8d..732b20d 100644 --- a/src/runner.c +++ b/src/runner.c @@ -22,13 +22,15 @@ * THE SOFTWARE. */ #include +#include #include #include -#include #include +#include "criterion/assert.h" +#include "criterion/stats.h" #include "runner.h" #include "report.h" -#include "assert.h" +#include "event.h" static struct criterion_test * const g_section_start = &__start_criterion_tests; static struct criterion_test * const g_section_end = &__stop_criterion_tests; @@ -92,31 +94,57 @@ static void map_tests(struct test_set *set, void (*fun)(struct criterion_test *) __attribute__ ((always_inline)) static inline void nothing() {} -struct criterion_test_stats g_current_test_stats; - -static void run_test_nofork(struct criterion_test *test) { - report(PRE_INIT, test); +static void run_test_child(struct criterion_test *test) { + send_event(PRE_INIT, NULL, 0); (test->data->init ?: nothing)(); - report(PRE_TEST, test); - - g_current_test_stats = (struct criterion_test_stats) { .test = test }; + send_event(PRE_TEST, NULL, 0); (test->test ?: nothing)(); - - report(POST_TEST, &g_current_test_stats); + send_event(POST_TEST, NULL, 0); (test->data->fini ?: nothing)(); - report(POST_FINI, test); + send_event(POST_FINI, NULL, 0); +} + +struct pipefds { + int in, out; +} __attribute__ ((packed)); + +static void setup_child(struct pipefds *fds) { + close(STDIN_FILENO); + close(fds->in); + dup2(fds->out, EVENT_PIPE); + close(fds->out); } static void run_test(struct criterion_test *test) { + struct pipefds fds; + if (pipe((int*) &fds) == -1) + abort(); + pid_t pid; if (!(pid = fork())) { - run_test_nofork(test); + setup_child(&fds); + + run_test_child(test); exit(0); } else { + struct criterion_test_stats stats = { .test = test }; + close(fds.out); + struct event *ev; + while ((ev = read_event(fds.in)) != NULL) { + switch (ev->kind) { + case PRE_INIT: report(PRE_INIT, test); break; + case PRE_TEST: report(PRE_TEST, test); break; + case ASSERT: report(PRE_TEST, ev->data); break; + case POST_TEST: report(POST_TEST, &stats); break; + case POST_FINI: report(POST_FINI, test); break; + } + sfree(ev); + } waitpid(pid, NULL, 0); } } +// TODO: disable & change tests at runtime void run_all(void) { report(PRE_EVERYTHING, NULL); smart struct test_set *set = read_all_tests(); diff --git a/src/runner.h b/src/runner.h index 3d252f4..6723104 100644 --- a/src/runner.h +++ b/src/runner.h @@ -24,7 +24,7 @@ #ifndef CRITERION_RUNNER_H_ # define CRITERION_RUNNER_H_ -# include "criterion.h" +# include "criterion/criterion.h" extern struct criterion_test __start_criterion_tests; extern struct criterion_test __stop_criterion_tests;