From 6b5d4f95d6362980de98a37041d4007281ee5585 Mon Sep 17 00:00:00 2001 From: Snaipe Date: Mon, 23 Mar 2015 00:09:21 +0100 Subject: [PATCH] Refactored outputting logic out of the report hook code --- Makefile.am | 2 + include/criterion/logging.h | 18 ++++++++ include/criterion/options.h | 2 +- src/log/normal.c | 77 ++++++++++++++++++++++++++++++++ src/log/tap.c | 85 +++++++++++++++++++++++++++++++++++ src/main.c | 8 +++- src/report.c | 89 +++++-------------------------------- 7 files changed, 201 insertions(+), 80 deletions(-) create mode 100644 src/log/normal.c create mode 100644 src/log/tap.c diff --git a/Makefile.am b/Makefile.am index 5646b3b..eb35753 100644 --- a/Makefile.am +++ b/Makefile.am @@ -45,6 +45,8 @@ libcriterion_la_SOURCES = \ src/stats.c \ src/stats.h \ src/logging.c \ + src/log/tap.c \ + src/log/normal.c \ src/options.c \ src/timer.c \ src/timer.h \ diff --git a/include/criterion/logging.h b/include/criterion/logging.h index c810933..25f389a 100644 --- a/include/criterion/logging.h +++ b/include/criterion/logging.h @@ -26,6 +26,7 @@ # include # include "common.h" +# include "ordered-set.h" enum criterion_logging_level { CRITERION_INFO = 1, @@ -38,4 +39,21 @@ void criterion_log(enum criterion_logging_level level, const char *msg, ...); # define criterion_info(...) criterion_log(CRITERION_INFO, __VA_ARGS__) # define criterion_important(...) criterion_log(CRITERION_IMPORTANT, __VA_ARGS__) +struct criterion_output_provider { + void (*log_pre_all )(struct criterion_test_set *set); + void (*log_pre_init )(struct criterion_test *test); + void (*log_pre_test )(struct criterion_test *test); + void (*log_assert )(struct criterion_assert_stats *stats); + void (*log_test_crash)(struct criterion_test_stats *stats); + void (*log_post_test )(struct criterion_test_stats *stats); + void (*log_post_fini )(struct criterion_test_stats *stats); + void (*log_post_all )(struct criterion_global_stats *stats); +}; + +extern struct criterion_output_provider normal_logging; +extern struct criterion_output_provider tap_logging; + +#define NORMAL_LOGGING (&normal_logging) +#define TAP_LOGGING (&tap_logging) + #endif /* !CRITERION_LOGGING_H_ */ diff --git a/include/criterion/options.h b/include/criterion/options.h index ca622a7..3e2dee6 100644 --- a/include/criterion/options.h +++ b/include/criterion/options.h @@ -29,7 +29,7 @@ struct criterion_options { enum criterion_logging_level logging_threshold; - bool enable_tap_format; + struct criterion_output_provider *output_provider; bool no_early_exit; bool always_succeed; bool use_ascii; diff --git a/src/log/normal.c b/src/log/normal.c new file mode 100644 index 0000000..8e6345d --- /dev/null +++ b/src/log/normal.c @@ -0,0 +1,77 @@ +/* + * 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. + */ +#define _GNU_SOURCE +#include +#include "criterion/stats.h" +#include "criterion/logging.h" +#include "criterion/options.h" +#include "criterion/ordered-set.h" +#include "timer.h" + +void normal_log_pre_init(struct criterion_test *test) { + criterion_info("%s::%s: RUNNING\n", test->category, test->name); +} + +void normal_log_post_test(struct criterion_test_stats *stats) { + const char *format = can_measure_time() ? "%s::%s: %s (%3.2fs)\n" : "%s::%s: %s\n"; + criterion_log(stats->failed ? CRITERION_IMPORTANT : CRITERION_INFO, + format, + stats->test->category, + stats->test->name, + stats->failed ? "FAILURE" : "SUCCESS", + stats->elapsed_time); +} + +void normal_log_post_all(struct criterion_global_stats *stats) { + criterion_important("Synthesis: " SIZE_T_FORMAT " tests were run. " SIZE_T_FORMAT " passed, " SIZE_T_FORMAT " failed (with " SIZE_T_FORMAT " crashes)\n", + stats->nb_tests, + stats->tests_passed, + stats->tests_failed, + stats->tests_crashed); +} + +void normal_log_assert(struct criterion_assert_stats *stats) { + if (!stats->passed) { + criterion_important("%s:%d: Assertion failed: %s\n", + stats->file, + stats->line, + *stats->message ? stats->message : stats->condition); + } +} + +void normal_log_test_crash(struct criterion_test_stats *stats) { + criterion_important("Unexpected signal after %s:%u!\n%s::%s: FAILURE (CRASH!)\n", + stats->file, + stats->progress, + stats->test->category, + stats->test->name); +} + +struct criterion_output_provider normal_logging = { + .log_pre_init = normal_log_pre_init, + .log_post_test = normal_log_post_test, + .log_assert = normal_log_assert, + .log_post_all = normal_log_post_all, + .log_test_crash = normal_log_test_crash, +}; diff --git a/src/log/tap.c b/src/log/tap.c new file mode 100644 index 0000000..498789b --- /dev/null +++ b/src/log/tap.c @@ -0,0 +1,85 @@ +/* + * 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. + */ +#define _GNU_SOURCE +#include +#include "criterion/stats.h" +#include "criterion/logging.h" +#include "criterion/options.h" +#include "criterion/ordered-set.h" +#include "timer.h" + +static size_t tap_test_index = 1; + +void tap_log_pre_all(struct criterion_test_set *set) { + size_t enabled_count = 0; + FOREACH_SET(struct criterion_suite_set *s, set->suites) { + if ((s->suite.data && s->suite.data->disabled) || !s->tests) + continue; + + FOREACH_SET(struct criterion_test *test, s->tests) { + if (!test->data->disabled) + ++enabled_count; + } + } + criterion_important("1.." SIZE_T_FORMAT "\n", enabled_count); +} + +void tap_log_post_test(struct criterion_test_stats *stats) { + const char *format = can_measure_time() ? "%s " SIZE_T_FORMAT " - %s::%s (%3.2fs)\n" + : "%s " SIZE_T_FORMAT " - %s::%s\n"; + criterion_important(format, + stats->failed ? "not ok" : "ok", + tap_test_index++, + stats->test->category, + stats->test->name, + stats->elapsed_time); + for (struct criterion_assert_stats *asrt = stats->asserts; asrt; asrt = asrt->next) { + if (!asrt->passed) { + char *dup = strdup(*asrt->message ? asrt->message : asrt->condition), *saveptr = NULL; + char *line = strtok_r(dup, "\n", &saveptr); + criterion_important("\t%s:%u: Assertion failed: %s\n", + asrt->file, + asrt->line, + line); + while ((line = strtok_r(NULL, "\n", &saveptr))) + criterion_important("\t%s\n", line); + free(dup); + } + } +} + +void tap_log_test_crash(struct criterion_test_stats *stats) { + criterion_important("not ok " SIZE_T_FORMAT " - %s::%s unexpected signal after %s:%u\n", + tap_test_index++, + stats->test->category, + stats->test->name, + stats->file, + stats->progress); +} + +struct criterion_output_provider tap_logging = { + .log_pre_all = tap_log_pre_all, + .log_test_crash = tap_log_test_crash, + .log_post_test = tap_log_post_test, +}; diff --git a/src/main.c b/src/main.c index 63a6631..50d8571 100644 --- a/src/main.c +++ b/src/main.c @@ -121,28 +121,32 @@ int main(int argc, char *argv[]) { criterion_options = (struct criterion_options) { .always_succeed = !strcmp("1", getenv("CRITERION_ALWAYS_SUCCEED") ?: "0"), .no_early_exit = !strcmp("1", getenv("CRITERION_NO_EARLY_EXIT") ?: "0"), - .enable_tap_format = !strcmp("1", getenv("CRITERION_ENABLE_TAP") ?: "0"), .logging_threshold = atoi(getenv("CRITERION_VERBOSITY_LEVEL") ?: "2"), + .output_provider = NORMAL_LOGGING, }; + bool use_tap = !strcmp("1", getenv("CRITERION_ENABLE_TAP") ?: "0"); + bool do_list_tests = false; bool do_print_version = false; bool do_print_usage = false; for (int c; (c = getopt_long(argc, argv, "hvlf", opts, NULL)) != -1;) { switch (c) { case 'b': criterion_options.logging_threshold = atoi(optarg ?: "1"); break; - case 't': criterion_options.enable_tap_format = true; break; case 'y': criterion_options.always_succeed = true; break; case 'z': criterion_options.no_early_exit = true; break; case 'k': criterion_options.use_ascii = true; break; case 'f': criterion_options.fail_fast = true; break; case 'p': criterion_options.pattern = optarg; break; + case 't': use_tap = true; break; case 'l': do_list_tests = true; break; case 'v': do_print_version = true; break; case 'h': default : do_print_usage = true; break; } } + if (use_tap) + criterion_options.output_provider = TAP_LOGGING; if (do_print_usage) return print_usage(argv[0]); if (do_print_version) diff --git a/src/report.c b/src/report.c index 7494f0a..770d19a 100644 --- a/src/report.c +++ b/src/report.c @@ -42,7 +42,8 @@ } \ } -static size_t tap_test_index = 1; +#define log(Type, Arg) \ + (criterion_options.output_provider->log_ ## Type ?: nothing)(Arg); IMPL_CALL_REPORT_HOOKS(PRE_ALL); IMPL_CALL_REPORT_HOOKS(PRE_INIT); @@ -53,44 +54,15 @@ IMPL_CALL_REPORT_HOOKS(POST_TEST); IMPL_CALL_REPORT_HOOKS(POST_FINI); IMPL_CALL_REPORT_HOOKS(POST_ALL); -ReportHook(PRE_INIT)(struct criterion_test *test) { - if (criterion_options.enable_tap_format) return; +__attribute__((always_inline)) +static inline void nothing() {} - criterion_info("%s::%s: RUNNING\n", test->category, test->name); +ReportHook(PRE_INIT)(struct criterion_test *test) { + log(pre_init, test); } ReportHook(POST_TEST)(struct criterion_test_stats *stats) { - if (criterion_options.enable_tap_format) { - const char *format = can_measure_time() ? "%s " SIZE_T_FORMAT " - %s::%s (%3.2fs)\n" - : "%s " SIZE_T_FORMAT " - %s::%s\n"; - criterion_important(format, - stats->failed ? "not ok" : "ok", - tap_test_index++, - stats->test->category, - stats->test->name, - stats->elapsed_time); - for (struct criterion_assert_stats *asrt = stats->asserts; asrt; asrt = asrt->next) { - if (!asrt->passed) { - char *dup = strdup(*asrt->message ? asrt->message : asrt->condition), *saveptr = NULL; - char *line = strtok_r(dup, "\n", &saveptr); - criterion_important("\t%s:%u: Assertion failed: %s\n", - asrt->file, - asrt->line, - line); - while ((line = strtok_r(NULL, "\n", &saveptr))) - criterion_important("\t%s\n", line); - free(dup); - } - } - } else { - const char *format = can_measure_time() ? "%s::%s: %s (%3.2fs)\n" : "%s::%s: %s\n"; - criterion_log(stats->failed ? CRITERION_IMPORTANT : CRITERION_INFO, - format, - stats->test->category, - stats->test->name, - stats->failed ? "FAILURE" : "SUCCESS", - stats->elapsed_time); - } + log(post_test, stats); } ReportHook(PRE_TEST)() {} @@ -112,54 +84,17 @@ ReportHook(PRE_ALL)(struct criterion_test_set *set) { } } } - if (criterion_options.enable_tap_format) { - size_t enabled_count = 0; - FOREACH_SET(struct criterion_suite_set *s, set->suites) { - if ((s->suite.data && s->suite.data->disabled) || !s->tests) - continue; - - FOREACH_SET(struct criterion_test *test, s->tests) { - if (!test->data->disabled) - ++enabled_count; - } - } - criterion_important("1.." SIZE_T_FORMAT "\n", enabled_count); - } + log(pre_all, set); } -ReportHook(POST_ALL)(struct criterion_global_stats *stats) { - if (criterion_options.enable_tap_format) return; - criterion_important("Synthesis: " SIZE_T_FORMAT " tests were run. " SIZE_T_FORMAT " passed, " SIZE_T_FORMAT " failed (with " SIZE_T_FORMAT " crashes)\n", - stats->nb_tests, - stats->tests_passed, - stats->tests_failed, - stats->tests_crashed); +ReportHook(POST_ALL)(struct criterion_global_stats *stats) { + log(post_all, stats); } ReportHook(ASSERT)(struct criterion_assert_stats *stats) { - if (criterion_options.enable_tap_format) return; - - if (!stats->passed) { - criterion_important("%s:%d: Assertion failed: %s\n", - stats->file, - stats->line, - *stats->message ? stats->message : stats->condition); - } + log(assert, stats); } ReportHook(TEST_CRASH)(struct criterion_test_stats *stats) { - if (criterion_options.enable_tap_format) { - criterion_important("not ok " SIZE_T_FORMAT " - %s::%s unexpected signal after %s:%u\n", - tap_test_index++, - stats->test->category, - stats->test->name, - stats->file, - stats->progress); - } else { - criterion_important("Unexpected signal after %s:%u!\n%s::%s: FAILURE (CRASH!)\n", - stats->file, - stats->progress, - stats->test->category, - stats->test->name); - } + log(test_crash, stats); }