[Issue #68] Merge branch 'features/new-reporting' into bleeding

Changelog:

~ Overhauls the output reporting system
+ Adds registration of user defined output reporters
+ Adds --output CLI switch
+ Adds --quiet CLI switch
- Removes CRITERION_ENABLE_{TAP,XML} environment variables
This commit is contained in:
Snaipe 2015-11-11 12:51:53 +01:00
commit 8624880183
19 changed files with 323 additions and 86 deletions

3
.gitmodules vendored
View file

@ -7,3 +7,6 @@
[submodule "dependencies/wingetopt"]
path = dependencies/wingetopt
url = https://github.com/alex85k/wingetopt.git
[submodule "dependencies/klib"]
path = dependencies/klib
url = https://github.com/attractivechaos/klib.git

View file

@ -23,6 +23,7 @@ include_directories(
dependencies/libcsptr/include/
dependencies/dyncall/dyncall/
dependencies/valgrind/include/
dependencies/klib/
)
if (MSVC)
@ -130,10 +131,12 @@ set(SOURCE_FILES
src/io/event.h
src/io/asprintf.c
src/io/file.c
src/io/output.c
src/io/output.h
src/io/tap.c
src/io/xml.c
src/log/logging.c
src/log/tap.c
src/log/normal.c
src/log/xml.c
src/string/i18n.c
src/string/i18n.h
src/entry/options.c
@ -170,6 +173,7 @@ set(INTERFACE_FILES
include/criterion/alloc.h
include/criterion/parameterized.h
include/criterion/redirect.h
include/criterion/output.h
)
# Generate the configure file

1
dependencies/klib vendored Submodule

@ -0,0 +1 @@
Subproject commit cdb7e9236dc47abf8da7ebd702cc6f7f21f0c502

View file

@ -8,6 +8,7 @@ Command line arguments
----------------------
* ``-h or --help``: Show a help message with the available switches.
* ``-q or --quiet``: Disables all logging.
* ``-v or --version``: Prints the version of criterion that has been
linked against.
* ``-l or --list``: Print all the tests in a list.
@ -22,10 +23,17 @@ Command line arguments
This is useful when tracking memory leaks with ``valgrind --tool=memcheck``.
* ``-S or --short-filename``: The filenames are displayed in their short form.
* ``--always-succeed``: The process shall exit with a status of ``0``.
* ``--tap``: Enables the TAP (Test Anything Protocol) output format.
* ``--xml``: Enables the JUnit4 XML output format.
* ``--tap[=FILE]``: Writes a TAP (Test Anything Protocol) report to FILE.
No file or ``"-"`` means ``stderr``. This option is equivalent to
``--output=tap:FILE``.
* ``--xml[=FILE]``: Writes JUnit4 XML report to FILE.
No file or ``"-"`` means ``stderr``. This option is equivalent to
``--output=xml:FILE``.
* ``--verbose[=level]``: Makes the output verbose. When provided with an integer,
sets the verbosity level to that integer.
* ``-OPROVIDER:FILE or --output=PROVIDER:FILE``: Write a test report to FILE
using the output provider named by PROVIDER. FILE may be a relative path, or
``"-"`` to write to ``stderr``.
Shell Wildcard Pattern
----------------------
@ -71,8 +79,6 @@ Environment variables are alternatives to command line switches when set to 1.
* ``CRITERION_ALWAYS_SUCCEED``: Same as ``--always-succeed``.
* ``CRITERION_NO_EARLY_EXIT``: Same as ``--no-early-exit``.
* ``CRITERION_ENABLE_TAP``: Same as ``--tap``.
* ``CRITERION_ENABLE_XML``: Same as ``--xml``.
* ``CRITERION_FAIL_FAST``: Same as ``--fail-fast``.
* ``CRITERION_USE_ASCII``: Same as ``--ascii``.
* ``CRITERION_JOBS``: Same as ``--jobs``. Sets the number of jobs to

View file

@ -10,6 +10,7 @@ Criterion
assert
hooks
env
output
parameterized
theories
internal

View file

@ -28,7 +28,7 @@ Field Type Description
=================== ================================== ==============================================================
logging_threshold enum criterion_logging_level The logging level
------------------- ---------------------------------- --------------------------------------------------------------
output_provider struct criterion_output_provider * The output provider (see below)
logger struct criterion_logger * The logger (see below)
------------------- ---------------------------------- --------------------------------------------------------------
no_early_exit bool True iff the test worker should exit early
------------------- ---------------------------------- --------------------------------------------------------------
@ -75,15 +75,15 @@ Example main
return result;
}
Implementing your own output provider
-------------------------------------
Implementing your own logger
----------------------------
In case you are not satisfied by the default output provider, you can implement
yours. To do so, simply set the ``output_provider`` option to your custom
output provider.
In case you are not satisfied by the default logger, you can implement
yours. To do so, simply set the ``logger`` option to your custom
logger.
Each function contained in the structure is called during one of the standard
phase of the criterion runner.
For more insight on how to implement this, see other existing output providers
For more insight on how to implement this, see other existing loggers
in ``src/log/``.

44
doc/output.rst Normal file
View file

@ -0,0 +1,44 @@
Writing tests reports in a custom format
========================================
Outputs providers are used to write tests reports in the format of your choice:
for instance, TAP and XML reporting are implemented with output providers.
Adding a custom output provider
-------------------------------
An output provider is a function with the following signature:
.. code-block:: c
void func(FILE *out, struct criterion_global_stats *stats);
Once implemented, you then need to register it as an output provider:
.. code-block:: c
criterion_register_output_provider("provider name", func);
This needs to be done before the test runner stops, so you may want to register
it either in a self-provided main, or in a PRE_ALL or POST_ALL report hook.
Writing to a file with an output provider
-----------------------------------------
To tell criterion to write a report to a specific file using the output provider
of your choice, you can either pass ``--output`` as a command-line
parameter:
.. code-block:: bash
./my_tests --output="provider name":/path/to/file
Or, you can do so directly by calling ``criterion_add_output`` before the
runner stops:
.. code-block:: c
criterion_add_output("provider name", "/path/to/file");
The path may be relative. If ``"-"`` is passed as a filename, the report will
be written to ``stderr``.

View file

@ -38,6 +38,8 @@ using std::va_list;
enum criterion_logging_level {
CRITERION_INFO = 1,
CRITERION_IMPORTANT,
CRITERION_LOG_LEVEL_QUIET = 1 << 30,
};
enum criterion_logging_prefix {
@ -101,7 +103,7 @@ CR_API void criterion_log(enum criterion_logging_level level, const char *msg, .
# define criterion_perror(...) criterion_plog(CRITERION_IMPORTANT, CRITERION_PREFIX_ERR, __VA_ARGS__)
struct criterion_output_provider {
struct criterion_logger {
void (*log_pre_all )(struct criterion_test_set *set);
void (*log_pre_suite )(struct criterion_suite_set *set);
void (*log_pre_init )(struct criterion_test *test);
@ -119,14 +121,10 @@ struct criterion_output_provider {
void (*log_post_all )(struct criterion_global_stats *stats);
};
extern struct criterion_output_provider normal_logging;
extern struct criterion_output_provider tap_logging;
extern struct criterion_output_provider xml_logging;
extern struct criterion_logger normal_logging;
CR_END_C_API
#define CR_NORMAL_LOGGING (&normal_logging)
#define CR_TAP_LOGGING (&tap_logging)
#define CR_XML_LOGGING (&xml_logging)
#endif /* !CRITERION_LOGGING_H_ */

View file

@ -29,7 +29,7 @@
struct criterion_options {
enum criterion_logging_level logging_threshold;
struct criterion_output_provider *output_provider;
struct criterion_logger *logger;
bool no_early_exit;
bool always_succeed;
bool use_ascii;

View file

@ -0,0 +1,34 @@
/*
* 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.
*/
#ifndef CRITERION_OUTPUT_H_
# define CRITERION_OUTPUT_H_
# include "stats.h"
typedef void criterion_reporter(FILE *stream, struct criterion_global_stats *);
int criterion_register_output_provider(const char *name, criterion_reporter *reporter);
int criterion_add_output(const char *provider, const char *path);
#endif /* !CRITERION_OUTPUT_H_ */

View file

@ -46,7 +46,7 @@ DECL_CALL_REPORT_HOOKS(POST_SUITE);
DECL_CALL_REPORT_HOOKS(POST_ALL);
#define log(Type, ...) \
log_(criterion_options.output_provider->log_ ## Type, __VA_ARGS__);
log_(criterion_options.logger->log_ ## Type, __VA_ARGS__);
#define log_(Log, ...) \
(Log ? Log(__VA_ARGS__) : nothing());

View file

@ -37,6 +37,7 @@
#include "wrappers/wrap.h"
#include "string/i18n.h"
#include "io/event.h"
#include "io/output.h"
#include "runner_coroutine.h"
#include "stats.h"
#include "runner.h"
@ -347,6 +348,9 @@ struct criterion_test_set *criterion_initialize(void) {
if (resume_child()) // (windows only) resume from the fork
exit(0);
criterion_register_output_provider("tap", tap_report);
criterion_register_output_provider("xml", xml_report);
return criterion_init();
}
@ -356,6 +360,8 @@ void criterion_finalize(struct criterion_test_set *set) {
#ifndef ENABLE_VALGRIND_ERRORS
VALGRIND_ENABLE_ERROR_REPORTING;
#endif
criterion_free_output();
}
static void run_tests_async(struct criterion_test_set *set,
@ -451,6 +457,8 @@ static int criterion_run_all_tests_impl(struct criterion_test_set *set) {
report(POST_ALL, stats);
log(post_all, stats);
process_all_output(stats);
cleanup:
sfree(g_worker_pipe);
sfree(stats);

View file

@ -29,7 +29,10 @@
#include "criterion/criterion.h"
#include "criterion/options.h"
#include "criterion/ordered-set.h"
#include "compat/posix.h"
#include "compat/strtok.h"
#include "core/runner.h"
#include "io/output.h"
#include "config.h"
#include "common.h"
@ -52,6 +55,7 @@
"usage: %s OPTIONS\n" \
"options: \n" \
" -h or --help: prints this message\n" \
" -q or --quiet: disables all logging\n" \
" -v or --version: prints the version of criterion " \
"these tests have been linked against\n" \
" -l or --list: prints all the tests in a list\n" \
@ -62,13 +66,17 @@
" -S or --short-filename: only display the base " \
"name of the source file on a failure\n" \
PATTERN_USAGE \
" --tap: enables TAP formatting\n" \
" --xml: enables XML formatting\n" \
" --tap[=FILE]: writes TAP report in FILE " \
"(no file or \"-\" means stderr)\n" \
" --xml[=FILE]: writes XML report in FILE " \
"(no file or \"-\" means stderr)\n" \
" --always-succeed: always exit with 0\n" \
" --no-early-exit: do not exit the test worker " \
"prematurely after the test\n" \
" --verbose[=level]: sets verbosity to level " \
"(1 by default)\n"
"(1 by default)\n" \
" -OP:F or --output=PROVIDER=FILE: write test " \
"report to FILE using the specified provider\n"
int print_usage(char *progname) {
fprintf(stderr, USAGE, progname);
@ -130,9 +138,10 @@ int atou(const char *str) {
int criterion_handle_args(int argc, char *argv[], bool handle_unknown_arg) {
static struct option opts[] = {
{"verbose", optional_argument, 0, 'b'},
{"quiet", no_argument, 0, 'q'},
{"version", no_argument, 0, 'v'},
{"tap", no_argument, 0, 't'},
{"xml", no_argument, 0, 'x'},
{"tap", optional_argument, 0, 't'},
{"xml", optional_argument, 0, 'x'},
{"help", no_argument, 0, 'h'},
{"list", no_argument, 0, 'l'},
{"ascii", no_argument, 0, 'k'},
@ -144,6 +153,7 @@ int criterion_handle_args(int argc, char *argv[], bool handle_unknown_arg) {
#endif
{"always-succeed", no_argument, 0, 'y'},
{"no-early-exit", no_argument, 0, 'z'},
{"output", required_argument, 0, 'O'},
{0, 0, 0, 0 }
};
@ -187,15 +197,13 @@ int criterion_handle_args(int argc, char *argv[], bool handle_unknown_arg) {
opt->pattern = env_pattern;
#endif
bool use_tap = !strcmp("1", DEF(getenv("CRITERION_ENABLE_TAP"), "0"));
bool use_xml = !strcmp("1", DEF(getenv("CRITERION_ENABLE_XML"), "0"));
opt->measure_time = !!strcmp("1", DEF(getenv("CRITERION_DISABLE_TIME_MEASUREMENTS"), "0"));
bool do_list_tests = false;
bool do_print_version = false;
bool do_print_usage = false;
for (int c; (c = getopt_long(argc, argv, "hvlfj:S", opts, NULL)) != -1;) {
bool quiet = false;
for (int c; (c = getopt_long(argc, argv, "hvlfj:SqO:", opts, NULL)) != -1;) {
switch (c) {
case 'b': criterion_options.logging_threshold = atou(DEF(optarg, "1")); break;
case 'y': criterion_options.always_succeed = true; break;
@ -207,19 +215,33 @@ int criterion_handle_args(int argc, char *argv[], bool handle_unknown_arg) {
#ifdef HAVE_PCRE
case 'p': criterion_options.pattern = optarg; break;
#endif
case 't': use_tap = true; break;
case 'x': use_xml = true; break;
case 'q': quiet = true; break;
case 't': quiet = true; criterion_add_output("tap", DEF(optarg, "-")); break;
case 'x': quiet = true; criterion_add_output("xml", DEF(optarg, "-")); break;
case 'l': do_list_tests = true; break;
case 'v': do_print_version = true; break;
case 'h': do_print_usage = true; break;
case 'O': {
char *arg = strdup(optarg);
char *buf = NULL;
strtok_r(arg, ":", &buf);
char *path = strtok_r(NULL, ":", &buf);
if (arg == NULL || path == NULL) {
do_print_usage = true;
break;
}
quiet = true;
criterion_add_output(arg, path);
} break;
case '?':
default : do_print_usage = handle_unknown_arg; break;
}
}
if (use_tap)
criterion_options.output_provider = CR_TAP_LOGGING;
else if (use_xml)
criterion_options.output_provider = CR_XML_LOGGING;
if (quiet)
criterion_options.logging_threshold = CRITERION_LOG_LEVEL_QUIET;
if (do_print_usage)
return print_usage(argv[0]);
if (do_print_version)

View file

@ -25,6 +25,6 @@
struct criterion_options criterion_options = {
.logging_threshold = CRITERION_IMPORTANT,
.output_provider = &normal_logging,
.logger = &normal_logging,
.measure_time = true,
};

89
src/io/output.c Normal file
View file

@ -0,0 +1,89 @@
#include <stdio.h>
#include <string.h>
#include <khash.h>
#include <kvec.h>
#include "criterion/output.h"
typedef kvec_t(const char *) str_vec;
KHASH_MAP_INIT_STR(ht_str, criterion_reporter*)
KHASH_MAP_INIT_STR(ht_path, str_vec*)
static khash_t(ht_str) *reporters;
static khash_t(ht_path) *outputs;
int criterion_register_output_provider(const char *name, criterion_reporter *reporter) {
if (!reporters)
reporters = kh_init(ht_str);
int absent;
khint_t k = kh_put(ht_str, reporters, name, &absent);
kh_value(reporters, k) = reporter;
return absent;
}
int criterion_add_output(const char *provider, const char *path) {
if (!outputs)
outputs = kh_init(ht_path);
khint_t k = kh_get(ht_path, outputs, provider);
if (k == kh_end(outputs)) {
int absent;
k = kh_put(ht_path, outputs, provider, &absent);
if (absent == -1)
return -1;
str_vec *vec = malloc(sizeof (str_vec));
kv_init(*vec);
kh_value(outputs, k) = vec;
}
str_vec *vec = kh_value(outputs, k);
kv_push(const char *, *vec, path);
return 1;
}
void criterion_free_output(void) {
if (reporters)
kh_destroy(ht_str, reporters);
if (outputs) {
for (khint_t k = kh_begin(outputs); k != kh_end(outputs); ++k) {
if (!kh_exist(outputs, k))
continue;
str_vec *vec = kh_value(outputs, k);
kv_destroy(*vec);
free(vec);
}
kh_destroy(ht_path, outputs);
}
}
void process_all_output(struct criterion_global_stats *stats) {
if (!outputs || !reporters)
return;
for (khint_t k = kh_begin(reporters); k != kh_end(reporters); ++k) {
if (!kh_exist(reporters, k))
continue;
criterion_reporter *report = kh_value(reporters, k);
khint_t ko = kh_get(ht_path, outputs, kh_key(reporters, k));
if (ko == kh_end(outputs))
continue;
str_vec *vec = kh_value(outputs, ko);
for (size_t i = 0; i < kv_size(*vec); ++i) {
const char *path = kv_A(*vec, i);
FILE *f;
if (path[0] == '-' && !path[1])
f = stderr;
else
f = fopen(path, "w");
report(f, stats);
}
}
}

35
src/io/output.h Normal file
View file

@ -0,0 +1,35 @@
/*
* 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.
*/
#ifndef OUTPUT_H_
# define OUTPUT_H_
# include "criterion/output.h"
void process_all_output(struct criterion_global_stats *stats);
void criterion_free_output(void);
void tap_report(FILE *f, struct criterion_global_stats *stats);
void xml_report(FILE *f, struct criterion_global_stats *stats);
#endif /* !OUTPUT_H_ */

View file

@ -26,24 +26,22 @@
#include <stdlib.h>
#include <string.h>
#include "criterion/stats.h"
#include "criterion/logging.h"
#include "criterion/options.h"
#include "criterion/ordered-set.h"
#include "compat/posix.h"
#include "compat/strtok.h"
#include "compat/time.h"
#include "config.h"
#include "common.h"
static void print_prelude(struct criterion_global_stats *stats) {
criterion_important("TAP version 13\n1.."
static void print_prelude(FILE *f, struct criterion_global_stats *stats) {
fprintf(f, "TAP version 13\n1.."
CR_SIZE_T_FORMAT
"\n", stats->nb_tests);
criterion_important("# Criterion v%s\n", VERSION);
fprintf(f, "# Criterion v%s\n", VERSION);
}
static void print_pre_suite(struct criterion_suite_stats *stats) {
criterion_important("\n# Running "
static void print_pre_suite(FILE *f, struct criterion_suite_stats *stats) {
fprintf(f, "\n# Running "
CR_SIZE_T_FORMAT
" tests from %s\n",
stats->nb_tests,
@ -54,10 +52,10 @@ static INLINE bool is_disabled(struct criterion_test *t, struct criterion_suite
return t->data->disabled || (s->data && s->data->disabled);
}
static void print_test_normal(struct criterion_test_stats *stats) {
static void print_test_normal(FILE *f, struct criterion_test_stats *stats) {
const char *format = can_measure_time() ? "%s - %s::%s %s (%3.2fs)\n"
: "%s - %s::%s %s\n";
criterion_important(format,
fprintf(f, format,
stats->failed ? "not ok" : "ok",
stats->test->category,
stats->test->name,
@ -69,64 +67,61 @@ static void print_test_normal(struct criterion_test_stats *stats) {
char *saveptr = NULL;
char *line = strtok_r(dup, "\n", &saveptr);
bool sf = criterion_options.short_filename;
criterion_important(" %s:%u: Assertion failed: %s\n",
fprintf(f, " %s:%u: Assertion failed: %s\n",
sf ? basename_compat(asrt->file) : asrt->file,
asrt->line,
line);
while ((line = strtok_r(NULL, "\n", &saveptr)))
criterion_important(" %s\n", line);
fprintf(f, " %s\n", line);
free(dup);
}
}
}
static void print_test_crashed(struct criterion_test_stats *stats) {
static void print_test_crashed(FILE *f, struct criterion_test_stats *stats) {
bool sf = criterion_options.short_filename;
criterion_important("not ok - %s::%s unexpected signal after %s:%u\n",
fprintf(f, "not ok - %s::%s unexpected signal after %s:%u\n",
stats->test->category,
stats->test->name,
sf ? basename_compat(stats->file) : stats->file,
stats->progress);
}
static void print_test_timeout(struct criterion_test_stats *stats) {
criterion_important("not ok - %s::%s timed out (%3.2fs)\n",
static void print_test_timeout(FILE *f, struct criterion_test_stats *stats) {
fprintf(f, "not ok - %s::%s timed out (%3.2fs)\n",
stats->test->category,
stats->test->name,
stats->elapsed_time);
}
static void print_test(struct criterion_test_stats *ts,
static void print_test(FILE *f,
struct criterion_test_stats *ts,
struct criterion_suite_stats *ss) {
if (is_disabled(ts->test, ss->suite)) {
criterion_important("ok - %s::%s %s # SKIP %s is disabled\n",
fprintf(f, "ok - %s::%s %s # SKIP %s is disabled\n",
ts->test->category,
ts->test->name,
DEF(ts->test->data->description, ""),
ts->test->data->disabled ? "test" : "suite");
} else if (ts->crashed) {
print_test_crashed(ts);
print_test_crashed(f, ts);
} else if (ts->timed_out) {
print_test_timeout(ts);
print_test_timeout(f, ts);
} else {
print_test_normal(ts);
print_test_normal(f, ts);
}
}
void tap_log_post_all(struct criterion_global_stats *stats) {
print_prelude(stats);
void tap_report(FILE *f, struct criterion_global_stats *stats) {
print_prelude(f, stats);
for (struct criterion_suite_stats *ss = stats->suites; ss; ss = ss->next) {
print_pre_suite(ss);
print_pre_suite(f, ss);
for (struct criterion_test_stats *ts = ss->tests; ts; ts = ts->next) {
print_test(ts, ss);
print_test(f, ts, ss);
}
}
}
struct criterion_output_provider tap_logging = {
.log_post_all = tap_log_post_all,
};

View file

@ -112,24 +112,25 @@ const char *get_status_string(struct criterion_test_stats *ts,
return status;
}
static void print_test(struct criterion_test_stats *ts,
static void print_test(FILE *f,
struct criterion_test_stats *ts,
struct criterion_suite_stats *ss) {
criterion_important(XML_TEST_TEMPLATE_BEGIN,
fprintf(f, XML_TEST_TEMPLATE_BEGIN,
ts->test->name,
(size_t) (ts->passed_asserts + ts->failed_asserts),
get_status_string(ts, ss)
);
if (is_disabled(ts->test, ss->suite)) {
criterion_important(XML_TEST_SKIPPED);
fprintf(f, XML_TEST_SKIPPED);
} else if (ts->crashed) {
criterion_important(XML_CRASH_MSG_ENTRY);
fprintf(f, XML_CRASH_MSG_ENTRY);
} else if (ts->timed_out) {
criterion_important(XML_TIMEOUT_MSG_ENTRY);
fprintf(f, XML_TIMEOUT_MSG_ENTRY);
} else {
if (ts->failed) {
criterion_important(XML_TEST_FAILED_TEMPLATE_BEGIN, ts->failed_asserts);
fprintf(f, XML_TEST_FAILED_TEMPLATE_BEGIN, ts->failed_asserts);
for (struct criterion_assert_stats *asrt = ts->asserts; asrt; asrt = asrt->next) {
if (!asrt->passed) {
bool sf = criterion_options.short_filename;
@ -137,26 +138,26 @@ static void print_test(struct criterion_test_stats *ts,
char *saveptr = NULL;
char *line = strtok_r(dup, "\n", &saveptr);
criterion_important(XML_FAILURE_MSG_ENTRY,
fprintf(f, XML_FAILURE_MSG_ENTRY,
sf ? basename_compat(asrt->file) : asrt->file,
asrt->line,
line
);
while ((line = strtok_r(NULL, "\n", &saveptr)))
criterion_important(" %s" LF, line);
fprintf(f, " %s" LF, line);
free(dup);
}
}
criterion_important(XML_TEST_FAILED_TEMPLATE_END);
fprintf(f, XML_TEST_FAILED_TEMPLATE_END);
}
}
criterion_important(XML_TEST_TEMPLATE_END);
fprintf(f, XML_TEST_TEMPLATE_END);
}
void xml_log_post_all(struct criterion_global_stats *stats) {
criterion_important(XML_BASE_TEMPLATE_BEGIN,
void xml_report(FILE *f, struct criterion_global_stats *stats) {
fprintf(f, XML_BASE_TEMPLATE_BEGIN,
stats->nb_tests,
stats->tests_failed,
stats->tests_crashed,
@ -165,7 +166,7 @@ void xml_log_post_all(struct criterion_global_stats *stats) {
for (struct criterion_suite_stats *ss = stats->suites; ss; ss = ss->next) {
criterion_important(XML_TESTSUITE_TEMPLATE_BEGIN,
fprintf(f, XML_TESTSUITE_TEMPLATE_BEGIN,
ss->suite->name,
ss->nb_tests,
ss->tests_failed,
@ -175,15 +176,11 @@ void xml_log_post_all(struct criterion_global_stats *stats) {
);
for (struct criterion_test_stats *ts = ss->tests; ts; ts = ts->next) {
print_test(ts, ss);
print_test(f, ts, ss);
}
criterion_important(XML_TESTSUITE_TEMPLATE_END);
fprintf(f, XML_TESTSUITE_TEMPLATE_END);
}
criterion_important(XML_BASE_TEMPLATE_END);
fprintf(f, XML_BASE_TEMPLATE_END);
}
struct criterion_output_provider xml_logging = {
.log_post_all = xml_log_post_all,
};

View file

@ -233,7 +233,7 @@ void normal_log_test_abort(CR_UNUSED struct criterion_test_stats *stats, const c
free(dup);
}
struct criterion_output_provider normal_logging = {
struct criterion_logger normal_logging = {
.log_pre_all = normal_log_pre_all,
.log_pre_init = normal_log_pre_init,
.log_pre_suite = normal_log_pre_suite,