Refactored outputting logic out of the report hook code

This commit is contained in:
Snaipe 2015-03-23 00:09:21 +01:00
parent 6a7161598c
commit 6b5d4f95d6
7 changed files with 201 additions and 80 deletions

View file

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

View file

@ -26,6 +26,7 @@
# include <stdbool.h>
# 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_ */

View file

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

77
src/log/normal.c Normal file
View file

@ -0,0 +1,77 @@
/*
* The MIT License (MIT)
*
* Copyright © 2015 Franklin "Snaipe" Mathieu <http://snai.pe/>
*
* 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 <stdio.h>
#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,
};

85
src/log/tap.c Normal file
View file

@ -0,0 +1,85 @@
/*
* The MIT License (MIT)
*
* Copyright © 2015 Franklin "Snaipe" Mathieu <http://snai.pe/>
*
* 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 <stdio.h>
#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,
};

View file

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

View file

@ -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);
}