From 6af7a69fb4e52f33f007e789c4e7b0706dd4fbe7 Mon Sep 17 00:00:00 2001 From: Snaipe Date: Tue, 24 Mar 2015 15:43:09 +0100 Subject: [PATCH 01/60] Added basic i18n interface --- src/i18n/i18n.h | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 src/i18n/i18n.h diff --git a/src/i18n/i18n.h b/src/i18n/i18n.h new file mode 100644 index 0000000..9f689c3 --- /dev/null +++ b/src/i18n/i18n.h @@ -0,0 +1,12 @@ +#ifndef I18N_H_ +# define I18N_H_ + +# include +# include "config.h" + +# define _(String) (dgettext ? dgettext(PACKAGE, String) : String) +# define _s(String, Plural, Quantity) \ + (dgettext ? dngettext(PACKAGE, String, Plural, Quantity) \ + : (Quantity == 1 ? String : Plural)) + +#endif /* !I18N_H_ */ From 818243902af4d0ae0ccba69a7b06babded0ae3d5 Mon Sep 17 00:00:00 2001 From: Snaipe Date: Tue, 24 Mar 2015 16:42:57 +0100 Subject: [PATCH 02/60] Fixed wrong information in README --- README.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/README.md b/README.md index a0537f7..fbf8749 100644 --- a/README.md +++ b/README.md @@ -75,9 +75,7 @@ A. Currently, on Linux 2.6.32 and Linux 3.15.7, although it should work on Windows 7 (with the Cygwin port of GCC). **Q. Can I use it on Windows without Cygwin?** -A. Yes, you can, Cygwin is only required to compile the static library if - you build it from source -- otherwise, a GNU C compatible compiler (like - GCC or Clang) is needed to compile your tests with the library. +A. Not for the moment. [online-docs]: http://criterion.readthedocs.org/ [pdf-docs]: http://readthedocs.org/projects/criterion/downloads/pdf/latest/ From 70a3c91dc51667fc4fb4eeeffc7e0e95990be604 Mon Sep 17 00:00:00 2001 From: Snaipe Date: Sun, 15 Mar 2015 16:00:21 +0100 Subject: [PATCH 03/60] Refactored code to prepare for windows integration --- Makefile.am | 1 + include/criterion/event.h | 3 +- src/event.c | 16 ++++---- src/event.h | 2 +- src/posix-compat.c | 82 +++++++++++++++++++++++++++++++++++++++ src/posix-compat.h | 35 +++++++++++++++++ src/process.c | 49 ++++++++++++----------- src/process.h | 3 +- src/runner.c | 7 ++-- 9 files changed, 162 insertions(+), 36 deletions(-) create mode 100644 src/posix-compat.c create mode 100644 src/posix-compat.h diff --git a/Makefile.am b/Makefile.am index e880bad..482175a 100644 --- a/Makefile.am +++ b/Makefile.am @@ -52,6 +52,7 @@ libcriterion_la_SOURCES = \ src/timer.c \ src/timer.h \ src/ordered-set.c \ + src/posix-compat.c \ src/main.c TARGET = $(PACKAGE)-$(VERSION) diff --git a/include/criterion/event.h b/include/criterion/event.h index 75f4a7c..99c85c8 100644 --- a/include/criterion/event.h +++ b/include/criterion/event.h @@ -25,8 +25,9 @@ # define CRITERION_EVENT_H_ # include +# include -extern int EVENT_PIPE; +extern FILE *g_event_pipe; void send_event(int kind, void *data, size_t size); diff --git a/src/event.c b/src/event.c index 339c477..a6a8b3d 100644 --- a/src/event.c +++ b/src/event.c @@ -22,36 +22,37 @@ * THE SOFTWARE. */ -#include +#include #include #include "criterion/stats.h" +#include "criterion/common.h" #include "criterion/hooks.h" #include "event.h" -int EVENT_PIPE = -1; +FILE *g_event_pipe = NULL; void destroy_event(void *ptr, UNUSED void *meta) { struct event *ev = ptr; free(ev->data); } -struct event *read_event(int fd) { +struct event *read_event(FILE *f) { unsigned kind; - if (read(fd, &kind, sizeof (unsigned)) < (ssize_t) sizeof (unsigned)) + if (fread(&kind, sizeof (unsigned), 1, f) == 0) return NULL; switch (kind) { case ASSERT: { const size_t assert_size = sizeof (struct criterion_assert_stats); unsigned char *buf = malloc(assert_size); - if (read(fd, buf, assert_size) < (ssize_t) assert_size) + if (fread(buf, assert_size, 1, f) == 0) return NULL; return unique_ptr(struct event, { .kind = kind, .data = buf }, destroy_event); } case POST_TEST: { double *elapsed_time = malloc(sizeof (double)); - if (read(fd, elapsed_time, sizeof (double)) < (ssize_t) sizeof (double)) + if (fread(elapsed_time, sizeof (double), 1, f) == 0) return NULL; return unique_ptr(struct event, { .kind = kind, .data = elapsed_time }, destroy_event); @@ -65,5 +66,6 @@ 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 (int) + size); + if (fwrite(buf, sizeof (int) + size, 1, g_event_pipe) == 0) + abort(); } diff --git a/src/event.h b/src/event.h index 405df73..fc8ce4f 100644 --- a/src/event.h +++ b/src/event.h @@ -31,6 +31,6 @@ struct event { void *data; }; -struct event *read_event(int fd); +struct event *read_event(FILE *f); #endif /* !EVENT_H_ */ diff --git a/src/posix-compat.c b/src/posix-compat.c new file mode 100644 index 0000000..46e26e4 --- /dev/null +++ b/src/posix-compat.c @@ -0,0 +1,82 @@ +#include "posix-compat.h" + +#ifdef _WIN32 +# include +#else +# include +# include +# include +# include +#endif + +#include + +struct proc_handle { +#ifdef _WIN32 + // TODO +#else + pid_t pid; +#endif +}; + +struct pipe_handle { +#ifdef _WIN32 + // TODO +#else + int fds[2]; +#endif +}; + +s_proc_handle *fork_process() { +#ifdef _WIN32 + // TODO +#else + pid_t pid = fork(); + if (pid == -1) + return (void *) -1; + if (pid == 0) + return NULL; + return unique_ptr(s_proc_handle, { pid }); +#endif +} + +void wait_process(s_proc_handle *handle, int *status) { +#ifdef _WIN32 + // TODO +#else + waitpid(handle->pid, status, 0); +#endif +} + +FILE *pipe_in(s_pipe_handle *p) { + close(p->fds[1]); + FILE *in = fdopen(p->fds[0], "r"); + setvbuf(in, NULL, _IONBF, 0); + return in; +} + +FILE *pipe_out(s_pipe_handle *p) { + close(p->fds[0]); + FILE *out = fdopen(p->fds[1], "w"); + setvbuf(out, NULL, _IONBF, 0); + return out; +} + +s_pipe_handle *stdpipe() { +#ifdef _WIN32 + // TODO +#else + int fds[2] = { -1, -1 }; + if (pipe(fds) == -1) + return NULL; + return unique_ptr(s_pipe_handle, {{ fds[0], fds[1] }}); +#endif +} + +s_proc_handle *get_current_process() { + return unique_ptr(s_proc_handle, { getpid() }); +} + +bool is_current_process(s_proc_handle *proc) { + return proc->pid == getpid(); +} diff --git a/src/posix-compat.h b/src/posix-compat.h new file mode 100644 index 0000000..83567f8 --- /dev/null +++ b/src/posix-compat.h @@ -0,0 +1,35 @@ +#ifndef POSIX_COMPAT_H_ +# define POSIX_COMPAT_H_ + +# define _POSIX_SOURCE 1 +# include +# undef _POSIX_SOURCE + +# ifdef _WIN32 +# define WEXITSTATUS(Status) (((Status) & 0xFF00) >> 8) +# define WTERMSIG(Status) ((Status) & 0x7F) +# define WIFEXITED(Status) (WTERMSIG(Status) == 0) +# define WIFSIGNALED(Status) (((signed char) (WTERMSIG(Status) + 1) >> 1) > 0) +# else +# include +# endif + +#include + +struct proc_handle; +typedef struct proc_handle s_proc_handle; + +struct pipe_handle; +typedef struct pipe_handle s_pipe_handle; + +s_pipe_handle *stdpipe(); +FILE *pipe_in(s_pipe_handle *p); +FILE *pipe_out(s_pipe_handle *p); + +s_proc_handle *fork_process(); +void wait_process(s_proc_handle *handle, int *status); + +s_proc_handle *get_current_process(); +bool is_current_process(s_proc_handle *proc); + +#endif /* !POSIX_COMPAT_H_ */ diff --git a/src/process.c b/src/process.c index 0d5689c..c0ebd76 100644 --- a/src/process.c +++ b/src/process.c @@ -22,33 +22,38 @@ * THE SOFTWARE. */ #include -#include -#include -#include +#include #include #include "criterion/types.h" #include "criterion/options.h" #include "process.h" #include "event.h" +#include "posix-compat.h" struct process { - pid_t pid; - int in; + s_proc_handle *proc; + FILE *in; }; -static pid_t g_runner_pid; +static s_proc_handle *g_current_proc; -void set_runner_pid(void) { - g_runner_pid = getpid(); +void set_runner_process(void) { + g_current_proc = get_current_process(); +} + +void unset_runner_process(void) { + sfree(g_current_proc); } bool is_runner(void) { - return g_runner_pid == getpid(); + return is_current_process(g_current_proc); } static void close_process(void *ptr, UNUSED void *meta) { - close(((struct process *) ptr)->in); + struct process *proc = ptr; + fclose(proc->in); + sfree(proc->proc); } struct event *worker_read_event(struct process *proc) { @@ -58,35 +63,33 @@ struct event *worker_read_event(struct process *proc) { struct process *spawn_test_worker(struct criterion_test *test, struct criterion_suite *suite, void (*func)(struct criterion_test *, struct criterion_suite *)) { - int fds[2]; - if (pipe(fds) == -1) + smart s_pipe_handle *pipe = stdpipe(); + if (pipe == NULL) abort(); - pid_t pid = fork(); - if (pid == -1) { + s_proc_handle *proc = fork_process(); + if (proc == (void *) -1) { return NULL; - } else if (!pid) { - close(STDIN_FILENO); - close(fds[0]); - EVENT_PIPE = fds[1]; + } else if (proc == NULL) { + fclose(stdin); + g_event_pipe = pipe_out(pipe); func(test, suite); - close(fds[1]); + fclose(g_event_pipe); fflush(NULL); // flush all opened streams if (criterion_options.no_early_exit) return NULL; else - _exit(0); + _Exit(0); } - close(fds[1]); - return unique_ptr(struct process, { .pid = pid, .in = fds[0] }, close_process); + return unique_ptr(struct process, { .proc = proc, .in = pipe_in(pipe) }, close_process); } struct process_status wait_proc(struct process *proc) { int status; - waitpid(proc->pid, &status, 0); + wait_process(proc->proc, &status); if (WIFEXITED(status)) return (struct process_status) { .kind = EXIT_STATUS, .status = WEXITSTATUS(status) }; diff --git a/src/process.h b/src/process.h index 02f480e..679c17f 100644 --- a/src/process.h +++ b/src/process.h @@ -39,7 +39,8 @@ struct process_status { int status; }; -void set_runner_pid(void); +void set_runner_process(void); +void unset_runner_process(void); bool is_runner(void); struct process_status wait_proc(struct process *proc); struct process *spawn_test_worker(struct criterion_test *test, diff --git a/src/runner.c b/src/runner.c index c4a535e..8f07b22 100644 --- a/src/runner.c +++ b/src/runner.c @@ -23,7 +23,6 @@ */ #include #include -#include #include #include "criterion/criterion.h" #include "criterion/options.h" @@ -203,7 +202,6 @@ static int criterion_run_all_tests_impl(void) { smart struct criterion_test_set *set = criterion_init(); report(PRE_ALL, set); - set_runner_pid(); smart struct criterion_global_stats *stats = stats_init(); map_tests(set, stats, run_test); @@ -216,9 +214,12 @@ static int criterion_run_all_tests_impl(void) { } int criterion_run_all_tests(void) { + set_runner_process(); int res = criterion_run_all_tests_impl(); + unset_runner_process(); + if (res == -1) // if this is the test worker terminating - _exit(0); + _Exit(0); return criterion_options.always_succeed || res; } From 130244d2cadde4a1fa84a558332b03f3f52ea96d Mon Sep 17 00:00:00 2001 From: Snaipe Date: Wed, 25 Mar 2015 00:22:33 +0100 Subject: [PATCH 04/60] Implemented pipe on the windows side --- src/posix-compat.c | 33 +++++++++++++++++++++++++++++++-- src/posix-compat.h | 10 ++++++++-- 2 files changed, 39 insertions(+), 4 deletions(-) diff --git a/src/posix-compat.c b/src/posix-compat.c index 46e26e4..7d7f0e4 100644 --- a/src/posix-compat.c +++ b/src/posix-compat.c @@ -1,7 +1,11 @@ #include "posix-compat.h" #ifdef _WIN32 +# define VC_EXTRALEAN +# define WIN32_LEAN_AND_MEAN # include +# include +# include #else # include # include @@ -21,7 +25,7 @@ struct proc_handle { struct pipe_handle { #ifdef _WIN32 - // TODO + HANDLE fhs[2]; #else int fds[2]; #endif @@ -49,22 +53,47 @@ void wait_process(s_proc_handle *handle, int *status) { } FILE *pipe_in(s_pipe_handle *p) { +#ifdef _WIN32 + CloseHandle(p->fhs[1]); + int fd = _open_osfhandle(p->fhs[0], _O_RDONLY); + if (fd == -1) + return NULL; + FILE *in = _fdopen(, "r"); +#else close(p->fds[1]); FILE *in = fdopen(p->fds[0], "r"); +#endif + if (!in) + return NULL; + setvbuf(in, NULL, _IONBF, 0); return in; } FILE *pipe_out(s_pipe_handle *p) { +#ifdef _WIN32 + CloseHandle(p->fhs[0]); + int fd = _open_osfhandle(p->fhs[1], _O_WRONLY); + if (fd == -1) + return NULL; + FILE *out = _fdopen(fd, "w"); +#else close(p->fds[0]); FILE *out = fdopen(p->fds[1], "w"); +#endif + if (!out) + return NULL; + setvbuf(out, NULL, _IONBF, 0); return out; } s_pipe_handle *stdpipe() { #ifdef _WIN32 - // TODO + HANDLE fhs[2]; + if (!CreatePipe(fhs, fhs + 1, NULL, 0)) + return NULL; + return unique_ptr(s_pipe_handle, {{ fhs[0], fhs[1] }}); #else int fds[2] = { -1, -1 }; if (pipe(fds) == -1) diff --git a/src/posix-compat.h b/src/posix-compat.h index 83567f8..8f53627 100644 --- a/src/posix-compat.h +++ b/src/posix-compat.h @@ -1,9 +1,15 @@ #ifndef POSIX_COMPAT_H_ # define POSIX_COMPAT_H_ -# define _POSIX_SOURCE 1 +# if !defined(_POSIX_SOURCE) +# define _POSIX_SOURCE 1 +# define TMP_POSIX +# endif # include -# undef _POSIX_SOURCE +# ifdef TMP_POSIX +# undef _POSIX_SOURCE +# undef TMP_POSIX +# endif # ifdef _WIN32 # define WEXITSTATUS(Status) (((Status) & 0xFF00) >> 8) From 7a74617884eb9263b1f41988e2eae9c7ccb82159 Mon Sep 17 00:00:00 2001 From: Snaipe Date: Wed, 25 Mar 2015 12:06:47 +0100 Subject: [PATCH 05/60] Made appveyor use mingw-gcc --- appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index 5ef46fa..e899727 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -52,7 +52,7 @@ configuration: Release install: - "%CYG_BASH% -lc 'cd $APPVEYOR_BUILD_FOLDER; ./autogen.sh'" - - '%CYG_BASH% -lc "cd $APPVEYOR_BUILD_FOLDER; exec 0 Date: Wed, 25 Mar 2015 17:17:28 +0100 Subject: [PATCH 06/60] Added WIP fork()'ing --- src/posix-compat.c | 90 ++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 87 insertions(+), 3 deletions(-) diff --git a/src/posix-compat.c b/src/posix-compat.c index 7d7f0e4..236f4f8 100644 --- a/src/posix-compat.c +++ b/src/posix-compat.c @@ -6,6 +6,26 @@ # include # include # include +# include +# include + +# define CREATE_SUSPENDED(Filename, CmdLine, StartupInfo, Info) \ + CreateProcessW(Filename, \ + CmdLine(), \ + NULL, \ + NULL, \ + TRUE, \ + CREATE_SUSPENDED, \ + NULL, \ + NULL, \ + &(StartupInfo), \ + &(Info)) + +# ifdef _WIN64 +# define Register(Reg, Context) ((Context).R ## Reg) +# else +# define Register(Reg, Context) ((Context).E ## Reg) +# endif #else # include # include @@ -17,7 +37,7 @@ struct proc_handle { #ifdef _WIN32 - // TODO + HANDLE handle; #else pid_t pid; #endif @@ -31,9 +51,69 @@ struct pipe_handle { #endif }; +#ifdef _WIN32 +# define CONTEXT_INIT {CONTEXT_FULL | CONTEXT_DEBUG_REGISTERS | CONTEXT_FLOATING_POINT} +struct stack_info { + char *ptr; + char *base; + size_t size; +}; + +static inline get_stack_info(struct stack_info *stack) { + CONTEXT context = CONTEXT_INIT; + MEMORY_BASIC_INFORMATION mbi; + + GetThreadContext(GetCurrentThread(), &context); + stack->ptr = (char *) Register(sp, context); + + VirtualQuery(stack->ptr, &mbi, sizeof (mbi)); + stack->base = mbi->BaseAddress; + stack->size = mbi->RegionSize; +} + +static g_jmp; + +static void resume_child(void) { + longjmp(g_jmp, 1); +} +#endif + s_proc_handle *fork_process() { #ifdef _WIN32 - // TODO + PROCESS_INFORMATION info; + STARTUPINFOW si = { .cb = sizeof (STARTUPINFOW) }; + + ZeroMemory(&info, sizeof (info)); + + CONTEXT context = {CONTEXT_FULL | CONTEXT_DEBUG_REGISTERS | CONTEXT_FLOATING_POINT}; + + // Initialize longjmp buffer + if (setjmp(g_jmp)) + return NULL; // we are the child, return + + // Create the suspended child process + wchar_t filename[MAX_PATH]; + GetModuleFileNameW(NULL, filename, MAX_PATH); + + if (!CREATE_SUSPENDED(filename, GetCommandLineW(), si, info)) + return NULL; + + // Set child's instruction pointer to resume_child + GetThreadContext(info.hThread, &context); + Register(ip, context) = resume_child; + SetThreadContext(info.hThread, &context); + + // Copy stack + struct stack_info stack; + get_stack_info(&stack); + + VirtualAllocEx(info.hProcess, stack->base, stack->size, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE); + WriteProcessMemory(info.hProcess, stack->ptr, stack->ptr, stack->base + stack->size - stack->ptr, NULL); + + ResumeThread(info.hThread); + CloseHandle(info.hThread); + + return unique_ptr(s_proc_handle, { info.hProcess }); #else pid_t pid = fork(); if (pid == -1) @@ -46,7 +126,11 @@ s_proc_handle *fork_process() { void wait_process(s_proc_handle *handle, int *status) { #ifdef _WIN32 - // TODO + WaitForSingleObject(handle->handle, INFINITE); + DWORD exit_code; + GetExitCodeProcess(handle->handle, &exit_code); + CloseHandle(handle->handle); + *status = exit_code << 8; #else waitpid(handle->pid, status, 0); #endif From cde5fed6d4032bce69556be499eb54f51da85854 Mon Sep 17 00:00:00 2001 From: Snaipe Date: Wed, 25 Mar 2015 18:48:28 +0100 Subject: [PATCH 07/60] Updated libcsptr for mingw 4.7 support --- dependencies/csptr | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dependencies/csptr b/dependencies/csptr index 15b825f..1c96aae 160000 --- a/dependencies/csptr +++ b/dependencies/csptr @@ -1 +1 @@ -Subproject commit 15b825ffb8ffe7309bf524659eb900d6bb1d7c04 +Subproject commit 1c96aaec456287dc63eeb31443f409b5476afa0e From e9f0dfb572c893823efbb9d2ff726f19f7df18a7 Mon Sep 17 00:00:00 2001 From: Snaipe Date: Wed, 25 Mar 2015 19:58:51 +0100 Subject: [PATCH 08/60] Added fnmatch conditional for Windows portability --- configure.ac | 2 ++ src/main.c | 6 ++++++ src/report.c | 8 +++++++- 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index bddf447..e8de7d2 100644 --- a/configure.ac +++ b/configure.ac @@ -20,6 +20,8 @@ AC_PROG_LN_S AC_PROG_MAKE_SET AC_SUBST([LIBTOOL_DEPS]) +AC_FUNC_FNMATCH + AC_ARG_ENABLE([gcov], [AS_HELP_STRING([--enable-gcov], [Compile the project with converage enabled])], diff --git a/src/main.c b/src/main.c index 467e49d..4ee1c76 100644 --- a/src/main.c +++ b/src/main.c @@ -112,7 +112,9 @@ int main(int argc, char *argv[]) { {"list", no_argument, 0, 'l'}, {"ascii", no_argument, 0, 'k'}, {"fail-fast", no_argument, 0, 'f'}, +#ifdef HAVE_FNMATCH {"pattern", required_argument, 0, 'p'}, +#endif {"always-succeed", no_argument, 0, 'y'}, {"no-early-exit", no_argument, 0, 'z'}, {0, 0, 0, 0 } @@ -124,7 +126,9 @@ int main(int argc, char *argv[]) { .fail_fast = !strcmp("1", getenv("CRITERION_FAIL_FAST") ?: "0"), .use_ascii = !strcmp("1", getenv("CRITERION_USE_ASCII") ?: "0"), .logging_threshold = atoi(getenv("CRITERION_VERBOSITY_LEVEL") ?: "2"), +#ifdef HAVE_FNMATCH .pattern = getenv("CRITERION_TEST_PATTERN"), +#endif .output_provider = NORMAL_LOGGING, }; @@ -140,7 +144,9 @@ int main(int argc, char *argv[]) { 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; +#ifdef HAVE_FNMATCH case 'p': criterion_options.pattern = optarg; break; +#endif case 't': use_tap = true; break; case 'l': do_list_tests = true; break; case 'v': do_print_version = true; break; diff --git a/src/report.c b/src/report.c index 5c70807..542f813 100644 --- a/src/report.c +++ b/src/report.c @@ -24,13 +24,17 @@ #define _GNU_SOURCE #include #include -#include #include "criterion/types.h" #include "criterion/stats.h" #include "criterion/logging.h" #include "criterion/options.h" #include "criterion/ordered-set.h" #include "report.h" +#include "config.h" + +#ifdef HAVE_FNMATCH +#include +#endif #define IMPL_CALL_REPORT_HOOKS(Kind) \ IMPL_SECTION_LIMITS(f_report_hook, crit_ ## Kind); \ @@ -53,6 +57,7 @@ __attribute__((always_inline)) static inline void nothing() {} IMPL_REPORT_HOOK(PRE_ALL)(struct criterion_test_set *set) { +#ifdef HAVE_FNMATCH if (criterion_options.pattern) { FOREACH_SET(struct criterion_suite_set *s, set->suites) { if ((s->suite.data && s->suite.data->disabled) || !s->tests) @@ -64,6 +69,7 @@ IMPL_REPORT_HOOK(PRE_ALL)(struct criterion_test_set *set) { } } } +#endif log(pre_all, set); } From bbb107e8da85608b68c9bcfc97901ebf10999d15 Mon Sep 17 00:00:00 2001 From: Snaipe Date: Wed, 25 Mar 2015 20:23:06 +0100 Subject: [PATCH 09/60] Fixed some issues on windows --- src/posix-compat.c | 53 +++++++++++++++++++++++++++------------------- 1 file changed, 31 insertions(+), 22 deletions(-) diff --git a/src/posix-compat.c b/src/posix-compat.c index 236f4f8..7c8b8ea 100644 --- a/src/posix-compat.c +++ b/src/posix-compat.c @@ -8,17 +8,18 @@ # include # include # include +# include -# define CREATE_SUSPENDED(Filename, CmdLine, StartupInfo, Info) \ - CreateProcessW(Filename, \ - CmdLine(), \ - NULL, \ - NULL, \ - TRUE, \ - CREATE_SUSPENDED, \ - NULL, \ - NULL, \ - &(StartupInfo), \ +# define CREATE_SUSPENDED_(Filename, CmdLine, StartupInfo, Info) \ + CreateProcessW(Filename, \ + CmdLine, \ + NULL, \ + NULL, \ + TRUE, \ + CREATE_SUSPENDED, \ + NULL, \ + NULL, \ + &(StartupInfo), \ &(Info)) # ifdef _WIN64 @@ -52,14 +53,14 @@ struct pipe_handle { }; #ifdef _WIN32 -# define CONTEXT_INIT {CONTEXT_FULL | CONTEXT_DEBUG_REGISTERS | CONTEXT_FLOATING_POINT} +# define CONTEXT_INIT { .ContextFlags = CONTEXT_FULL | CONTEXT_DEBUG_REGISTERS | CONTEXT_FLOATING_POINT } struct stack_info { char *ptr; char *base; size_t size; }; -static inline get_stack_info(struct stack_info *stack) { +static inline void get_stack_info(struct stack_info *stack) { CONTEXT context = CONTEXT_INIT; MEMORY_BASIC_INFORMATION mbi; @@ -67,8 +68,8 @@ static inline get_stack_info(struct stack_info *stack) { stack->ptr = (char *) Register(sp, context); VirtualQuery(stack->ptr, &mbi, sizeof (mbi)); - stack->base = mbi->BaseAddress; - stack->size = mbi->RegionSize; + stack->base = mbi.BaseAddress; + stack->size = mbi.RegionSize; } static g_jmp; @@ -85,7 +86,7 @@ s_proc_handle *fork_process() { ZeroMemory(&info, sizeof (info)); - CONTEXT context = {CONTEXT_FULL | CONTEXT_DEBUG_REGISTERS | CONTEXT_FLOATING_POINT}; + CONTEXT context = CONTEXT_INIT; // Initialize longjmp buffer if (setjmp(g_jmp)) @@ -95,20 +96,20 @@ s_proc_handle *fork_process() { wchar_t filename[MAX_PATH]; GetModuleFileNameW(NULL, filename, MAX_PATH); - if (!CREATE_SUSPENDED(filename, GetCommandLineW(), si, info)) + if (!CREATE_SUSPENDED_(filename, GetCommandLineW(), si, info)) return NULL; // Set child's instruction pointer to resume_child GetThreadContext(info.hThread, &context); - Register(ip, context) = resume_child; + Register(ip, context) = (intptr_t) resume_child; SetThreadContext(info.hThread, &context); // Copy stack struct stack_info stack; get_stack_info(&stack); - VirtualAllocEx(info.hProcess, stack->base, stack->size, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE); - WriteProcessMemory(info.hProcess, stack->ptr, stack->ptr, stack->base + stack->size - stack->ptr, NULL); + VirtualAllocEx(info.hProcess, stack.base, stack.size, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE); + WriteProcessMemory(info.hProcess, stack.ptr, stack.ptr, stack.base + stack.size - stack.ptr, NULL); ResumeThread(info.hThread); CloseHandle(info.hThread); @@ -139,10 +140,10 @@ void wait_process(s_proc_handle *handle, int *status) { FILE *pipe_in(s_pipe_handle *p) { #ifdef _WIN32 CloseHandle(p->fhs[1]); - int fd = _open_osfhandle(p->fhs[0], _O_RDONLY); + int fd = _open_osfhandle((intptr_t) p->fhs[0], _O_RDONLY); if (fd == -1) return NULL; - FILE *in = _fdopen(, "r"); + FILE *in = _fdopen(fd, "r"); #else close(p->fds[1]); FILE *in = fdopen(p->fds[0], "r"); @@ -157,7 +158,7 @@ FILE *pipe_in(s_pipe_handle *p) { FILE *pipe_out(s_pipe_handle *p) { #ifdef _WIN32 CloseHandle(p->fhs[0]); - int fd = _open_osfhandle(p->fhs[1], _O_WRONLY); + int fd = _open_osfhandle((intptr_t) p->fhs[1], _O_WRONLY); if (fd == -1) return NULL; FILE *out = _fdopen(fd, "w"); @@ -187,9 +188,17 @@ s_pipe_handle *stdpipe() { } s_proc_handle *get_current_process() { +#ifdef _WIN32 + return unique_ptr(s_proc_handle, { GetCurrentProcess() }); +#else return unique_ptr(s_proc_handle, { getpid() }); +#endif } bool is_current_process(s_proc_handle *proc) { +#ifdef _WIN32 + return GetProcessId(proc->handle) == GetProcessId(GetCurrentProcess()); +#else return proc->pid == getpid(); +#endif } From 419d80639f4138b76aaed7a78e67c15b5901990e Mon Sep 17 00:00:00 2001 From: Snaipe Date: Wed, 25 Mar 2015 20:24:41 +0100 Subject: [PATCH 10/60] Added missing jmp_buf type --- src/posix-compat.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/posix-compat.c b/src/posix-compat.c index 7c8b8ea..636c8a5 100644 --- a/src/posix-compat.c +++ b/src/posix-compat.c @@ -72,7 +72,7 @@ static inline void get_stack_info(struct stack_info *stack) { stack->size = mbi.RegionSize; } -static g_jmp; +static jmp_buf g_jmp; static void resume_child(void) { longjmp(g_jmp, 1); From f652d174fe3e5339a3a472e40b0358e6bc3a569b Mon Sep 17 00:00:00 2001 From: Snaipe Date: Thu, 26 Mar 2015 14:49:09 +0100 Subject: [PATCH 11/60] Also copy the heap --- src/posix-compat.c | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/src/posix-compat.c b/src/posix-compat.c index 636c8a5..7a5d809 100644 --- a/src/posix-compat.c +++ b/src/posix-compat.c @@ -54,13 +54,13 @@ struct pipe_handle { #ifdef _WIN32 # define CONTEXT_INIT { .ContextFlags = CONTEXT_FULL | CONTEXT_DEBUG_REGISTERS | CONTEXT_FLOATING_POINT } -struct stack_info { +struct region_info { char *ptr; char *base; size_t size; }; -static inline void get_stack_info(struct stack_info *stack) { +static inline void get_memory_info(struct region_info *stack, struct region_info *heap) { CONTEXT context = CONTEXT_INIT; MEMORY_BASIC_INFORMATION mbi; @@ -70,6 +70,13 @@ static inline void get_stack_info(struct stack_info *stack) { VirtualQuery(stack->ptr, &mbi, sizeof (mbi)); stack->base = mbi.BaseAddress; stack->size = mbi.RegionSize; + + void *ptr = malloc(1); + VirtualQuery(ptr, &mbi, sizeof (mbi)); + heap->ptr = NULL; + heap->base = mbi.BaseAddress; + heap->size = mbi.RegionSize; + free(ptr); } static jmp_buf g_jmp; @@ -104,12 +111,19 @@ s_proc_handle *fork_process() { Register(ip, context) = (intptr_t) resume_child; SetThreadContext(info.hThread, &context); - // Copy stack - struct stack_info stack; - get_stack_info(&stack); + // Copy stack, heap + struct region_info stack; + struct region_info heap; + get_memory_info(&stack, &heap); VirtualAllocEx(info.hProcess, stack.base, stack.size, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE); - WriteProcessMemory(info.hProcess, stack.ptr, stack.ptr, stack.base + stack.size - stack.ptr, NULL); + WriteProcessMemory(info.hProcess, stack.base, stack.base, stack.size, NULL); + + VirtualAllocEx(info.hProcess, heap.base, heap.size, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE); + WriteProcessMemory(info.hProcess, heap.base, heap.base, heap.size, NULL); + + // Copy jmp_buf + WriteProcessMemory(info.hProcess, &g_jmp, &g_jmp, sizeof (jmp_buf), NULL); ResumeThread(info.hThread); CloseHandle(info.hThread); From 243ed3a8b83ed1419a6c4093ad323b1a38827a68 Mon Sep 17 00:00:00 2001 From: Snaipe Date: Thu, 26 Mar 2015 22:18:43 +0100 Subject: [PATCH 12/60] Trying a safer approach for a fork() alternative --- include/criterion/types.h | 12 +++--- src/posix-compat.c | 91 +++++++++++++++------------------------ src/posix-compat.h | 13 +++++- src/process.c | 34 +++++++++------ src/process.h | 2 + src/runner.c | 4 ++ 6 files changed, 81 insertions(+), 75 deletions(-) diff --git a/include/criterion/types.h b/include/criterion/types.h index 3a4672f..6e7dae2 100644 --- a/include/criterion/types.h +++ b/include/criterion/types.h @@ -29,9 +29,9 @@ struct criterion_test_extra_data { int sentinel_; - const char *const identifier_; - const char *const file_; - const unsigned line_; + const char *identifier_; + const char *file_; + unsigned line_; void (*init)(void); void (*fini)(void); int signal; @@ -44,12 +44,14 @@ struct criterion_test { const char *name; const char *category; void (*test)(void); - struct criterion_test_extra_data *const data; + struct criterion_test_extra_data *data; }; struct criterion_suite { const char *name; - struct criterion_test_extra_data *const data; + struct criterion_test_extra_data *data; }; +typedef void (*f_worker_func)(struct criterion_test *, struct criterion_suite *); + #endif /* !CRITERION_TYPES_H_ */ diff --git a/src/posix-compat.c b/src/posix-compat.c index 7a5d809..01e4527 100644 --- a/src/posix-compat.c +++ b/src/posix-compat.c @@ -1,4 +1,5 @@ #include "posix-compat.h" +#include "process.h" #ifdef _WIN32 # define VC_EXTRALEAN @@ -7,7 +8,6 @@ # include # include # include -# include # include # define CREATE_SUSPENDED_(Filename, CmdLine, StartupInfo, Info) \ @@ -22,11 +22,7 @@ &(StartupInfo), \ &(Info)) -# ifdef _WIN64 -# define Register(Reg, Context) ((Context).R ## Reg) -# else -# define Register(Reg, Context) ((Context).E ## Reg) -# endif +# define CONTEXT_INIT { .ContextFlags = CONTEXT_FULL | CONTEXT_DEBUG_REGISTERS | CONTEXT_FLOATING_POINT } #else # include # include @@ -52,40 +48,24 @@ struct pipe_handle { #endif }; +struct worker_context g_worker_context = {.test = NULL}; + #ifdef _WIN32 -# define CONTEXT_INIT { .ContextFlags = CONTEXT_FULL | CONTEXT_DEBUG_REGISTERS | CONTEXT_FLOATING_POINT } -struct region_info { - char *ptr; - char *base; - size_t size; -}; - -static inline void get_memory_info(struct region_info *stack, struct region_info *heap) { - CONTEXT context = CONTEXT_INIT; - MEMORY_BASIC_INFORMATION mbi; - - GetThreadContext(GetCurrentThread(), &context); - stack->ptr = (char *) Register(sp, context); - - VirtualQuery(stack->ptr, &mbi, sizeof (mbi)); - stack->base = mbi.BaseAddress; - stack->size = mbi.RegionSize; - - void *ptr = malloc(1); - VirtualQuery(ptr, &mbi, sizeof (mbi)); - heap->ptr = NULL; - heap->base = mbi.BaseAddress; - heap->size = mbi.RegionSize; - free(ptr); -} - -static jmp_buf g_jmp; - -static void resume_child(void) { - longjmp(g_jmp, 1); -} +static struct criterion_test child_test; +static struct criterion_test_extra_data child_test_data; +static struct criterion_suite child_suite; +static struct criterion_test_extra_data child_suite_data; +static struct pipe_handle child_pipe; #endif +int resume_child(void) { + if (g_worker_context.test) { + run_worker(&g_worker_context); + return 1; + } + return 0; +} + s_proc_handle *fork_process() { #ifdef _WIN32 PROCESS_INFORMATION info; @@ -95,35 +75,32 @@ s_proc_handle *fork_process() { CONTEXT context = CONTEXT_INIT; - // Initialize longjmp buffer - if (setjmp(g_jmp)) - return NULL; // we are the child, return - // Create the suspended child process wchar_t filename[MAX_PATH]; GetModuleFileNameW(NULL, filename, MAX_PATH); if (!CREATE_SUSPENDED_(filename, GetCommandLineW(), si, info)) - return NULL; + return (void *) -1; - // Set child's instruction pointer to resume_child - GetThreadContext(info.hThread, &context); - Register(ip, context) = (intptr_t) resume_child; - SetThreadContext(info.hThread, &context); + // Copy context over + f_worker_func child_func = g_worker_context.func; - // Copy stack, heap - struct region_info stack; - struct region_info heap; - get_memory_info(&stack, &heap); + child_test = *g_worker_context.test; + child_test_data = *g_worker_context.test->data; + child_suite = *g_worker_context.suite; + child_suite_data = *g_worker_context.suite->data; + child_pipe = *g_worker_context.pipe; - VirtualAllocEx(info.hProcess, stack.base, stack.size, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE); - WriteProcessMemory(info.hProcess, stack.base, stack.base, stack.size, NULL); + g_worker_context = (struct worker_context) { &child_test, &child_suite, child_func, &child_pipe }; + child_test.data = &child_test_data; + child_suite.data = &child_suite_data; - VirtualAllocEx(info.hProcess, heap.base, heap.size, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE); - WriteProcessMemory(info.hProcess, heap.base, heap.base, heap.size, NULL); - - // Copy jmp_buf - WriteProcessMemory(info.hProcess, &g_jmp, &g_jmp, sizeof (jmp_buf), NULL); + WriteProcessMemory(info.hProcess, &child_test, &child_test, sizeof (child_test), NULL); + WriteProcessMemory(info.hProcess, &child_test_data, &child_test_data, sizeof (child_test_data), NULL); + WriteProcessMemory(info.hProcess, &child_suite, &child_suite, sizeof (child_suite), NULL); + WriteProcessMemory(info.hProcess, &child_suite_data, &child_suite_data, sizeof (child_suite_data), NULL); + WriteProcessMemory(info.hProcess, &child_pipe, &child_pipe, sizeof (child_pipe), NULL); + WriteProcessMemory(info.hProcess, &g_worker_context, &g_worker_context, sizeof (struct worker_context), NULL); ResumeThread(info.hThread); CloseHandle(info.hThread); diff --git a/src/posix-compat.h b/src/posix-compat.h index 8f53627..3c32e9c 100644 --- a/src/posix-compat.h +++ b/src/posix-compat.h @@ -20,7 +20,7 @@ # include # endif -#include +#include struct proc_handle; typedef struct proc_handle s_proc_handle; @@ -28,6 +28,17 @@ typedef struct proc_handle s_proc_handle; struct pipe_handle; typedef struct pipe_handle s_pipe_handle; +struct worker_context { + struct criterion_test *test; + struct criterion_suite *suite; + f_worker_func func; + struct pipe_handle *pipe; +}; + +extern struct worker_context g_worker_context; + +int resume_child(void); + s_pipe_handle *stdpipe(); FILE *pipe_in(s_pipe_handle *p); FILE *pipe_out(s_pipe_handle *p); diff --git a/src/process.c b/src/process.c index c0ebd76..83afc73 100644 --- a/src/process.c +++ b/src/process.c @@ -60,28 +60,38 @@ struct event *worker_read_event(struct process *proc) { return read_event(proc->in); } +void run_worker(struct worker_context *ctx) { + fclose(stdin); + g_event_pipe = pipe_out(ctx->pipe); + + ctx->func(ctx->test, ctx->suite); + fclose(g_event_pipe); + + fflush(NULL); // flush all opened streams + if (criterion_options.no_early_exit) + return; + _Exit(0); +} + struct process *spawn_test_worker(struct criterion_test *test, struct criterion_suite *suite, - void (*func)(struct criterion_test *, struct criterion_suite *)) { + f_worker_func func) { smart s_pipe_handle *pipe = stdpipe(); if (pipe == NULL) abort(); + g_worker_context = (struct worker_context) { + .test = test, + .suite = suite, + .func = func, + .pipe = pipe + }; s_proc_handle *proc = fork_process(); if (proc == (void *) -1) { return NULL; } else if (proc == NULL) { - fclose(stdin); - g_event_pipe = pipe_out(pipe); - - func(test, suite); - fclose(g_event_pipe); - - fflush(NULL); // flush all opened streams - if (criterion_options.no_early_exit) - return NULL; - else - _Exit(0); + run_worker(&g_worker_context); + return NULL; } return unique_ptr(struct process, { .proc = proc, .in = pipe_in(pipe) }, close_process); diff --git a/src/process.h b/src/process.h index 679c17f..5e0a6c3 100644 --- a/src/process.h +++ b/src/process.h @@ -25,6 +25,7 @@ # define PROCESS_H_ # include +# include "posix-compat.h" struct process; @@ -39,6 +40,7 @@ struct process_status { int status; }; +void run_worker(struct worker_context *ctx); void set_runner_process(void); void unset_runner_process(void); bool is_runner(void); diff --git a/src/runner.c b/src/runner.c index 8f07b22..8c84b1e 100644 --- a/src/runner.c +++ b/src/runner.c @@ -33,6 +33,7 @@ #include "event.h" #include "process.h" #include "timer.h" +#include "posix-compat.h" IMPL_SECTION_LIMITS(struct criterion_test, criterion_tests); IMPL_SECTION_LIMITS(struct criterion_suite, crit_suites); @@ -199,6 +200,9 @@ static void run_test(struct criterion_global_stats *stats, } static int criterion_run_all_tests_impl(void) { + if (resume_child()) // (windows only) resume from the fork + return -1; + smart struct criterion_test_set *set = criterion_init(); report(PRE_ALL, set); From 53c38d244e70a00f83cd1521c7ccf779fa3383c1 Mon Sep 17 00:00:00 2001 From: Snaipe Date: Thu, 26 Mar 2015 23:04:02 +0100 Subject: [PATCH 13/60] Added documentation on adding a custom main --- doc/index.rst | 1 + doc/internal.rst | 41 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+) create mode 100644 doc/internal.rst diff --git a/doc/index.rst b/doc/index.rst index 21a4a6c..dd79dd7 100644 --- a/doc/index.rst +++ b/doc/index.rst @@ -9,4 +9,5 @@ Criterion starter hooks env + internal faq diff --git a/doc/internal.rst b/doc/internal.rst new file mode 100644 index 0000000..df3518d --- /dev/null +++ b/doc/internal.rst @@ -0,0 +1,41 @@ +Changing the internals +====================== + +Providing your own main +----------------------- + +If you are not satisfied with the default CLI or environment variables, you +can define your own main function. + +Configuring the test runner +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +You'd usually want to configure the test runner before calling it. +Configuration is done by setting fields in a global variable named +``criterion_options`` (include criterion/options.h). + +Here is an exhaustive list of these fields: + +=================== ================================== ============================================================== +Field Type Description +=================== ================================== ============================================================== +logging_threshold enum criterion_logging_level The logging level +------------------- ---------------------------------- -------------------------------------------------------------- +output_provider struct criterion_output_provider * The output provider (see below) +------------------- ---------------------------------- -------------------------------------------------------------- +no_early_exit bool True iff the test worker should exit early +------------------- ---------------------------------- -------------------------------------------------------------- +always_succeed bool True iff criterion_run_all_tests should always returns 1 +------------------- ---------------------------------- -------------------------------------------------------------- +use_ascii bool True iff the outputs should use the ASCII charset +------------------- ---------------------------------- -------------------------------------------------------------- +fail_fast bool True iff the test runner should abort after the first failure +------------------- ---------------------------------- -------------------------------------------------------------- +pattern const char * The pattern of the tests that should be executed +=================== ================================== ============================================================== + +Starting the test runner +~~~~~~~~~~~~~~~~~~~~~~~~ + +The test runner can be called with ``criterion_run_all_tests``. The function +returns 0 if one test or more failed, 1 otherwise. From 07a5d9a6004543dbd812f797d3a1156130342820 Mon Sep 17 00:00:00 2001 From: Snaipe Date: Fri, 27 Mar 2015 07:39:33 -0700 Subject: [PATCH 14/60] Made the pipe handles inheritable --- src/posix-compat.c | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/src/posix-compat.c b/src/posix-compat.c index 01e4527..ec1e315 100644 --- a/src/posix-compat.c +++ b/src/posix-compat.c @@ -22,7 +22,6 @@ &(StartupInfo), \ &(Info)) -# define CONTEXT_INIT { .ContextFlags = CONTEXT_FULL | CONTEXT_DEBUG_REGISTERS | CONTEXT_FLOATING_POINT } #else # include # include @@ -73,8 +72,6 @@ s_proc_handle *fork_process() { ZeroMemory(&info, sizeof (info)); - CONTEXT context = CONTEXT_INIT; - // Create the suspended child process wchar_t filename[MAX_PATH]; GetModuleFileNameW(NULL, filename, MAX_PATH); @@ -85,20 +82,23 @@ s_proc_handle *fork_process() { // Copy context over f_worker_func child_func = g_worker_context.func; - child_test = *g_worker_context.test; - child_test_data = *g_worker_context.test->data; - child_suite = *g_worker_context.suite; - child_suite_data = *g_worker_context.suite->data; - child_pipe = *g_worker_context.pipe; + child_test = *g_worker_context.test; + child_test_data = *g_worker_context.test->data; + child_suite = *g_worker_context.suite; + child_pipe = *g_worker_context.pipe; g_worker_context = (struct worker_context) { &child_test, &child_suite, child_func, &child_pipe }; child_test.data = &child_test_data; - child_suite.data = &child_suite_data; + + if (g_worker_context.suite->data) { + child_suite_data = *g_worker_context.suite->data; + child_suite.data = &child_suite_data; + WriteProcessMemory(info.hProcess, &child_suite_data, &child_suite_data, sizeof (child_suite_data), NULL); + } WriteProcessMemory(info.hProcess, &child_test, &child_test, sizeof (child_test), NULL); WriteProcessMemory(info.hProcess, &child_test_data, &child_test_data, sizeof (child_test_data), NULL); WriteProcessMemory(info.hProcess, &child_suite, &child_suite, sizeof (child_suite), NULL); - WriteProcessMemory(info.hProcess, &child_suite_data, &child_suite_data, sizeof (child_suite_data), NULL); WriteProcessMemory(info.hProcess, &child_pipe, &child_pipe, sizeof (child_pipe), NULL); WriteProcessMemory(info.hProcess, &g_worker_context, &g_worker_context, sizeof (struct worker_context), NULL); @@ -167,7 +167,8 @@ FILE *pipe_out(s_pipe_handle *p) { s_pipe_handle *stdpipe() { #ifdef _WIN32 HANDLE fhs[2]; - if (!CreatePipe(fhs, fhs + 1, NULL, 0)) + SECURITY_ATTRIBUTES attr = { .nLength = sizeof (SECURITY_ATTRIBUTES), .bInheritHandle = TRUE }; + if (!CreatePipe(fhs, fhs + 1, &attr, 0)) return NULL; return unique_ptr(s_pipe_handle, {{ fhs[0], fhs[1] }}); #else From 9374693b66c18e6ce4359859976ca06d2b85860e Mon Sep 17 00:00:00 2001 From: Snaipe Date: Fri, 27 Mar 2015 16:21:03 +0100 Subject: [PATCH 15/60] Added conditional usage display for --pattern --- src/main.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/main.c b/src/main.c index 4ee1c76..832a28b 100644 --- a/src/main.c +++ b/src/main.c @@ -33,6 +33,14 @@ # define VERSION_MSG "Tests compiled with Criterion v" VERSION "\n" +#ifdef HAVE_FNMATCH +# define PATTERN_USAGE \ + " --pattern [PATTERN]: run tests matching the " \ + "given pattern\n" +#else +# define PATTERN_USAGE +#endif + # define USAGE \ VERSION_MSG "\n" \ "usage: %s OPTIONS\n" \ @@ -44,8 +52,7 @@ " -f or --fail-fast: exit after the first failure\n" \ " --ascii: don't use fancy unicode symbols " \ "or colors in the output\n" \ - " --pattern [PATTERN]: run tests matching the " \ - "given pattern\n" \ + PATTERN_USAGE \ " --tap: enables TAP formatting\n" \ " --always-succeed: always exit with 0\n" \ " --no-early-exit: do not exit the test worker " \ From 7cab7632168475f2dbd2698b819265685e84f6aa Mon Sep 17 00:00:00 2001 From: Snaipe Date: Fri, 27 Mar 2015 16:21:30 +0100 Subject: [PATCH 16/60] Made appveyor builds work again --- appveyor.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index e899727..fe3ad27 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -14,6 +14,7 @@ init: -P mingw-gcc-core \ -P mingw-pthreads \ -P mingw-w32api \ + -P mingw64-i686-gcc-core \ -P libtool \ -P make \ -P python \ @@ -52,7 +53,7 @@ configuration: Release install: - "%CYG_BASH% -lc 'cd $APPVEYOR_BUILD_FOLDER; ./autogen.sh'" - - '%CYG_BASH% -lc "cd $APPVEYOR_BUILD_FOLDER; exec 0 Date: Fri, 27 Mar 2015 19:29:34 +0100 Subject: [PATCH 17/60] Only test criterion, not csptr --- appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index fe3ad27..cc59949 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -59,7 +59,7 @@ build_script: - '%CYG_BASH% -lc "cd $APPVEYOR_BUILD_FOLDER; exec 0 Date: Fri, 27 Mar 2015 19:50:53 +0100 Subject: [PATCH 18/60] Default to ascii charset when on a dumb terminal (or cmd.exe) --- src/main.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/main.c b/src/main.c index 832a28b..8cb1f7a 100644 --- a/src/main.c +++ b/src/main.c @@ -127,11 +127,14 @@ int main(int argc, char *argv[]) { {0, 0, 0, 0 } }; + bool use_ascii = !strcmp("1", getenv("CRITERION_USE_ASCII") ?: "0") + || !strcmp("dumb", getenv("TERM") ?: "dumb"); + 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"), .fail_fast = !strcmp("1", getenv("CRITERION_FAIL_FAST") ?: "0"), - .use_ascii = !strcmp("1", getenv("CRITERION_USE_ASCII") ?: "0"), + .use_ascii = use_ascii, .logging_threshold = atoi(getenv("CRITERION_VERBOSITY_LEVEL") ?: "2"), #ifdef HAVE_FNMATCH .pattern = getenv("CRITERION_TEST_PATTERN"), From 15fc9b771766af4c3db95d1f1b92563e0519174e Mon Sep 17 00:00:00 2001 From: Snaipe Date: Sat, 28 Mar 2015 15:39:35 +0100 Subject: [PATCH 19/60] Added mingw support notification in README --- README.md | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index fbf8749..4ea9f8d 100644 --- a/README.md +++ b/README.md @@ -31,7 +31,7 @@ the user would have with other frameworks: reported and tested. * [x] Progress and statistics can be followed in real time with report hooks. * [x] TAP output format can be enabled with an option. -* [x] Runs on Linux, FreeBSD, Mac OS X, and Windows (compiles only with Cygwin for the moment). +* [x] Runs on Linux, FreeBSD, Mac OS X, and Windows (Compiles only with MinGW or Cygwin). ## Downloads @@ -72,10 +72,7 @@ A. I worked with CUnit and Check, and I must say that they do their job **Q. Where has this been tested?** A. Currently, on Linux 2.6.32 and Linux 3.15.7, although it should work on most \*nix systems; Mac OS X Yosemite 10.10, FreeBSD 10.0, and finally - Windows 7 (with the Cygwin port of GCC). - -**Q. Can I use it on Windows without Cygwin?** -A. Not for the moment. + Windows 7 (with the MinGW and Cygwin ports of GCC). [online-docs]: http://criterion.readthedocs.org/ [pdf-docs]: http://readthedocs.org/projects/criterion/downloads/pdf/latest/ From beb9b64eb1d28eba9e13e34eacbbefff999d2871 Mon Sep 17 00:00:00 2001 From: Snaipe Date: Tue, 31 Mar 2015 22:13:09 +0200 Subject: [PATCH 20/60] Refactored most of the output for i18n support --- include/criterion/logging.h | 50 +++++++++++++++++ src/i18n.h | 15 ++++++ src/i18n/i18n.h | 12 ----- src/log/logging.c | 40 +++++++++++++- src/log/normal.c | 103 +++++++++++++++--------------------- 5 files changed, 147 insertions(+), 73 deletions(-) create mode 100644 src/i18n.h delete mode 100644 src/i18n/i18n.h diff --git a/include/criterion/logging.h b/include/criterion/logging.h index 776361a..86aed5a 100644 --- a/include/criterion/logging.h +++ b/include/criterion/logging.h @@ -25,6 +25,7 @@ # define CRITERION_LOGGING_H_ # include +# include # include "common.h" # include "ordered-set.h" # include "stats.h" @@ -34,12 +35,61 @@ enum criterion_logging_level { CRITERION_IMPORTANT, }; +enum criterion_logging_prefix { + CRITERION_LOGGING_PREFIX_DASHES, + CRITERION_LOGGING_PREFIX_EQUALS, + CRITERION_LOGGING_PREFIX_RUN, + CRITERION_LOGGING_PREFIX_SKIP, + CRITERION_LOGGING_PREFIX_PASS, + CRITERION_LOGGING_PREFIX_FAIL, +}; + +struct criterion_prefix_data { + const char *prefix; + const char *color; +}; + +# ifdef CRITERION_LOGGING_COLORS +# define CRIT_COLOR_NORMALIZE(Str) (criterion_options.use_ascii ? "" : Str) + +# define CRIT_FG_BOLD "\e[0;1m" +# define CRIT_FG_RED "\e[0;31m" +# define CRIT_FG_GREEN "\e[0;32m" +# define CRIT_FG_GOLD "\e[0;33m" +# define CRIT_FG_BLUE "\e[0;34m" +# define CRIT_RESET "\e[0m" + +# define FG_BOLD CRIT_COLOR_NORMALIZE(CRIT_FG_BOLD) +# define FG_RED CRIT_COLOR_NORMALIZE(CRIT_FG_RED) +# define FG_GREEN CRIT_COLOR_NORMALIZE(CRIT_FG_GREEN) +# define FG_GOLD CRIT_COLOR_NORMALIZE(CRIT_FG_GOLD) +# define FG_BLUE CRIT_COLOR_NORMALIZE(CRIT_FG_BLUE) +# define RESET CRIT_COLOR_NORMALIZE(CRIT_RESET) +# endif + +extern const struct criterion_prefix_data g_criterion_logging_prefixes[]; + +# define CRITERION_PREFIX_DASHES (&g_criterion_logging_prefixes[CRITERION_LOGGING_PREFIX_DASHES]) +# define CRITERION_PREFIX_EQUALS (&g_criterion_logging_prefixes[CRITERION_LOGGING_PREFIX_EQUALS]) +# define CRITERION_PREFIX_RUN (&g_criterion_logging_prefixes[CRITERION_LOGGING_PREFIX_RUN ]) +# define CRITERION_PREFIX_SKIP (&g_criterion_logging_prefixes[CRITERION_LOGGING_PREFIX_SKIP ]) +# define CRITERION_PREFIX_PASS (&g_criterion_logging_prefixes[CRITERION_LOGGING_PREFIX_PASS ]) +# define CRITERION_PREFIX_FAIL (&g_criterion_logging_prefixes[CRITERION_LOGGING_PREFIX_EQUALS]) + +void criterion_vlog(enum criterion_logging_level level, const char *msg, va_list args); + +FORMAT(printf, 3, 4) +void criterion_plog(enum criterion_logging_level level, const struct criterion_prefix_data *prefix, const char *msg, ...); + FORMAT(printf, 2, 3) 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__) +# define criterion_pinfo(...) criterion_plog(CRITERION_INFO, __VA_ARGS__) +# define criterion_pimportant(...) criterion_plog(CRITERION_IMPORTANT, __VA_ARGS__) + struct criterion_output_provider { void (*log_pre_all )(struct criterion_test_set *set); void (*log_pre_suite )(struct criterion_suite_set *set); diff --git a/src/i18n.h b/src/i18n.h new file mode 100644 index 0000000..83a62f2 --- /dev/null +++ b/src/i18n.h @@ -0,0 +1,15 @@ +#ifndef I18N_H_ +# define I18N_H_ + +# include "config.h" + +# ifndef I18N +# define _(String) String +# define _s(String, Plural, Quantity) ((Quantity) == 1 ? String : Plural) +# else +# include +# define _(String) dgettext(PACKAGE, String) +# define _s(String, Plural, Quantity) dngettext(PACKAGE, String, Plural, (Quantity)) +# endif + +#endif /* !I18N_H_ */ diff --git a/src/i18n/i18n.h b/src/i18n/i18n.h deleted file mode 100644 index 9f689c3..0000000 --- a/src/i18n/i18n.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef I18N_H_ -# define I18N_H_ - -# include -# include "config.h" - -# define _(String) (dgettext ? dgettext(PACKAGE, String) : String) -# define _s(String, Plural, Quantity) \ - (dgettext ? dngettext(PACKAGE, String, Plural, Quantity) \ - : (Quantity == 1 ? String : Plural)) - -#endif /* !I18N_H_ */ diff --git a/src/log/logging.c b/src/log/logging.c index f26d1e2..5d2bc8d 100644 --- a/src/log/logging.c +++ b/src/log/logging.c @@ -21,18 +21,54 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ +#define CRITERION_LOGGING_COLORS #include #include +#include #include "criterion/logging.h" #include "criterion/options.h" +#include "i18n.h" -void criterion_log(enum criterion_logging_level level, const char *msg, ...) { +#define LOG_FORMAT "[%1$s%2$s%3$s] %4$s" + +const struct criterion_prefix_data g_criterion_logging_prefixes[] = { + [CRITERION_LOGGING_PREFIX_DASHES] = { "----", CRIT_FG_BLUE }, + [CRITERION_LOGGING_PREFIX_EQUALS] = { "====", CRIT_FG_BLUE }, + [CRITERION_LOGGING_PREFIX_RUN] = { "RUN ", CRIT_FG_BLUE }, + [CRITERION_LOGGING_PREFIX_SKIP] = { "SKIP", CRIT_FG_GOLD }, + [CRITERION_LOGGING_PREFIX_PASS] = { "PASS", CRIT_FG_GREEN }, + [CRITERION_LOGGING_PREFIX_FAIL] = { "FAIL", CRIT_FG_RED }, + { NULL } +}; + +void criterion_plog(enum criterion_logging_level level, const struct criterion_prefix_data *prefix, const char *msg, ...) { va_list args; if (level < criterion_options.logging_threshold) return; + char formatted_msg[1024]; va_start(args, msg); - vfprintf(stderr, msg, args); + vsnprintf(formatted_msg, sizeof formatted_msg, msg, args); + va_end(args); + + fprintf(stderr, _(LOG_FORMAT), + CRIT_COLOR_NORMALIZE(prefix->color), + prefix->prefix, + RESET, + formatted_msg); +} + +void criterion_log(enum criterion_logging_level level, const char *msg, ...) { + va_list args; + va_start(args, msg); + criterion_vlog(level, msg, args); va_end(args); } + +void criterion_vlog(enum criterion_logging_level level, const char *msg, va_list args) { + if (level < criterion_options.logging_threshold) + return; + + vfprintf(stderr, msg, args); +} diff --git a/src/log/normal.c b/src/log/normal.c index b4c2d79..9a9f9db 100644 --- a/src/log/normal.c +++ b/src/log/normal.c @@ -22,6 +22,7 @@ * THE SOFTWARE. */ #define _GNU_SOURCE +#define CRITERION_LOGGING_COLORS #include #include #include @@ -31,32 +32,25 @@ #include "criterion/ordered-set.h" #include "timer.h" #include "config.h" - -#define NORMALIZE(Str) (criterion_options.use_ascii ? "" : Str) - -#define FG_BOLD NORMALIZE("\e[0;1m") -#define FG_RED NORMALIZE("\e[0;31m") -#define FG_GREEN NORMALIZE("\e[0;32m") -#define FG_GOLD NORMALIZE("\e[0;33m") -#define FG_BLUE NORMALIZE("\e[0;34m") -#define RESET NORMALIZE("\e[0m") +#include "i18n.h" void normal_log_pre_all(UNUSED struct criterion_test_set *set) { - criterion_info("[%s====%s] Criterion v%s\n", FG_BLUE, RESET, VERSION); + criterion_pinfo(CRITERION_PREFIX_DASHES, _("Criterion v%s\n"), VERSION); } void normal_log_pre_init(struct criterion_test *test) { - criterion_info("[%sRUN%s ] %s::%s\n", FG_BLUE, RESET, test->category, test->name); + criterion_pinfo(CRITERION_PREFIX_RUN, _("%1$s::%2$s\n"), test->category, test->name); } void normal_log_post_test(struct criterion_test_stats *stats) { - const char *format = can_measure_time() ? "%s::%s: (%3.2fs)\n" : "%s::%s\n"; - const enum criterion_logging_level level = stats->failed ? CRITERION_IMPORTANT - : CRITERION_INFO; - const char *color = stats->failed ? FG_RED : FG_GREEN; + const char *format = can_measure_time() ? "%1$s::%2$s: (%3$3.2fs)\n" : "%1$s::%2$s\n"; - criterion_log(level, "[%s%s%s] ", color, stats->failed ? "FAIL" : "PASS", RESET); - criterion_log(level, format, + const enum criterion_logging_level level + = stats->failed ? CRITERION_IMPORTANT : CRITERION_INFO; + const struct criterion_prefix_data *prefix + = stats->failed ? CRITERION_PREFIX_FAIL : CRITERION_PREFIX_PASS; + + criterion_plog(level, prefix, _(format), stats->test->category, stats->test->name, stats->elapsed_time); @@ -70,26 +64,29 @@ static inline bool is_disabled(struct criterion_test *t, struct criterion_suite void normal_log_post_suite(struct criterion_suite_stats *stats) { for (struct criterion_test_stats *ts = stats->tests; ts; ts = ts->next) { if (is_disabled(ts->test, stats->suite)) { - criterion_info("[%sSKIP%s] %s::%s: %s is disabled\n", - FG_GOLD, - RESET, + const char *format = ts->test->data->disabled + ? _("%1$s::%2$s: Test is disabled\n") + : _("%1$s::%2$s: Suite is disabled\n"); + + criterion_pinfo(CRITERION_PREFIX_SKIP, format, ts->test->category, - ts->test->name, - ts->test->data->disabled ? "test" : "suite"); + ts->test->name); } } } void normal_log_post_all(struct criterion_global_stats *stats) { - criterion_important("[%s====%s] ", FG_BLUE, RESET); - criterion_important("%sSynthesis: " SIZE_T_FORMAT " test%s run. " SIZE_T_FORMAT " passed, " SIZE_T_FORMAT " failed (with " SIZE_T_FORMAT " crash%s)%s\n", + criterion_pimportant(CRITERION_PREFIX_EQUALS, + _("%1$sSynthesis: Tested: %2$s%3$lu%4$s " + "| Passing: %5$s%6$lu%7$s " + "| Failing: %8$s%9$lu%10$s " + "| Crashing: %11$s%12$lu%13$s " + "%14$s\n"), FG_BOLD, - stats->nb_tests, - stats->nb_tests == 1 ? " was" : "s were", - stats->tests_passed, - stats->tests_failed, - stats->tests_crashed, - stats->tests_crashed == 1 ? "" : "es", + FG_BLUE, stats->nb_tests, FG_BOLD, + FG_GREEN, stats->tests_passed, FG_BOLD, + FG_RED, stats->tests_failed, FG_BOLD, + FG_RED, stats->tests_crashed, FG_BOLD, RESET); } @@ -98,48 +95,36 @@ void normal_log_assert(struct criterion_assert_stats *stats) { char *dup = strdup(*stats->message ? stats->message : stats->condition), *saveptr = NULL; char *line = strtok_r(dup, "\n", &saveptr); - criterion_important("[%s----%s] ", FG_BLUE, RESET); - criterion_important("%s%s%s:%s%d%s: Assertion failed: %s\n", - FG_BOLD, - stats->file, - RESET, - FG_RED, - stats->line, - RESET, + criterion_pimportant(CRITERION_PREFIX_DASHES, + _("%1$s%2$s%3$s:%4$s%5$d%6$s: Assertion failed: %7$s\n"), + FG_BOLD, stats->file, RESET, + FG_RED, stats->line, RESET, line); while ((line = strtok_r(NULL, "\n", &saveptr))) - criterion_important("[%s----%s] %s\n", FG_BLUE, RESET, line); + criterion_pimportant(CRITERION_PREFIX_DASHES, _(" %s\n"), line); free(dup); } } void normal_log_test_crash(struct criterion_test_stats *stats) { - criterion_important("[%s----%s] ", FG_BLUE, RESET); - criterion_important("%s%s%s:%s%u%s: Unexpected signal caught below this line!\n", - FG_BOLD, - stats->file, - RESET, - FG_RED, - stats->progress, - RESET); - criterion_important("[%sFAIL%s] %s::%s: CRASH!\n", - FG_RED, - RESET, + criterion_pimportant(CRITERION_PREFIX_DASHES, + _("%1$s%2$s%3$s:%4$s%5$u%6$s: " + "Unexpected signal caught below this line!\n"), + FG_BOLD, stats->file, RESET, + FG_RED, stats->progress, RESET); + criterion_pimportant(CRITERION_PREFIX_FAIL, _("%1$s::%2$s: CRASH!\n"), stats->test->category, stats->test->name); } void normal_log_pre_suite(struct criterion_suite_set *set) { - criterion_info("[%s====%s] ", FG_BLUE, RESET); - criterion_info("Running %s" SIZE_T_FORMAT "%s test%s from %s%s%s:\n", - FG_BLUE, - set->tests->size, - RESET, - set->tests->size == 1 ? "" : "s", - FG_GOLD, - set->suite.name, - RESET); + criterion_pinfo(CRITERION_PREFIX_EQUALS, + _s("Running %1$s%2$lu%3$s test from %4$s%5$s%6$s:\n", + "Running %1$s%2$lu%3$s tests from %4$s%5$s%6$s:\n", + set->tests->size), + FG_BLUE, set->tests->size, RESET, + FG_GOLD, set->suite.name, RESET); } struct criterion_output_provider normal_logging = { From 24a20253c5645b87fd7ad96b049a291919b4821a Mon Sep 17 00:00:00 2001 From: Snaipe Date: Wed, 1 Apr 2015 20:42:21 +0200 Subject: [PATCH 21/60] Added i18n initialization --- Makefile.am | 2 ++ src/i18n.c | 8 ++++++++ src/main.c | 3 +++ 3 files changed, 13 insertions(+) create mode 100644 src/i18n.c diff --git a/Makefile.am b/Makefile.am index e880bad..378f18e 100644 --- a/Makefile.am +++ b/Makefile.am @@ -51,6 +51,8 @@ libcriterion_la_SOURCES = \ src/options.c \ src/timer.c \ src/timer.h \ + src/i18n.c \ + src/i18n.h \ src/ordered-set.c \ src/main.c diff --git a/src/i18n.c b/src/i18n.c new file mode 100644 index 0000000..9507789 --- /dev/null +++ b/src/i18n.c @@ -0,0 +1,8 @@ +#include "i18n.h" + +#ifdef I18N +__attribute__ ((constructor)) +void init_i18n(void) { + bindtextdomain (PACKAGE, LOCALEDIR); +} +#endif diff --git a/src/main.c b/src/main.c index 467e49d..f263fd5 100644 --- a/src/main.c +++ b/src/main.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include "runner.h" @@ -118,6 +119,8 @@ int main(int argc, char *argv[]) { {0, 0, 0, 0 } }; + setlocale(LC_ALL, ""); + 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"), From 633e4c63df19087cb10c8dff8852b1334b3e5cb0 Mon Sep 17 00:00:00 2001 From: Snaipe Date: Fri, 3 Apr 2015 20:44:10 +0200 Subject: [PATCH 22/60] Added french translation --- .gitignore | 1 + Makefile.am | 5 ++-- configure.ac | 4 ++- po/LINGUAS | 1 + po/Makevars | 78 ++++++++++++++++++++++++++++++++++++++++++++++++++ po/POTFILES.in | 2 ++ po/fr.po | 68 +++++++++++++++++++++++++++++++++++++++++++ src/main.c | 7 +++++ 8 files changed, 163 insertions(+), 3 deletions(-) create mode 100644 po/LINGUAS create mode 100644 po/Makevars create mode 100644 po/POTFILES.in create mode 100644 po/fr.po diff --git a/.gitignore b/.gitignore index a807c71..c1f4e54 100644 --- a/.gitignore +++ b/.gitignore @@ -7,6 +7,7 @@ !*.h !*.rst !samples/tests/*.sh +!*.po !LICENSE !HEADER diff --git a/Makefile.am b/Makefile.am index 378f18e..884ff44 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,5 +1,6 @@ ACLOCAL_AMFLAGS = -I m4 -SUBDIRS = dependencies/csptr samples +AM_CPPFLAGS = -DLOCALEDIR='"$(localedir)"' +SUBDIRS = po dependencies/csptr samples lib_LTLIBRARIES = libcriterion.la @@ -19,7 +20,7 @@ libcriterion_la_LDFLAGS = $(COVERAGE_LDFLAGS) # dirty but unless someone has a better alternative... libcriterion_la_LIBADD = dependencies/csptr/src/libcsptr_la-*.lo -EXTRA_DIST = LICENSE +EXTRA_DIST = config.rpath LICENSE subdirincludedir = $(includedir)/criterion/ subdirinclude_HEADERS = \ diff --git a/configure.ac b/configure.ac index d095e15..da028eb 100644 --- a/configure.ac +++ b/configure.ac @@ -20,6 +20,8 @@ AC_PROG_LN_S AC_PROG_MAKE_SET AC_SUBST([LIBTOOL_DEPS]) +AM_GNU_GETTEXT([external]) + AC_ARG_ENABLE([gcov], [AS_HELP_STRING([--enable-gcov], [Compile the project with converage enabled])], @@ -31,7 +33,7 @@ AC_ARG_ENABLE([gcov], []) AC_CONFIG_HEADERS([src/config.h]) -AC_CONFIG_FILES([Makefile samples/Makefile]) +AC_CONFIG_FILES([Makefile samples/Makefile po/Makefile.in]) AC_CONFIG_SUBDIRS([dependencies/csptr]) diff --git a/po/LINGUAS b/po/LINGUAS new file mode 100644 index 0000000..527e861 --- /dev/null +++ b/po/LINGUAS @@ -0,0 +1 @@ +fr diff --git a/po/Makevars b/po/Makevars new file mode 100644 index 0000000..70daf30 --- /dev/null +++ b/po/Makevars @@ -0,0 +1,78 @@ +# Makefile variables for PO directory in any package using GNU gettext. + +# Usually the message domain is the same as the package name. +DOMAIN = $(PACKAGE) + +# These two variables depend on the location of this directory. +subdir = po +top_builddir = .. + +# These options get passed to xgettext. +XGETTEXT_OPTIONS = --keyword=_ --keyword=N_ + +# This is the copyright holder that gets inserted into the header of the +# $(DOMAIN).pot file. Set this to the copyright holder of the surrounding +# package. (Note that the msgstr strings, extracted from the package's +# sources, belong to the copyright holder of the package.) Translators are +# expected to transfer the copyright for their translations to this person +# or entity, or to disclaim their copyright. The empty string stands for +# the public domain; in this case the translators are expected to disclaim +# their copyright. +COPYRIGHT_HOLDER = Franklin "Snaipe" Mathieu + +# This tells whether or not to prepend "GNU " prefix to the package +# name that gets inserted into the header of the $(DOMAIN).pot file. +# Possible values are "yes", "no", or empty. If it is empty, try to +# detect it automatically by scanning the files in $(top_srcdir) for +# "GNU packagename" string. +PACKAGE_GNU = no + +# This is the email address or URL to which the translators shall report +# bugs in the untranslated strings: +# - Strings which are not entire sentences, see the maintainer guidelines +# in the GNU gettext documentation, section 'Preparing Strings'. +# - Strings which use unclear terms or require additional context to be +# understood. +# - Strings which make invalid assumptions about notation of date, time or +# money. +# - Pluralisation problems. +# - Incorrect English spelling. +# - Incorrect formatting. +# It can be your email address, or a mailing list address where translators +# can write to without being subscribed, or the URL of a web page through +# which the translators can contact you. +MSGID_BUGS_ADDRESS = + +# This is the list of locale categories, beyond LC_MESSAGES, for which the +# message catalogs shall be used. It is usually empty. +EXTRA_LOCALE_CATEGORIES = + +# This tells whether the $(DOMAIN).pot file contains messages with an 'msgctxt' +# context. Possible values are "yes" and "no". Set this to yes if the +# package uses functions taking also a message context, like pgettext(), or +# if in $(XGETTEXT_OPTIONS) you define keywords with a context argument. +USE_MSGCTXT = no + +# These options get passed to msgmerge. +# Useful options are in particular: +# --previous to keep previous msgids of translated messages, +# --quiet to reduce the verbosity. +MSGMERGE_OPTIONS = + +# These options get passed to msginit. +# If you want to disable line wrapping when writing PO files, add +# --no-wrap to MSGMERGE_OPTIONS, XGETTEXT_OPTIONS, and +# MSGINIT_OPTIONS. +MSGINIT_OPTIONS = + +# This tells whether or not to regenerate a PO file when $(DOMAIN).pot +# has changed. Possible values are "yes" and "no". Set this to no if +# the POT file is checked in the repository and the version control +# program ignores timestamps. +PO_DEPENDS_ON_POT = yes + +# This tells whether or not to forcibly update $(DOMAIN).pot and +# regenerate PO files on "make dist". Possible values are "yes" and +# "no". Set this to no if the POT file and PO files are maintained +# externally. +DIST_DEPENDS_ON_UPDATE_PO = yes diff --git a/po/POTFILES.in b/po/POTFILES.in new file mode 100644 index 0000000..d9d2b16 --- /dev/null +++ b/po/POTFILES.in @@ -0,0 +1,2 @@ +# List of source files which contain translatable strings. +src/log/normal.c diff --git a/po/fr.po b/po/fr.po new file mode 100644 index 0000000..f2a909b --- /dev/null +++ b/po/fr.po @@ -0,0 +1,68 @@ +# French translations for criterion package +# Traductions françaises du paquet criterion. +# Copyright (C) 2015 Franklin "Snaipe" Mathieu +# This file is distributed under the same license as the criterion package. +# , 2015. +# +msgid "" +msgstr "" +"Project-Id-Version: criterion 1.0.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2015-04-03 17:57+0200\n" +"PO-Revision-Date: 2015-04-03 17:58+0200\n" +"Last-Translator: \n" +"Language-Team: French\n" +"Language: fr\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n > 1);\n" + +#: src/log/normal.c:38 +#, c-format +msgid "Criterion v%s\n" +msgstr "Criterion v%s\n" + +#: src/log/normal.c:42 +#, c-format +msgid "%1$s::%2$s\n" +msgstr "%1$s::%2$s\n" + +#: src/log/normal.c:68 +#, c-format +msgid "%1$s::%2$s: Test is disabled\n" +msgstr "%1$s::%2$s: Le test est désactivé\n" + +#: src/log/normal.c:69 +#, c-format +msgid "%1$s::%2$s: Suite is disabled\n" +msgstr "%1$s::%2$s: La suite est désactivée\n" + +#: src/log/normal.c:80 +#, c-format +msgid "" +"%1$sSynthesis: Tested: %2$s%3$lu%4$s | Passing: %5$s%6$lu%7$s | Failing: %8$s" +"%9$lu%10$s | Crashing: %11$s%12$lu%13$s %14$s\n" +msgstr "" +"%1$sSynthèse: Testés: %2$s%3$lu%4$s | Validés: %5$s%6$lu%7$s | Échoués: %8$s" +"%9$lu%10$s | Plantages: %11$s%12$lu%13$s %14$s\n" + +#: src/log/normal.c:99 +#, c-format +msgid "%1$s%2$s%3$s:%4$s%5$d%6$s: Assertion failed: %7$s\n" +msgstr "%1$s%2$s%3$s:%4$s%5$d%6$s: Échec d'assertion: %7$s\n" + +#: src/log/normal.c:105 +#, c-format +msgid " %s\n" +msgstr " %s\n" + +#: src/log/normal.c:112 +#, c-format +msgid "%1$s%2$s%3$s:%4$s%5$u%6$s: Unexpected signal caught below this line!\n" +msgstr "%1$s%2$s%3$s:%4$s%5$u%6$s: Un signal inattendu a été reçu après cette ligne!\n" + +#: src/log/normal.c:116 +#, c-format +msgid "%1$s::%2$s: CRASH!\n" +msgstr "%1$s::%2$s: PLANTAGE!\n" diff --git a/src/main.c b/src/main.c index f263fd5..ada2b99 100644 --- a/src/main.c +++ b/src/main.c @@ -32,6 +32,10 @@ #include "runner.h" #include "config.h" +#ifdef I18N +# include +#endif + # define VERSION_MSG "Tests compiled with Criterion v" VERSION "\n" # define USAGE \ @@ -120,6 +124,9 @@ int main(int argc, char *argv[]) { }; setlocale(LC_ALL, ""); +#ifdef I18N + textdomain (PACKAGE "-test"); +#endif criterion_options = (struct criterion_options) { .always_succeed = !strcmp("1", getenv("CRITERION_ALWAYS_SUCCEED") ?: "0"), From 8efe5bee2871c0abe702ebe51190950c9caf56f2 Mon Sep 17 00:00:00 2001 From: Snaipe Date: Sat, 4 Apr 2015 03:39:32 +0200 Subject: [PATCH 23/60] Added gettext version in configure.ac --- configure.ac | 1 + 1 file changed, 1 insertion(+) diff --git a/configure.ac b/configure.ac index da028eb..7a7822b 100644 --- a/configure.ac +++ b/configure.ac @@ -21,6 +21,7 @@ AC_PROG_MAKE_SET AC_SUBST([LIBTOOL_DEPS]) AM_GNU_GETTEXT([external]) +AM_GNU_GETTEXT_VERSION([0.19.4]) AC_ARG_ENABLE([gcov], [AS_HELP_STRING([--enable-gcov], From d8beebb01b287feb94adba85259f9afacec1877b Mon Sep 17 00:00:00 2001 From: Snaipe Date: Sun, 5 Apr 2015 13:29:32 +0200 Subject: [PATCH 24/60] Made autogen call gettextize before running autoreconf --- autogen.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/autogen.sh b/autogen.sh index 491727c..d8b1d5c 100755 --- a/autogen.sh +++ b/autogen.sh @@ -1,3 +1,4 @@ #!/bin/sh git submodule update --init --recursive +gettextize autoreconf -i From e3fdcdd8f033954e1a762c2594d60331a2960435 Mon Sep 17 00:00:00 2001 From: Snaipe Date: Mon, 6 Apr 2015 17:16:45 +0200 Subject: [PATCH 25/60] gettextize cannot be used in a script --- autogen.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/autogen.sh b/autogen.sh index d8b1d5c..886e91f 100755 --- a/autogen.sh +++ b/autogen.sh @@ -1,4 +1,4 @@ #!/bin/sh git submodule update --init --recursive -gettextize +autopoint autoreconf -i From aff5145088e09d80219a73bd9045eaf2d553adf4 Mon Sep 17 00:00:00 2001 From: Snaipe Date: Mon, 6 Apr 2015 17:26:00 +0200 Subject: [PATCH 26/60] Added gettext packages in CI configuration --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 95ce90a..55f5f64 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,7 +4,7 @@ compiler: before_install: - sudo add-apt-repository ppa:ubuntu-toolchain-r/test -y - sudo apt-get -qq update - - sudo apt-get -qq install -y check gcc-4.9 + - sudo apt-get -qq install -y check gcc-4.9 gettext autopoint - sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-4.9 90 - sudo pip install cpp-coveralls script: From 8dc46e48589fa95d63c61b34bc423a6f33a69120 Mon Sep 17 00:00:00 2001 From: Snaipe Date: Mon, 6 Apr 2015 17:37:18 +0200 Subject: [PATCH 27/60] Use gnu gettext 0.18+ --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 7a7822b..8f43797 100644 --- a/configure.ac +++ b/configure.ac @@ -21,7 +21,7 @@ AC_PROG_MAKE_SET AC_SUBST([LIBTOOL_DEPS]) AM_GNU_GETTEXT([external]) -AM_GNU_GETTEXT_VERSION([0.19.4]) +AM_GNU_GETTEXT_VERSION([0.18]) AC_ARG_ENABLE([gcov], [AS_HELP_STRING([--enable-gcov], From ffefdbb83b5d04256ce0049628e9a82c63ca7da7 Mon Sep 17 00:00:00 2001 From: Snaipe Date: Thu, 9 Apr 2015 12:09:21 +0200 Subject: [PATCH 28/60] Added contribution rules in README --- README.md | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/README.md b/README.md index 4ea9f8d..012e0a1 100644 --- a/README.md +++ b/README.md @@ -58,6 +58,34 @@ Sample tests can be found in the [sample directory][samples]. * [Tests with signals][sample-signal] * [Using report hooks][sample-report] +## Contributing + +Contributions are welcomed, but must follow a simple set of rules in order to +be merged. + +**Please follow these conventions if you want your pull request(s) accepted.** + +### General + +* Use 4 (four) spaces for indentation. +* No trailing whitespaces. +* 80 chars column limit. +* No trash files. Trash files are by-products of the compilation process, or + generated files that does not need to be under version control. +* Pull requests must compile and work properly. +* Pull requests must be mergeable automatically. +* Number of commits in a pull request should be kept to one commit and all + additional commits must be squashed. +* You may have more than one commit in a pull request if the commits are + separate changes, otherwise squash them. + +### Translations + +* You can contribute new translation files for output messages, on the + condition that you are fluent with the language itself. +* Each correction on existing translations must be followed by a + rationale ("why would the translation be better if the change is applied?") + ## F.A.Q. **Q. What's wrong with other test frameworks?** From 0782f9a89dbdfbfd8d5587106c6ea50aae1e92cf Mon Sep 17 00:00:00 2001 From: Snaipe Date: Thu, 9 Apr 2015 22:28:08 +0200 Subject: [PATCH 29/60] [Issue #11] Fixed coverage not being made for forked children --- src/runner.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/runner.c b/src/runner.c index 8c84b1e..e8f7a0d 100644 --- a/src/runner.c +++ b/src/runner.c @@ -223,7 +223,7 @@ int criterion_run_all_tests(void) { unset_runner_process(); if (res == -1) // if this is the test worker terminating - _Exit(0); + exit(0); return criterion_options.always_succeed || res; } From 55bef02069a0a36e883f22e510cf4b2b58129144 Mon Sep 17 00:00:00 2001 From: Snaipe Date: Thu, 9 Apr 2015 22:51:15 +0200 Subject: [PATCH 30/60] Restored full cygwin compatibility (win32 should only be used for timing functions with the cygwin layer) --- src/posix-compat.c | 22 +++++++++++----------- src/posix-compat.h | 6 +++++- 2 files changed, 16 insertions(+), 12 deletions(-) diff --git a/src/posix-compat.c b/src/posix-compat.c index ec1e315..517329e 100644 --- a/src/posix-compat.c +++ b/src/posix-compat.c @@ -1,7 +1,7 @@ #include "posix-compat.h" #include "process.h" -#ifdef _WIN32 +#ifdef VANILLA_WIN32 # define VC_EXTRALEAN # define WIN32_LEAN_AND_MEAN # include @@ -32,7 +32,7 @@ #include struct proc_handle { -#ifdef _WIN32 +#ifdef VANILLA_WIN32 HANDLE handle; #else pid_t pid; @@ -40,7 +40,7 @@ struct proc_handle { }; struct pipe_handle { -#ifdef _WIN32 +#ifdef VANILLA_WIN32 HANDLE fhs[2]; #else int fds[2]; @@ -49,7 +49,7 @@ struct pipe_handle { struct worker_context g_worker_context = {.test = NULL}; -#ifdef _WIN32 +#ifdef VANILLA_WIN32 static struct criterion_test child_test; static struct criterion_test_extra_data child_test_data; static struct criterion_suite child_suite; @@ -66,7 +66,7 @@ int resume_child(void) { } s_proc_handle *fork_process() { -#ifdef _WIN32 +#ifdef VANILLA_WIN32 PROCESS_INFORMATION info; STARTUPINFOW si = { .cb = sizeof (STARTUPINFOW) }; @@ -117,7 +117,7 @@ s_proc_handle *fork_process() { } void wait_process(s_proc_handle *handle, int *status) { -#ifdef _WIN32 +#ifdef VANILLA_WIN32 WaitForSingleObject(handle->handle, INFINITE); DWORD exit_code; GetExitCodeProcess(handle->handle, &exit_code); @@ -129,7 +129,7 @@ void wait_process(s_proc_handle *handle, int *status) { } FILE *pipe_in(s_pipe_handle *p) { -#ifdef _WIN32 +#ifdef VANILLA_WIN32 CloseHandle(p->fhs[1]); int fd = _open_osfhandle((intptr_t) p->fhs[0], _O_RDONLY); if (fd == -1) @@ -147,7 +147,7 @@ FILE *pipe_in(s_pipe_handle *p) { } FILE *pipe_out(s_pipe_handle *p) { -#ifdef _WIN32 +#ifdef VANILLA_WIN32 CloseHandle(p->fhs[0]); int fd = _open_osfhandle((intptr_t) p->fhs[1], _O_WRONLY); if (fd == -1) @@ -165,7 +165,7 @@ FILE *pipe_out(s_pipe_handle *p) { } s_pipe_handle *stdpipe() { -#ifdef _WIN32 +#ifdef VANILLA_WIN32 HANDLE fhs[2]; SECURITY_ATTRIBUTES attr = { .nLength = sizeof (SECURITY_ATTRIBUTES), .bInheritHandle = TRUE }; if (!CreatePipe(fhs, fhs + 1, &attr, 0)) @@ -180,7 +180,7 @@ s_pipe_handle *stdpipe() { } s_proc_handle *get_current_process() { -#ifdef _WIN32 +#ifdef VANILLA_WIN32 return unique_ptr(s_proc_handle, { GetCurrentProcess() }); #else return unique_ptr(s_proc_handle, { getpid() }); @@ -188,7 +188,7 @@ s_proc_handle *get_current_process() { } bool is_current_process(s_proc_handle *proc) { -#ifdef _WIN32 +#ifdef VANILLA_WIN32 return GetProcessId(proc->handle) == GetProcessId(GetCurrentProcess()); #else return proc->pid == getpid(); diff --git a/src/posix-compat.h b/src/posix-compat.h index 3c32e9c..5faa151 100644 --- a/src/posix-compat.h +++ b/src/posix-compat.h @@ -1,6 +1,10 @@ #ifndef POSIX_COMPAT_H_ # define POSIX_COMPAT_H_ +#if defined(_WIN32) && !defined(__CYGWIN__) +# define VANILLA_WIN32 +#endif + # if !defined(_POSIX_SOURCE) # define _POSIX_SOURCE 1 # define TMP_POSIX @@ -11,7 +15,7 @@ # undef TMP_POSIX # endif -# ifdef _WIN32 +# ifdef VANILLA_WIN32 # define WEXITSTATUS(Status) (((Status) & 0xFF00) >> 8) # define WTERMSIG(Status) ((Status) & 0x7F) # define WIFEXITED(Status) (WTERMSIG(Status) == 0) From e255e5deadc9e3a295fac518568808b39eb932ee Mon Sep 17 00:00:00 2001 From: Snaipe Date: Fri, 10 Apr 2015 00:30:34 +0200 Subject: [PATCH 31/60] Switched to ENABLE_NLS macro instead of rolling our own --- src/i18n.c | 2 +- src/i18n.h | 2 +- src/main.c | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/i18n.c b/src/i18n.c index 9507789..5b9899b 100644 --- a/src/i18n.c +++ b/src/i18n.c @@ -1,6 +1,6 @@ #include "i18n.h" -#ifdef I18N +#if ENABLE_NLS __attribute__ ((constructor)) void init_i18n(void) { bindtextdomain (PACKAGE, LOCALEDIR); diff --git a/src/i18n.h b/src/i18n.h index 83a62f2..260c788 100644 --- a/src/i18n.h +++ b/src/i18n.h @@ -3,7 +3,7 @@ # include "config.h" -# ifndef I18N +# if !ENABLE_NLS # define _(String) String # define _s(String, Plural, Quantity) ((Quantity) == 1 ? String : Plural) # else diff --git a/src/main.c b/src/main.c index eaaeaa8..19c7fcd 100644 --- a/src/main.c +++ b/src/main.c @@ -32,7 +32,7 @@ #include "runner.h" #include "config.h" -#ifdef I18N +#if ENABLE_NLS # include #endif @@ -136,7 +136,7 @@ int main(int argc, char *argv[]) { || !strcmp("dumb", getenv("TERM") ?: "dumb"); setlocale(LC_ALL, ""); -#ifdef I18N +#if ENABLE_NLS textdomain (PACKAGE "-test"); #endif From 7f75797e90812c27f8cbcfd351f2aaa651e4bdc8 Mon Sep 17 00:00:00 2001 From: Snaipe Date: Fri, 10 Apr 2015 00:31:14 +0200 Subject: [PATCH 32/60] Updated po files to latest source match --- po/fr.po | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/po/fr.po b/po/fr.po index f2a909b..ba1069f 100644 --- a/po/fr.po +++ b/po/fr.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: criterion 1.0.0\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2015-04-03 17:57+0200\n" +"POT-Creation-Date: 2015-04-10 00:15+0200\n" "PO-Revision-Date: 2015-04-03 17:58+0200\n" "Last-Translator: \n" "Language-Team: French\n" @@ -28,17 +28,22 @@ msgstr "Criterion v%s\n" msgid "%1$s::%2$s\n" msgstr "%1$s::%2$s\n" -#: src/log/normal.c:68 +#: src/log/normal.c:44 src/log/normal.c:110 +#, c-format +msgid " %s\n" +msgstr " %s\n" + +#: src/log/normal.c:70 #, c-format msgid "%1$s::%2$s: Test is disabled\n" msgstr "%1$s::%2$s: Le test est désactivé\n" -#: src/log/normal.c:69 +#: src/log/normal.c:71 #, c-format msgid "%1$s::%2$s: Suite is disabled\n" msgstr "%1$s::%2$s: La suite est désactivée\n" -#: src/log/normal.c:80 +#: src/log/normal.c:85 #, c-format msgid "" "%1$sSynthesis: Tested: %2$s%3$lu%4$s | Passing: %5$s%6$lu%7$s | Failing: %8$s" @@ -47,22 +52,19 @@ msgstr "" "%1$sSynthèse: Testés: %2$s%3$lu%4$s | Validés: %5$s%6$lu%7$s | Échoués: %8$s" "%9$lu%10$s | Plantages: %11$s%12$lu%13$s %14$s\n" -#: src/log/normal.c:99 +#: src/log/normal.c:104 #, c-format msgid "%1$s%2$s%3$s:%4$s%5$d%6$s: Assertion failed: %7$s\n" msgstr "%1$s%2$s%3$s:%4$s%5$d%6$s: Échec d'assertion: %7$s\n" -#: src/log/normal.c:105 -#, c-format -msgid " %s\n" -msgstr " %s\n" - -#: src/log/normal.c:112 +#: src/log/normal.c:117 #, c-format msgid "%1$s%2$s%3$s:%4$s%5$u%6$s: Unexpected signal caught below this line!\n" -msgstr "%1$s%2$s%3$s:%4$s%5$u%6$s: Un signal inattendu a été reçu après cette ligne!\n" +msgstr "" +"%1$s%2$s%3$s:%4$s%5$u%6$s: Un signal inattendu a été reçu après cette " +"ligne!\n" -#: src/log/normal.c:116 +#: src/log/normal.c:121 #, c-format msgid "%1$s::%2$s: CRASH!\n" msgstr "%1$s::%2$s: PLANTAGE!\n" From fe65034ecd0c07c7a81ed9d8495541c698bcef4b Mon Sep 17 00:00:00 2001 From: Snaipe Date: Fri, 10 Apr 2015 00:33:57 +0200 Subject: [PATCH 33/60] Preemptively cast size_t's to unsigned long for compatibility issues on localized format strings --- src/log/normal.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/log/normal.c b/src/log/normal.c index c961ccb..69099cc 100644 --- a/src/log/normal.c +++ b/src/log/normal.c @@ -88,10 +88,10 @@ void normal_log_post_all(struct criterion_global_stats *stats) { "| Crashing: %11$s%12$lu%13$s " "%14$s\n"), FG_BOLD, - FG_BLUE, stats->nb_tests, FG_BOLD, - FG_GREEN, stats->tests_passed, FG_BOLD, - FG_RED, stats->tests_failed, FG_BOLD, - FG_RED, stats->tests_crashed, FG_BOLD, + FG_BLUE, (unsigned long) stats->nb_tests, FG_BOLD, + FG_GREEN, (unsigned long) stats->tests_passed, FG_BOLD, + FG_RED, (unsigned long) stats->tests_failed, FG_BOLD, + FG_RED, (unsigned long) stats->tests_crashed, FG_BOLD, RESET); } @@ -128,7 +128,7 @@ void normal_log_pre_suite(struct criterion_suite_set *set) { _s("Running %1$s%2$lu%3$s test from %4$s%5$s%6$s:\n", "Running %1$s%2$lu%3$s tests from %4$s%5$s%6$s:\n", set->tests->size), - FG_BLUE, set->tests->size, RESET, + FG_BLUE, (unsigned long) set->tests->size, RESET, FG_GOLD, set->suite.name, RESET); } From 260b88c5d77c3199331d0ab26c7790ba4fcadac4 Mon Sep 17 00:00:00 2001 From: Snaipe Date: Fri, 10 Apr 2015 01:03:58 +0200 Subject: [PATCH 34/60] Boyscouting --- include/criterion/ordered-set.h | 18 ++++++++++++------ src/event.c | 8 ++++++-- src/i18n.h | 3 ++- src/log/normal.c | 23 ++++++++++++++++------- src/options.c | 4 +++- src/ordered-set.c | 11 ++++++++--- src/posix-compat.c | 28 ++++++++++++++++++++-------- src/posix-compat.h | 8 ++++---- src/process.c | 14 +++++++++++--- src/report.c | 24 +++++++++++++++--------- src/runner.c | 19 +++++++++++++++---- 11 files changed, 112 insertions(+), 48 deletions(-) diff --git a/include/criterion/ordered-set.h b/include/criterion/ordered-set.h index a8d1b11..4b71081 100644 --- a/include/criterion/ordered-set.h +++ b/include/criterion/ordered-set.h @@ -26,10 +26,12 @@ # include "types.h" +typedef int (*f_criterion_cmp)(void *, void *); + struct criterion_ordered_set { struct criterion_ordered_set_node *first; size_t size; - int (*const cmp)(void *, void *); + f_criterion_cmp cmp; void (*const dtor)(void *, void *); }; @@ -48,12 +50,16 @@ struct criterion_test_set { size_t tests; }; -struct criterion_ordered_set *new_ordered_set(int (*cmp)(void *, void *), void (*dtor)(void *, void *)); -void *insert_ordered_set(struct criterion_ordered_set *l, void *ptr, size_t size); +struct criterion_ordered_set *new_ordered_set(f_criterion_cmp cmp, + void (*dtor)(void *, void *)); -# define FOREACH_SET(Elt, Set) \ - for (struct criterion_ordered_set_node *n = Set->first; n; n = n->next) \ - for (int cond = 1; cond;) \ +void *insert_ordered_set(struct criterion_ordered_set *l, + void *ptr, + size_t size); + +# define FOREACH_SET(Elt, Set) \ + for (struct criterion_ordered_set_node *n = Set->first; n; n = n->next) \ + for (int cond = 1; cond;) \ for (Elt = (void*) n->data; cond && (cond = 0, 1);) #endif /* !CRITERION_ORDERED_SET_H_ */ diff --git a/src/event.c b/src/event.c index a6a8b3d..cca6ce6 100644 --- a/src/event.c +++ b/src/event.c @@ -48,14 +48,18 @@ struct event *read_event(FILE *f) { if (fread(buf, assert_size, 1, f) == 0) return NULL; - return unique_ptr(struct event, { .kind = kind, .data = buf }, destroy_event); + return unique_ptr(struct event, + .value = { .kind = kind, .data = buf }, + .dtor = destroy_event); } case POST_TEST: { double *elapsed_time = malloc(sizeof (double)); if (fread(elapsed_time, sizeof (double), 1, f) == 0) return NULL; - return unique_ptr(struct event, { .kind = kind, .data = elapsed_time }, destroy_event); + return unique_ptr(struct event, + .value = { .kind = kind, .data = elapsed_time }, + .dtor = destroy_event); } default: return unique_ptr(struct event, { .kind = kind, .data = NULL }); diff --git a/src/i18n.h b/src/i18n.h index 260c788..74c159e 100644 --- a/src/i18n.h +++ b/src/i18n.h @@ -9,7 +9,8 @@ # else # include # define _(String) dgettext(PACKAGE, String) -# define _s(String, Plural, Quantity) dngettext(PACKAGE, String, Plural, (Quantity)) +# define _s(String, Plural, Quantity) \ + dngettext(PACKAGE, String, Plural, (Quantity)) # endif #endif /* !I18N_H_ */ diff --git a/src/log/normal.c b/src/log/normal.c index 69099cc..c696516 100644 --- a/src/log/normal.c +++ b/src/log/normal.c @@ -39,13 +39,18 @@ void normal_log_pre_all(UNUSED struct criterion_test_set *set) { } void normal_log_pre_init(struct criterion_test *test) { - criterion_pinfo(CRITERION_PREFIX_RUN, _("%1$s::%2$s\n"), test->category, test->name); + criterion_pinfo(CRITERION_PREFIX_RUN, _("%1$s::%2$s\n"), + test->category, + test->name); + if (test->data->description) - criterion_pinfo(CRITERION_PREFIX_RUN, _(" %s\n"), test->data->description); + criterion_pinfo(CRITERION_PREFIX_RUN, _(" %s\n"), + test->data->description); } void normal_log_post_test(struct criterion_test_stats *stats) { - const char *format = can_measure_time() ? "%1$s::%2$s: (%3$3.2fs)\n" : "%1$s::%2$s\n"; + const char *format = can_measure_time() ? "%1$s::%2$s: (%3$3.2fs)\n" + : "%1$s::%2$s\n"; const enum criterion_logging_level level = stats->failed ? CRITERION_IMPORTANT : CRITERION_INFO; @@ -59,7 +64,8 @@ void normal_log_post_test(struct criterion_test_stats *stats) { } __attribute__((always_inline)) -static inline bool is_disabled(struct criterion_test *t, struct criterion_suite *s) { +static inline bool is_disabled(struct criterion_test *t, + struct criterion_suite *s) { return t->data->disabled || (s->data && s->data->disabled); } @@ -75,7 +81,8 @@ void normal_log_post_suite(struct criterion_suite_stats *stats) { ts->test->name); if (ts->test->data->description) - criterion_pinfo(CRITERION_PREFIX_DASHES, " %s\n", ts->test->data->description); + criterion_pinfo(CRITERION_PREFIX_DASHES, " %s\n", + ts->test->data->description); } } } @@ -97,8 +104,10 @@ void normal_log_post_all(struct criterion_global_stats *stats) { void normal_log_assert(struct criterion_assert_stats *stats) { if (!stats->passed) { - char *dup = strdup(*stats->message ? stats->message : stats->condition), *saveptr = NULL; - char *line = strtok_r(dup, "\n", &saveptr); + char *dup = strdup(*stats->message ? stats->message + : stats->condition); + char *saveptr = NULL; + char *line = strtok_r(dup, "\n", &saveptr); criterion_pimportant(CRITERION_PREFIX_DASHES, _("%1$s%2$s%3$s:%4$s%5$d%6$s: Assertion failed: %7$s\n"), diff --git a/src/options.c b/src/options.c index 9b47c44..21fcef8 100644 --- a/src/options.c +++ b/src/options.c @@ -23,4 +23,6 @@ */ # include "criterion/options.h" -struct criterion_options criterion_options = { .logging_threshold = CRITERION_IMPORTANT }; +struct criterion_options criterion_options = { + .logging_threshold = CRITERION_IMPORTANT, +}; diff --git a/src/ordered-set.c b/src/ordered-set.c index 220b56a..9386b59 100644 --- a/src/ordered-set.c +++ b/src/ordered-set.c @@ -39,12 +39,17 @@ static void destroy_ordered_set_node(void *ptr, void *meta) { sfree(((struct criterion_ordered_set_node *) ptr)->next); } -struct criterion_ordered_set *new_ordered_set(int (*cmp)(void *, void *), f_destructor dtor) { +struct criterion_ordered_set *new_ordered_set(f_criterion_cmp cmp, + f_destructor dtor) { + return unique_ptr(struct criterion_ordered_set, - { .cmp = cmp, .dtor = dtor }, destroy_ordered_set); + .value = { .cmp = cmp, .dtor = dtor }, + .dtor = destroy_ordered_set); } -void *insert_ordered_set(struct criterion_ordered_set *l, void *ptr, size_t size) { +void *insert_ordered_set(struct criterion_ordered_set *l, + void *ptr, + size_t size) { int cmp; struct criterion_ordered_set_node *n, *prev = NULL; for (n = l->first; n && (cmp = l->cmp(ptr, n->data)) > 0; n = n->next) diff --git a/src/posix-compat.c b/src/posix-compat.c index 517329e..e68f848 100644 --- a/src/posix-compat.c +++ b/src/posix-compat.c @@ -22,6 +22,9 @@ &(StartupInfo), \ &(Info)) +# define WRITE_PROCESS_(Proc, What, Size) \ + WriteProcessMemory(Proc, &What, &What, Size, NULL); + #else # include # include @@ -87,20 +90,26 @@ s_proc_handle *fork_process() { child_suite = *g_worker_context.suite; child_pipe = *g_worker_context.pipe; - g_worker_context = (struct worker_context) { &child_test, &child_suite, child_func, &child_pipe }; + g_worker_context = (struct worker_context) { + &child_test, + &child_suite, + child_func, + &child_pipe + }; + child_test.data = &child_test_data; if (g_worker_context.suite->data) { child_suite_data = *g_worker_context.suite->data; child_suite.data = &child_suite_data; - WriteProcessMemory(info.hProcess, &child_suite_data, &child_suite_data, sizeof (child_suite_data), NULL); + WRITE_PROCESS_(info.hProcess, child_suite_data, sizeof (child_suite_data)); } - WriteProcessMemory(info.hProcess, &child_test, &child_test, sizeof (child_test), NULL); - WriteProcessMemory(info.hProcess, &child_test_data, &child_test_data, sizeof (child_test_data), NULL); - WriteProcessMemory(info.hProcess, &child_suite, &child_suite, sizeof (child_suite), NULL); - WriteProcessMemory(info.hProcess, &child_pipe, &child_pipe, sizeof (child_pipe), NULL); - WriteProcessMemory(info.hProcess, &g_worker_context, &g_worker_context, sizeof (struct worker_context), NULL); + WRITE_PROCESS_(info.hProcess, child_test, sizeof (child_test)); + WRITE_PROCESS_(info.hProcess, child_test_data, sizeof (child_test_data)); + WRITE_PROCESS_(info.hProcess, child_suite, sizeof (child_suite)); + WRITE_PROCESS_(info.hProcess, child_pipe, sizeof (child_pipe)); + WRITE_PROCESS_(info.hProcess, g_worker_context, sizeof (struct worker_context)); ResumeThread(info.hThread); CloseHandle(info.hThread); @@ -167,7 +176,10 @@ FILE *pipe_out(s_pipe_handle *p) { s_pipe_handle *stdpipe() { #ifdef VANILLA_WIN32 HANDLE fhs[2]; - SECURITY_ATTRIBUTES attr = { .nLength = sizeof (SECURITY_ATTRIBUTES), .bInheritHandle = TRUE }; + SECURITY_ATTRIBUTES attr = { + .nLength = sizeof (SECURITY_ATTRIBUTES), + .bInheritHandle = TRUE + }; if (!CreatePipe(fhs, fhs + 1, &attr, 0)) return NULL; return unique_ptr(s_pipe_handle, {{ fhs[0], fhs[1] }}); diff --git a/src/posix-compat.h b/src/posix-compat.h index 5faa151..477361e 100644 --- a/src/posix-compat.h +++ b/src/posix-compat.h @@ -16,10 +16,10 @@ # endif # ifdef VANILLA_WIN32 -# define WEXITSTATUS(Status) (((Status) & 0xFF00) >> 8) -# define WTERMSIG(Status) ((Status) & 0x7F) -# define WIFEXITED(Status) (WTERMSIG(Status) == 0) -# define WIFSIGNALED(Status) (((signed char) (WTERMSIG(Status) + 1) >> 1) > 0) +# define WEXITSTATUS(Status) (((Status) & 0xFF00) >> 8) +# define WTERMSIG(Status) ((Status) & 0x7F) +# define WIFEXITED(Status) (WTERMSIG(Status) == 0) +# define WIFSIGNALED(Status) (((signed char) (WTERMSIG(Status) + 1) >> 1) > 0) # else # include # endif diff --git a/src/process.c b/src/process.c index 83afc73..d3a5f9e 100644 --- a/src/process.c +++ b/src/process.c @@ -94,7 +94,9 @@ struct process *spawn_test_worker(struct criterion_test *test, return NULL; } - return unique_ptr(struct process, { .proc = proc, .in = pipe_in(pipe) }, close_process); + return unique_ptr(struct process, + .value = { .proc = proc, .in = pipe_in(pipe) }, + .dtor = close_process); } struct process_status wait_proc(struct process *proc) { @@ -102,10 +104,16 @@ struct process_status wait_proc(struct process *proc) { wait_process(proc->proc, &status); if (WIFEXITED(status)) - return (struct process_status) { .kind = EXIT_STATUS, .status = WEXITSTATUS(status) }; + return (struct process_status) { + .kind = EXIT_STATUS, + .status = WEXITSTATUS(status) + }; if (WIFSIGNALED(status)) - return (struct process_status) { .kind = SIGNAL, .status = WTERMSIG(status) }; + return (struct process_status) { + .kind = SIGNAL, + .status = WTERMSIG(status) + }; return (struct process_status) { .kind = STOPPED }; } diff --git a/src/report.c b/src/report.c index 542f813..140e628 100644 --- a/src/report.c +++ b/src/report.c @@ -56,18 +56,24 @@ __attribute__((always_inline)) static inline void nothing() {} +#ifdef HAVE_FNMATCH +void disable_unmatching(struct criterion_test_set *set) { + 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 (fnmatch(criterion_options.pattern, test->data->identifier_, 0)) + test->data->disabled = true; + } + } +} +#endif + IMPL_REPORT_HOOK(PRE_ALL)(struct criterion_test_set *set) { #ifdef HAVE_FNMATCH if (criterion_options.pattern) { - 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 (fnmatch(criterion_options.pattern, test->data->identifier_, 0)) - test->data->disabled = true; - } - } + disable_unmatching(set); } #endif log(pre_all, set); diff --git a/src/runner.c b/src/runner.c index e8f7a0d..719e090 100644 --- a/src/runner.c +++ b/src/runner.c @@ -38,6 +38,7 @@ IMPL_SECTION_LIMITS(struct criterion_test, criterion_tests); IMPL_SECTION_LIMITS(struct criterion_suite, crit_suites); +// This is here to make the test suite section non-empty TestSuite(default); int cmp_suite(void *a, void *b) { @@ -95,7 +96,10 @@ typedef void (*f_test_run)(struct criterion_global_stats *, struct criterion_test *, struct criterion_suite *); -static void map_tests(struct criterion_test_set *set, struct criterion_global_stats *stats, f_test_run fun) { +static void map_tests(struct criterion_test_set *set, + struct criterion_global_stats *stats, + f_test_run fun) { + FOREACH_SET(struct criterion_suite_set *s, set->suites) { if (!s->tests) continue; @@ -122,7 +126,9 @@ static void map_tests(struct criterion_test_set *set, struct criterion_global_st __attribute__ ((always_inline)) static inline void nothing() {} -static void run_test_child(struct criterion_test *test, struct criterion_suite *suite) { +static void run_test_child(struct criterion_test *test, + struct criterion_suite *suite) { + send_event(PRE_INIT, NULL, 0); if (suite->data) (suite->data->init ?: nothing)(); @@ -144,7 +150,9 @@ static void run_test_child(struct criterion_test *test, struct criterion_suite * } __attribute__((always_inline)) -static inline bool is_disabled(struct criterion_test *t, struct criterion_suite *s) { +static inline bool is_disabled(struct criterion_test *t, + struct criterion_suite *s) { + return t->data->disabled || (s->data && s->data->disabled); } @@ -165,7 +173,10 @@ static void run_test(struct criterion_global_stats *stats, smart struct criterion_test_stats *test_stats = test_stats_init(test); if (is_disabled(test, suite)) { - stat_push_event(stats, suite_stats, test_stats, &(struct event) { .kind = PRE_TEST }); + stat_push_event(stats, + suite_stats, + test_stats, + &(struct event) { .kind = PRE_TEST }); return; } From 8a29e3e79228098c18d21eed099eee591fd949a1 Mon Sep 17 00:00:00 2001 From: Snaipe Date: Fri, 10 Apr 2015 22:50:30 +0200 Subject: [PATCH 35/60] [Issue #15] Fixed inaccurate statistics on disabled tests --- include/criterion/stats.h | 2 ++ src/log/normal.c | 4 +++- src/stats.c | 12 ++++++++++++ 3 files changed, 17 insertions(+), 1 deletion(-) diff --git a/include/criterion/stats.h b/include/criterion/stats.h index 6d84e8c..8a1b4e7 100644 --- a/include/criterion/stats.h +++ b/include/criterion/stats.h @@ -56,6 +56,7 @@ struct criterion_suite_stats { struct criterion_test_stats *tests; size_t nb_tests; size_t nb_asserts; + size_t tests_skipped; size_t tests_failed; size_t tests_crashed; size_t tests_passed; @@ -70,6 +71,7 @@ struct criterion_global_stats { size_t nb_suites; size_t nb_tests; size_t nb_asserts; + size_t tests_skipped; size_t tests_failed; size_t tests_crashed; size_t tests_passed; diff --git a/src/log/normal.c b/src/log/normal.c index c696516..eff52f6 100644 --- a/src/log/normal.c +++ b/src/log/normal.c @@ -88,6 +88,8 @@ void normal_log_post_suite(struct criterion_suite_stats *stats) { } void normal_log_post_all(struct criterion_global_stats *stats) { + size_t tested = stats->nb_tests - stats->tests_skipped; + criterion_pimportant(CRITERION_PREFIX_EQUALS, _("%1$sSynthesis: Tested: %2$s%3$lu%4$s " "| Passing: %5$s%6$lu%7$s " @@ -95,7 +97,7 @@ void normal_log_post_all(struct criterion_global_stats *stats) { "| Crashing: %11$s%12$lu%13$s " "%14$s\n"), FG_BOLD, - FG_BLUE, (unsigned long) stats->nb_tests, FG_BOLD, + FG_BLUE, (unsigned long) tested, FG_BOLD, FG_GREEN, (unsigned long) stats->tests_passed, FG_BOLD, FG_RED, (unsigned long) stats->tests_failed, FG_BOLD, FG_RED, (unsigned long) stats->tests_crashed, FG_BOLD, diff --git a/src/stats.c b/src/stats.c index a817ec3..fcc5fb5 100644 --- a/src/stats.c +++ b/src/stats.c @@ -106,6 +106,13 @@ static void push_pre_suite(s_glob_stats *stats, ++stats->nb_suites; } +__attribute__((always_inline)) +static inline bool is_disabled(struct criterion_test *t, + struct criterion_suite *s) { + + return t->data->disabled || (s->data && s->data->disabled); +} + static void push_pre_test(s_glob_stats *stats, s_suite_stats *suite, s_test_stats *test, @@ -114,6 +121,11 @@ static void push_pre_test(s_glob_stats *stats, suite->tests = sref(test); ++stats->nb_tests; ++suite->nb_tests; + + if (is_disabled(test->test, suite->suite)) { + ++stats->tests_skipped; + ++suite->tests_skipped; + } } static void destroy_assert(void *ptr, UNUSED void *meta) { From 14aa37594d6a77d546f28c7c8b205e2df96d2d5e Mon Sep 17 00:00:00 2001 From: Snaipe Date: Fri, 10 Apr 2015 23:21:03 +0200 Subject: [PATCH 36/60] [Issue #15] Fixed incorrect reporting on setup/teardown crash --- include/criterion/logging.h | 21 +++++++++++---------- po/fr.po | 23 +++++++++++++++-------- src/log/normal.c | 23 +++++++++++++++-------- src/report.c | 3 --- src/report.h | 3 +++ src/runner.c | 20 ++++++++++++++++++-- src/stats.c | 8 ++++---- 7 files changed, 66 insertions(+), 35 deletions(-) diff --git a/include/criterion/logging.h b/include/criterion/logging.h index 86aed5a..bec9959 100644 --- a/include/criterion/logging.h +++ b/include/criterion/logging.h @@ -91,16 +91,17 @@ void criterion_log(enum criterion_logging_level level, const char *msg, ...); # define criterion_pimportant(...) criterion_plog(CRITERION_IMPORTANT, __VA_ARGS__) struct criterion_output_provider { - 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); - 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_suite)(struct criterion_suite_stats *stats); - void (*log_post_all )(struct criterion_global_stats *stats); + 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); + 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_other_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_suite )(struct criterion_suite_stats *stats); + void (*log_post_all )(struct criterion_global_stats *stats); }; extern struct criterion_output_provider normal_logging; diff --git a/po/fr.po b/po/fr.po index ba1069f..ffbd217 100644 --- a/po/fr.po +++ b/po/fr.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: criterion 1.0.0\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2015-04-10 00:15+0200\n" +"POT-Creation-Date: 2015-04-10 23:08+0200\n" "PO-Revision-Date: 2015-04-03 17:58+0200\n" "Last-Translator: \n" "Language-Team: French\n" @@ -28,22 +28,22 @@ msgstr "Criterion v%s\n" msgid "%1$s::%2$s\n" msgstr "%1$s::%2$s\n" -#: src/log/normal.c:44 src/log/normal.c:110 +#: src/log/normal.c:47 src/log/normal.c:121 #, c-format msgid " %s\n" msgstr " %s\n" -#: src/log/normal.c:70 +#: src/log/normal.c:76 #, c-format msgid "%1$s::%2$s: Test is disabled\n" msgstr "%1$s::%2$s: Le test est désactivé\n" -#: src/log/normal.c:71 +#: src/log/normal.c:77 #, c-format msgid "%1$s::%2$s: Suite is disabled\n" msgstr "%1$s::%2$s: La suite est désactivée\n" -#: src/log/normal.c:85 +#: src/log/normal.c:94 #, c-format msgid "" "%1$sSynthesis: Tested: %2$s%3$lu%4$s | Passing: %5$s%6$lu%7$s | Failing: %8$s" @@ -52,19 +52,26 @@ msgstr "" "%1$sSynthèse: Testés: %2$s%3$lu%4$s | Validés: %5$s%6$lu%7$s | Échoués: %8$s" "%9$lu%10$s | Plantages: %11$s%12$lu%13$s %14$s\n" -#: src/log/normal.c:104 +#: src/log/normal.c:115 #, c-format msgid "%1$s%2$s%3$s:%4$s%5$d%6$s: Assertion failed: %7$s\n" msgstr "%1$s%2$s%3$s:%4$s%5$d%6$s: Échec d'assertion: %7$s\n" -#: src/log/normal.c:117 +#: src/log/normal.c:128 #, c-format msgid "%1$s%2$s%3$s:%4$s%5$u%6$s: Unexpected signal caught below this line!\n" msgstr "" "%1$s%2$s%3$s:%4$s%5$u%6$s: Un signal inattendu a été reçu après cette " "ligne!\n" -#: src/log/normal.c:121 +#: src/log/normal.c:132 #, c-format msgid "%1$s::%2$s: CRASH!\n" msgstr "%1$s::%2$s: PLANTAGE!\n" + +#: src/log/normal.c:139 +#, c-format +msgid "%1$sWarning! This test crashed during its setup or teardown.%2$s\n" +msgstr "" +"%1$sAttention! Ce test a planté pendant son initialisation ou sa " +"finalisation.%2$s\n" diff --git a/src/log/normal.c b/src/log/normal.c index eff52f6..42645be 100644 --- a/src/log/normal.c +++ b/src/log/normal.c @@ -134,6 +134,12 @@ void normal_log_test_crash(struct criterion_test_stats *stats) { stats->test->name); } +void normal_log_other_crash(UNUSED struct criterion_test_stats *stats) { + criterion_pimportant(CRITERION_PREFIX_DASHES, + _("%1$sWarning! This test crashed during its setup or teardown.%2$s\n"), + FG_BOLD, RESET); +} + void normal_log_pre_suite(struct criterion_suite_set *set) { criterion_pinfo(CRITERION_PREFIX_EQUALS, _s("Running %1$s%2$lu%3$s test from %4$s%5$s%6$s:\n", @@ -144,12 +150,13 @@ void normal_log_pre_suite(struct criterion_suite_set *set) { } struct criterion_output_provider normal_logging = { - .log_pre_all = normal_log_pre_all, - .log_pre_init = normal_log_pre_init, - .log_pre_suite = normal_log_pre_suite, - .log_assert = normal_log_assert, - .log_test_crash = normal_log_test_crash, - .log_post_test = normal_log_post_test, - .log_post_suite = normal_log_post_suite, - .log_post_all = normal_log_post_all, + .log_pre_all = normal_log_pre_all, + .log_pre_init = normal_log_pre_init, + .log_pre_suite = normal_log_pre_suite, + .log_assert = normal_log_assert, + .log_test_crash = normal_log_test_crash, + .log_other_crash = normal_log_other_crash, + .log_post_test = normal_log_post_test, + .log_post_suite = normal_log_post_suite, + .log_post_all = normal_log_post_all, }; diff --git a/src/report.c b/src/report.c index 140e628..ea13806 100644 --- a/src/report.c +++ b/src/report.c @@ -50,9 +50,6 @@ IMPL_CALL_REPORT_HOOKS(Type); \ ReportHook(Type) -#define log(Type, Arg) \ - (criterion_options.output_provider->log_ ## Type ?: nothing)(Arg); - __attribute__((always_inline)) static inline void nothing() {} diff --git a/src/report.h b/src/report.h index 29e3a97..6a740c5 100644 --- a/src/report.h +++ b/src/report.h @@ -43,4 +43,7 @@ DECL_CALL_REPORT_HOOKS(POST_FINI); DECL_CALL_REPORT_HOOKS(POST_SUITE); DECL_CALL_REPORT_HOOKS(POST_ALL); +#define log(Type, Arg) \ + (criterion_options.output_provider->log_ ## Type ?: nothing)(Arg); + #endif /* !REPORT_H_ */ diff --git a/src/runner.c b/src/runner.c index 719e090..0b705b6 100644 --- a/src/runner.c +++ b/src/runner.c @@ -184,14 +184,20 @@ static void run_test(struct criterion_global_stats *stats, if (proc == NULL && !is_runner()) return; + bool test_started = false; + bool normal_finish = false; struct event *ev; while ((ev = worker_read_event(proc)) != NULL) { stat_push_event(stats, suite_stats, test_stats, ev); switch (ev->kind) { case PRE_INIT: report(PRE_INIT, test); break; - case PRE_TEST: report(PRE_TEST, test); break; + case PRE_TEST: report(PRE_TEST, test); + test_started = true; + break; case ASSERT: report(ASSERT, ev->data); break; - case POST_TEST: report(POST_TEST, test_stats); break; + case POST_TEST: report(POST_TEST, test_stats); + normal_finish = true; + break; case POST_FINI: report(POST_FINI, test_stats); break; } sfree(ev); @@ -199,6 +205,16 @@ static void run_test(struct criterion_global_stats *stats, struct process_status status = wait_proc(proc); if (status.kind == SIGNAL) { + if (normal_finish || !test_started) { + log(other_crash, test_stats); + if (!test_started) { + stat_push_event(stats, + suite_stats, + test_stats, + &(struct event) { .kind = TEST_CRASH }); + } + return; + } test_stats->signal = status.status; if (test->data->signal == 0) { push_event(TEST_CRASH); diff --git a/src/stats.c b/src/stats.c index fcc5fb5..3d27db2 100644 --- a/src/stats.c +++ b/src/stats.c @@ -29,7 +29,7 @@ static void nothing() {}; static void push_pre_suite(); -static void push_pre_test(); +static void push_pre_init(); static void push_assert(); static void push_post_test(); static void push_test_crash(); @@ -81,8 +81,8 @@ void stat_push_event(s_glob_stats *stats, static void (*const handles[])(s_glob_stats *, s_suite_stats *, s_test_stats *, void *) = { nothing, // PRE_ALL push_pre_suite, // PRE_SUITE - nothing, // PRE_INIT - push_pre_test, // PRE_TEST + push_pre_init, // PRE_INIT + nothing, // PRE_TEST push_assert, // ASSERT push_test_crash, // TEST_CRASH push_post_test, // POST_TEST @@ -113,7 +113,7 @@ static inline bool is_disabled(struct criterion_test *t, return t->data->disabled || (s->data && s->data->disabled); } -static void push_pre_test(s_glob_stats *stats, +static void push_pre_init(s_glob_stats *stats, s_suite_stats *suite, s_test_stats *test, UNUSED void *ptr) { From de24bd181a857b890b4eedbb2d5006250bace298 Mon Sep 17 00:00:00 2001 From: Snaipe Date: Sat, 11 Apr 2015 13:04:00 +0200 Subject: [PATCH 37/60] Updated dependencies to latest --- dependencies/csptr | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dependencies/csptr b/dependencies/csptr index 1c96aae..4f3e63a 160000 --- a/dependencies/csptr +++ b/dependencies/csptr @@ -1 +1 @@ -Subproject commit 1c96aaec456287dc63eeb31443f409b5476afa0e +Subproject commit 4f3e63aca586939ed734f4e76c4f7f7f8c07d247 From a5922bc3773af2166ee977262b9a787310a9b86f Mon Sep 17 00:00:00 2001 From: Snaipe Date: Sun, 12 Apr 2015 15:30:21 +0200 Subject: [PATCH 38/60] Build and coverage status should come from the bleeding branch --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 012e0a1..8e35b6e 100644 --- a/README.md +++ b/README.md @@ -2,8 +2,8 @@ Criterion ========= -[![Build Status](https://travis-ci.org/Snaipe/Criterion.svg?branch=master)](https://travis-ci.org/Snaipe/Criterion) -[![Coverage Status](https://coveralls.io/repos/Snaipe/Criterion/badge.svg?branch=master)](https://coveralls.io/r/Snaipe/Criterion?branch=master) +[![Build Status](https://travis-ci.org/Snaipe/Criterion.svg?branch=bleeding)](https://travis-ci.org/Snaipe/Criterion) +[![Coverage Status](https://coveralls.io/repos/Snaipe/Criterion/badge.svg?branch=bleeding)](https://coveralls.io/r/Snaipe/Criterion?branch=bleeding) [![License](https://img.shields.io/badge/license-MIT-blue.svg?style=flat)](https://github.com/Snaipe/Criterion/blob/master/LICENSE) [![Version](https://img.shields.io/github/tag/Snaipe/Criterion.svg?label=version&style=flat)](https://github.com/Snaipe/Criterion/releases) From f43a179b79c62aebf0a10773afcb581cfaa86e08 Mon Sep 17 00:00:00 2001 From: Snaipe Date: Sun, 12 Apr 2015 16:38:14 +0200 Subject: [PATCH 39/60] Added more samples for coverage --- samples/Makefile.am | 4 ++++ samples/more-suites.c | 6 ++++-- samples/other-crashes.c | 14 ++++++++++++++ samples/with-time.c | 1 + 4 files changed, 23 insertions(+), 2 deletions(-) create mode 100644 samples/other-crashes.c create mode 120000 samples/with-time.c diff --git a/samples/Makefile.am b/samples/Makefile.am index 78d071a..a1d7231 100644 --- a/samples/Makefile.am +++ b/samples/Makefile.am @@ -7,6 +7,8 @@ BIN_TESTS = \ more-suites \ long-messages \ description \ + other-crashes \ + with-time \ simple TESTS_ENVIRONMENT = CRITERION_ALWAYS_SUCCEED=1 @@ -15,6 +17,8 @@ check_PROGRAMS := $(BIN_TESTS) CFLAGS = -I$(top_srcdir)/include/ -std=c99 -Wall -Wextra -pedantic LDADD = -L$(top_srcdir)/ -lcriterion +with_time_LDADD = $(LDADD) -lrt + SCRIPT_TESTS = tests/tap_test.sh \ tests/early_exit.sh \ tests/verbose.sh \ diff --git a/samples/more-suites.c b/samples/more-suites.c index 701866a..1b2f14e 100644 --- a/samples/more-suites.c +++ b/samples/more-suites.c @@ -1,10 +1,12 @@ #include void setup_suite(void) { - // setup suite } -TestSuite(suite1, .init = setup_suite); +void teardown_suite(void) { +} + +TestSuite(suite1, .init = setup_suite, .fini = teardown_suite); Test(suite1, test) { assert(1); diff --git a/samples/other-crashes.c b/samples/other-crashes.c new file mode 100644 index 0000000..a1baa27 --- /dev/null +++ b/samples/other-crashes.c @@ -0,0 +1,14 @@ +#include + +void crash(void) { + int *i = NULL; + *i = 42; +} + +Test(misc, setup_crash, .init = crash) { + assert(true); +} + +Test(misc, teardown_crash, .fini = crash) { + assert(true); +} diff --git a/samples/with-time.c b/samples/with-time.c new file mode 120000 index 0000000..9ef1a34 --- /dev/null +++ b/samples/with-time.c @@ -0,0 +1 @@ +simple.c \ No newline at end of file From 9ec422cf9b71f4a01acdbfca40dce26be962a4a1 Mon Sep 17 00:00:00 2001 From: Snaipe Date: Sun, 12 Apr 2015 16:38:36 +0200 Subject: [PATCH 40/60] Added coveralls reports on appveyor builds --- appveyor.yml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index cc59949..ecccddb 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -28,7 +28,7 @@ init: -P git \ -P wget \ -P curl - - "%CYG_BASH% -lc 'echo $PATH'" + - "%CYG_BASH% -lc 'pip install cpp-coveralls'" environment: global: @@ -36,6 +36,8 @@ environment: CYG_MIRROR: http://cygwin.mirror.constant.com CYG_CACHE: C:\cygwin\var\cache\setup CYG_BASH: C:\cygwin\bin\bash + COVERALLS_TOKEN: + secure: 5nuCg+faxFPeppoNNcSwVobswAVFUf8ut83vw8CX/4W2y0kZkGmwEfCUxSQWiQDU cache: - '%CYG_CACHE%' @@ -53,7 +55,7 @@ configuration: Release install: - "%CYG_BASH% -lc 'cd $APPVEYOR_BUILD_FOLDER; ./autogen.sh'" - - '%CYG_BASH% -lc "cd $APPVEYOR_BUILD_FOLDER; exec 0 Date: Sun, 12 Apr 2015 16:44:48 +0200 Subject: [PATCH 41/60] Fixed wrong prefix for failed tests --- include/criterion/logging.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/criterion/logging.h b/include/criterion/logging.h index bec9959..616dac9 100644 --- a/include/criterion/logging.h +++ b/include/criterion/logging.h @@ -74,7 +74,7 @@ extern const struct criterion_prefix_data g_criterion_logging_prefixes[]; # define CRITERION_PREFIX_RUN (&g_criterion_logging_prefixes[CRITERION_LOGGING_PREFIX_RUN ]) # define CRITERION_PREFIX_SKIP (&g_criterion_logging_prefixes[CRITERION_LOGGING_PREFIX_SKIP ]) # define CRITERION_PREFIX_PASS (&g_criterion_logging_prefixes[CRITERION_LOGGING_PREFIX_PASS ]) -# define CRITERION_PREFIX_FAIL (&g_criterion_logging_prefixes[CRITERION_LOGGING_PREFIX_EQUALS]) +# define CRITERION_PREFIX_FAIL (&g_criterion_logging_prefixes[CRITERION_LOGGING_PREFIX_FAIL ]) void criterion_vlog(enum criterion_logging_level level, const char *msg, va_list args); From 795f2d28da6cd0edbf225112a55ad9a2de674c49 Mon Sep 17 00:00:00 2001 From: Snaipe Date: Sun, 12 Apr 2015 16:48:54 +0200 Subject: [PATCH 42/60] Fixed skipped tests not being reported --- src/runner.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/runner.c b/src/runner.c index 0b705b6..a47292d 100644 --- a/src/runner.c +++ b/src/runner.c @@ -176,7 +176,7 @@ static void run_test(struct criterion_global_stats *stats, stat_push_event(stats, suite_stats, test_stats, - &(struct event) { .kind = PRE_TEST }); + &(struct event) { .kind = PRE_INIT }); return; } From f24033e9699034ab2666e5b9099006cc71368893 Mon Sep 17 00:00:00 2001 From: Snaipe Date: Sun, 12 Apr 2015 16:56:06 +0200 Subject: [PATCH 43/60] Added coverage case of a skipped test with description --- samples/description.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/samples/description.c b/samples/description.c index 3e9f02a..335036b 100644 --- a/samples/description.c +++ b/samples/description.c @@ -3,3 +3,6 @@ Test(misc, failing, .description = "Just a failing test") { assert(0); } + +Test(misc, skipped, .description = "This one is skipped", .disabled = true) { +} From 95953960e77af25ba1086f4d3309ad31ed3f3fd4 Mon Sep 17 00:00:00 2001 From: Snaipe Date: Sun, 12 Apr 2015 17:19:15 +0200 Subject: [PATCH 44/60] Switched to python 3 in appveyor builds --- appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index ecccddb..0b49b03 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -17,7 +17,7 @@ init: -P mingw64-i686-gcc-core \ -P libtool \ -P make \ - -P python \ + -P python3 \ -P gettext-devel \ -P gettext \ -P expat \ From e83cfc412e0e82d2d235fc8fdfdbea2ff32de03d Mon Sep 17 00:00:00 2001 From: Snaipe Date: Sun, 12 Apr 2015 18:07:49 +0200 Subject: [PATCH 45/60] Added pip installation in appveyor builds --- .ci/install-pip.sh | 4 ++++ appveyor.yml | 5 ++++- 2 files changed, 8 insertions(+), 1 deletion(-) create mode 100755 .ci/install-pip.sh diff --git a/.ci/install-pip.sh b/.ci/install-pip.sh new file mode 100755 index 0000000..379cfbf --- /dev/null +++ b/.ci/install-pip.sh @@ -0,0 +1,4 @@ +#!/bin/sh +curl -O https://bootstrap.pypa.io/get-pip.py +python3 get-pip.py +rm -f get-pip.py diff --git a/appveyor.yml b/appveyor.yml index 0b49b03..16e765e 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -28,7 +28,6 @@ init: -P git \ -P wget \ -P curl - - "%CYG_BASH% -lc 'pip install cpp-coveralls'" environment: global: @@ -60,6 +59,10 @@ install: build_script: - '%CYG_BASH% -lc "cd $APPVEYOR_BUILD_FOLDER; exec 0 Date: Sun, 12 Apr 2015 23:00:41 +0200 Subject: [PATCH 46/60] Changed with-type to a real file for windows builds --- samples/with-time.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) mode change 120000 => 100644 samples/with-time.c diff --git a/samples/with-time.c b/samples/with-time.c deleted file mode 120000 index 9ef1a34..0000000 --- a/samples/with-time.c +++ /dev/null @@ -1 +0,0 @@ -simple.c \ No newline at end of file diff --git a/samples/with-time.c b/samples/with-time.c new file mode 100644 index 0000000..1d67a01 --- /dev/null +++ b/samples/with-time.c @@ -0,0 +1,5 @@ +#include + +Test(samples, timed) { + assert(0); +} From e5ebb64bb8c9f670eb849870d7cea0e528576a2e Mon Sep 17 00:00:00 2001 From: Snaipe Date: Sun, 12 Apr 2015 23:04:55 +0200 Subject: [PATCH 47/60] Removed "Any CPU" builds in appveyor --- appveyor.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index 16e765e..43e51f6 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -48,7 +48,6 @@ matrix: platform: - x86 - - Any CPU configuration: Release From 77c5e43140a1924804d46f1ccf76c6dcc1440e05 Mon Sep 17 00:00:00 2001 From: Snaipe Date: Sun, 12 Apr 2015 23:31:16 +0200 Subject: [PATCH 48/60] Disabled RT tests when unavailable --- configure.ac | 5 +++++ samples/Makefile.am | 4 +++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 0951dab..836281f 100644 --- a/configure.ac +++ b/configure.ac @@ -22,6 +22,11 @@ AC_SUBST([LIBTOOL_DEPS]) AC_FUNC_FNMATCH +enable_rt_tests="no" +AC_CHECK_LIB([rt], [clock_gettime], [enable_rt_tests="yes"]) + +AM_CONDITIONAL([ENABLE_RT_TESTS], [test "x$enable_rt_tests" != "xno"]) + AM_GNU_GETTEXT([external]) AM_GNU_GETTEXT_VERSION([0.18]) diff --git a/samples/Makefile.am b/samples/Makefile.am index a1d7231..7ed5f12 100644 --- a/samples/Makefile.am +++ b/samples/Makefile.am @@ -8,7 +8,6 @@ BIN_TESTS = \ long-messages \ description \ other-crashes \ - with-time \ simple TESTS_ENVIRONMENT = CRITERION_ALWAYS_SUCCEED=1 @@ -17,7 +16,10 @@ check_PROGRAMS := $(BIN_TESTS) CFLAGS = -I$(top_srcdir)/include/ -std=c99 -Wall -Wextra -pedantic LDADD = -L$(top_srcdir)/ -lcriterion +if ENABLE_RT_TESTS +BIN_TESTS += with-time with_time_LDADD = $(LDADD) -lrt +endif SCRIPT_TESTS = tests/tap_test.sh \ tests/early_exit.sh \ From 442b546db43937bbbf7b8a84f1a153bc67afa2a6 Mon Sep 17 00:00:00 2001 From: Snaipe Date: Mon, 13 Apr 2015 00:00:10 +0200 Subject: [PATCH 49/60] Fixed typo on coveralls token --- appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index 43e51f6..181f7cb 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -67,7 +67,7 @@ test_script: after_test: - '%CYG_BASH% -lc "cat $(find $APPVEYOR_BUILD_FOLDER/samples -iname \"*.log\") /dev/null' - - '%CYG_BASH% -lc "cd $APPVEYOR_BUILD_FOLDER; coveralls --exclude samples --exclude dependencies --gcov-options \\-lp -b . -t $(COVERALLS_TOKEN)' + - '%CYG_BASH% -lc "cd $APPVEYOR_BUILD_FOLDER; coveralls --exclude samples --exclude dependencies --gcov-options \\-lp -b . -t $COVERALLS_TOKEN' notifications: From 8687b82d08048df4a086fcdadcf63c244b2f7ae7 Mon Sep 17 00:00:00 2001 From: Snaipe Date: Mon, 13 Apr 2015 00:25:11 +0200 Subject: [PATCH 50/60] Fixed gcov options on appveyor build --- appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index 181f7cb..1cdbe2d 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -67,7 +67,7 @@ test_script: after_test: - '%CYG_BASH% -lc "cat $(find $APPVEYOR_BUILD_FOLDER/samples -iname \"*.log\") /dev/null' - - '%CYG_BASH% -lc "cd $APPVEYOR_BUILD_FOLDER; coveralls --exclude samples --exclude dependencies --gcov-options \\-lp -b . -t $COVERALLS_TOKEN' + - '%CYG_BASH% -lc "cd $APPVEYOR_BUILD_FOLDER; coveralls --exclude samples --exclude dependencies --gcov-options \"\-lp\" -b . -t $COVERALLS_TOKEN' notifications: From 9dcf11a82f7f9265d267efb242d1f10dd651aa93 Mon Sep 17 00:00:00 2001 From: Snaipe Date: Mon, 13 Apr 2015 16:47:15 +0200 Subject: [PATCH 51/60] Fixed bad gcov version used on appveyor builds --- appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index 1cdbe2d..6d03dde 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -67,7 +67,7 @@ test_script: after_test: - '%CYG_BASH% -lc "cat $(find $APPVEYOR_BUILD_FOLDER/samples -iname \"*.log\") /dev/null' - - '%CYG_BASH% -lc "cd $APPVEYOR_BUILD_FOLDER; coveralls --exclude samples --exclude dependencies --gcov-options \"\-lp\" -b . -t $COVERALLS_TOKEN' + - '%CYG_BASH% -lc "cd $APPVEYOR_BUILD_FOLDER; coveralls --gcov i686-w64-mingw32-gcov --exclude samples --exclude dependencies --gcov-options \"\-lp\" -b . -t $COVERALLS_TOKEN' notifications: From f38b1b24feb6f9e8f8226a702f2f0d0c70f43f70 Mon Sep 17 00:00:00 2001 From: Snaipe Date: Mon, 13 Apr 2015 17:43:01 +0200 Subject: [PATCH 52/60] Changed gcov prefix for appveyor builds --- appveyor.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/appveyor.yml b/appveyor.yml index 6d03dde..76e605f 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -52,6 +52,7 @@ platform: configuration: Release install: + - 'set GCOV_PREFIX=%APPVEYOR_BUILD_FOLDER%' - "%CYG_BASH% -lc 'cd $APPVEYOR_BUILD_FOLDER; ./autogen.sh'" - '%CYG_BASH% -lc "cd $APPVEYOR_BUILD_FOLDER; exec 0 Date: Tue, 14 Apr 2015 14:53:18 +0200 Subject: [PATCH 53/60] Completed documentation with parameter reference, test-suite configuration, custom output provider, and various fixes --- doc/env.rst | 7 +++--- doc/faq.rst | 3 ++- doc/hooks.rst | 19 +++++++++++++++ doc/internal.rst | 13 +++++++++++ doc/starter.rst | 61 ++++++++++++++++++++++++++++++++++++++++++++++-- 5 files changed, 97 insertions(+), 6 deletions(-) diff --git a/doc/env.rst b/doc/env.rst index c0fc38b..1db5788 100644 --- a/doc/env.rst +++ b/doc/env.rst @@ -14,7 +14,7 @@ Command line arguments * ``-f or --fail-fast``: Exit after the first test failure. * ``--ascii``: Don't use fancy unicode symbols or colors in the output. * ``--pattern [PATTERN]``: Run tests whose string identifier matches - the given shell wildcard pattern (see dedicated section below). + the given shell wildcard pattern (see dedicated section below). (\*nix only) * ``--no-early-exit``: The test workers shall not prematurely exit when done and will properly return from the main, cleaning up their process space. This is useful when tracking memory leaks with ``valgrind --tool=memcheck``. @@ -27,7 +27,8 @@ Shell Wildcard Pattern ---------------------- Patterns in criterion are matched against a test's string identifier with -``fnmatch``. +``fnmatch``. This feature is only available on \*nix systems where ``fnmatch`` +is provided. Special characters used in shell-style wildcard patterns are: @@ -61,4 +62,4 @@ Environment variables are alternatives to command line switches when set to 1. * ``CRITERION_VERBOSITY_LEVEL``: Same as ``--verbose``. Sets the verbosity level to its value. * ``CRITERION_TEST_PATTERN``: Same as ``--pattern``. Sets the test pattern - to its value. + to its value. (\*nix only) diff --git a/doc/faq.rst b/doc/faq.rst index 82af2fc..aa15aa5 100644 --- a/doc/faq.rst +++ b/doc/faq.rst @@ -14,4 +14,5 @@ There are plenty of ways to fix that behaviour: **Q. I'm having an issue with the library, what can I do ?** A. Open a new issue on the `github issue tracker `_, -and describe the problem you are experiencing. +and describe the problem you are experiencing, along with the platform you are +running criterion on. diff --git a/doc/hooks.rst b/doc/hooks.rst index 0596a9e..a9b8bd6 100644 --- a/doc/hooks.rst +++ b/doc/hooks.rst @@ -17,6 +17,10 @@ A report hook can be declared using the ``ReportHook`` macro: The macro takes a Phase parameter that indicates the phase at which the function shall be run. Valid phases are described below. +**Note**: there are no guarantees regarding the order of execution of report hooks +on the same phase. In other words, all report hooks of a specific phase could +be executed in any order. + Testing Phases -------------- @@ -49,3 +53,18 @@ Valid types for each phases are: * ``struct criterion_test_stats *`` for ``POST_TEST``, ``POST_FINI``, and ``TEST_CRASH``. * ``struct criterion_suite_stats *`` for ``POST_SUITE``. * ``struct criterion_global_stats *`` for ``POST_ALL``. + +For instance, these are valid report hook declarations for the ``PRE_TEST`` phase: + +.. code-block:: c + + #include + #include + + ReportHook(PRE_TEST)() { + // not using the parameter + } + + ReportHook(PRE_TEST)(struct criterion_test *test) { + // using the parameter + } diff --git a/doc/internal.rst b/doc/internal.rst index df3518d..8c94237 100644 --- a/doc/internal.rst +++ b/doc/internal.rst @@ -39,3 +39,16 @@ Starting the test runner The test runner can be called with ``criterion_run_all_tests``. The function returns 0 if one test or more failed, 1 otherwise. + +Implementing your own output provider +------------------------------------- + +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. + +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 +in ``src/log/``. diff --git a/doc/starter.rst b/doc/starter.rst index b974bdd..cd8890b 100644 --- a/doc/starter.rst +++ b/doc/starter.rst @@ -68,8 +68,16 @@ On top of those, more assertions are available for common operations: * ``{assert,expect}_arrays_eq(Actual, Expected, Size, [Message])`` * ``{assert,expect}_arrays_neq(Actual, Unexpected, Size, [Message])`` +Please note that ``arrays_(n)eq`` assertions should not be used for padded structures. + +Configuring tests +----------------- + +Tests may receive optional configuration parameters to alter their behaviour +or provide additional metadata. + Fixtures --------- +~~~~~~~~ Tests that need some setup and teardown can register functions that will run before and after the test function: @@ -91,8 +99,13 @@ run before and after the test function: // test contents } +If a setup crashes, you will get a warning message, and the test will be aborted +and marked as a failure. +Is a teardown crashes, you will get a warning message, and the test will keep +its result. + Testing signals ---------------- +~~~~~~~~~~~~~~~ If a test receives a signal, it will by default be marked as a failure. You can, however, expect a test to only pass if a special kind of signal @@ -115,3 +128,47 @@ is received: int *ptr = NULL; *ptr = 42; } + +This feature will of course not work on Windows. + +Configuration reference +~~~~~~~~~~~~~~~~~~~~~~~ + +Here is an exhaustive list of all possible configuration parameters you can +pass: + +============= =============== ============================================================== +Parameter Type Description +============= =============== ============================================================== +.description const char * Adds a description. Cannot be ``NULL``. +------------- --------------- -------------------------------------------------------------- +.init void (*)(void) Adds a setup function the be executed before the test. +------------- --------------- -------------------------------------------------------------- +.fini void (*)(void) Adds a teardown function the be executed after the test. +------------- --------------- -------------------------------------------------------------- +.disabled bool Disables the test. +------------- --------------- -------------------------------------------------------------- +.signal int Expect the test to raise the specified signal. +============= =============== ============================================================== + +Setting up suite-wise configuration +----------------------------------- + +Tests under the same suite can have a suite-wise configuration -- this is done +using the ``TestSuite`` macro: + +.. code-block:: c + + #include + + TestSuite(suite_name, [params...]); + + Test(suite_name, test_1) { + } + + Test(suite_name, test_2) { + } + +Configuration parameters are the same as above, but applied to the suite itself. + +Suite fixtures are run *along with* test fixtures. From 223fe6b79b62cb67b8edb572bb604a21fd70d263 Mon Sep 17 00:00:00 2001 From: Snaipe Date: Tue, 14 Apr 2015 17:00:42 +0200 Subject: [PATCH 54/60] [Issue #16] sources with no tests can now compile --- src/runner.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/runner.c b/src/runner.c index a47292d..4da3b28 100644 --- a/src/runner.c +++ b/src/runner.c @@ -38,8 +38,9 @@ IMPL_SECTION_LIMITS(struct criterion_test, criterion_tests); IMPL_SECTION_LIMITS(struct criterion_suite, crit_suites); -// This is here to make the test suite section non-empty -TestSuite(default); +// This is here to make the test suite & test sections non-empty +TestSuite(); +Test(,) {}; int cmp_suite(void *a, void *b) { struct criterion_suite *s1 = a, *s2 = b; @@ -71,7 +72,11 @@ struct criterion_test_set *criterion_init(void) { insert_ordered_set(suites, &css, sizeof (css)); } + size_t nb_tests = 0; FOREACH_TEST_SEC(test) { + if (!*test->category) + continue; + struct criterion_suite_set css = { .suite = { .name = test->category }, }; @@ -80,11 +85,9 @@ struct criterion_test_set *criterion_init(void) { s->tests = new_ordered_set(cmp_test, NULL); insert_ordered_set(s->tests, test, sizeof(*test)); + ++nb_tests; } - const size_t nb_tests = SECTION_END(criterion_tests) - - SECTION_START(criterion_tests); - return unique_ptr(struct criterion_test_set, { suites, nb_tests, From f9d3d318f11133a9b80aa3f025e22c664f502984 Mon Sep 17 00:00:00 2001 From: Snaipe Date: Tue, 14 Apr 2015 17:22:55 +0200 Subject: [PATCH 55/60] Fixed rare crash where the output provider does not get defined --- src/main.c | 16 +++++++--------- src/options.c | 1 + 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/src/main.c b/src/main.c index 19c7fcd..32859c9 100644 --- a/src/main.c +++ b/src/main.c @@ -140,17 +140,15 @@ int main(int argc, char *argv[]) { textdomain (PACKAGE "-test"); #endif - 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"), - .fail_fast = !strcmp("1", getenv("CRITERION_FAIL_FAST") ?: "0"), - .use_ascii = use_ascii, - .logging_threshold = atoi(getenv("CRITERION_VERBOSITY_LEVEL") ?: "2"), + struct criterion_options *opt = &criterion_options; + opt->always_succeed = !strcmp("1", getenv("CRITERION_ALWAYS_SUCCEED") ?: "0"); + opt->no_early_exit = !strcmp("1", getenv("CRITERION_NO_EARLY_EXIT") ?: "0"); + opt->fail_fast = !strcmp("1", getenv("CRITERION_FAIL_FAST") ?: "0"); + opt->use_ascii = use_ascii; + opt->logging_threshold = atoi(getenv("CRITERION_VERBOSITY_LEVEL") ?: "2"); #ifdef HAVE_FNMATCH - .pattern = getenv("CRITERION_TEST_PATTERN"), + opt->pattern = getenv("CRITERION_TEST_PATTERN"); #endif - .output_provider = NORMAL_LOGGING, - }; bool use_tap = !strcmp("1", getenv("CRITERION_ENABLE_TAP") ?: "0"); diff --git a/src/options.c b/src/options.c index 21fcef8..c83b294 100644 --- a/src/options.c +++ b/src/options.c @@ -25,4 +25,5 @@ struct criterion_options criterion_options = { .logging_threshold = CRITERION_IMPORTANT, + .output_provider = &normal_logging, }; From ea2721dbb865a5df74f3048d08de34bc7246eb15 Mon Sep 17 00:00:00 2001 From: Snaipe Date: Tue, 14 Apr 2015 17:57:54 +0200 Subject: [PATCH 56/60] Only run samples on travis builds --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 55f5f64..1624538 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,7 +8,7 @@ before_install: - sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-4.9 90 - sudo pip install cpp-coveralls script: - - ./autogen.sh && ./configure --enable-gcov CFLAGS="-g -O0" && make && make check + - ./autogen.sh && ./configure --enable-gcov CFLAGS="-g -O0" && make && make -C samples check after_success: - coveralls --gcov gcov-4.9 --exclude samples --exclude dependencies --gcov-options '\-lp' -b . after_failure: From c583e7e742ba81699df845e770b39a7485fe07aa Mon Sep 17 00:00:00 2001 From: Snaipe Date: Tue, 14 Apr 2015 18:39:40 +0200 Subject: [PATCH 57/60] [Issue #17] Fixed nested failed asserts not aborting the test --- Makefile.am | 3 +++ include/criterion/abort.h | 31 +++++++++++++++++++++++++++++++ include/criterion/assert.h | 3 ++- include/criterion/common.h | 1 + src/abort.c | 35 +++++++++++++++++++++++++++++++++++ src/abort.h | 31 +++++++++++++++++++++++++++++++ src/runner.c | 8 ++++++-- 7 files changed, 109 insertions(+), 3 deletions(-) create mode 100644 include/criterion/abort.h create mode 100644 src/abort.c create mode 100644 src/abort.h diff --git a/Makefile.am b/Makefile.am index bcc7f94..1bffb46 100644 --- a/Makefile.am +++ b/Makefile.am @@ -25,6 +25,7 @@ EXTRA_DIST = config.rpath LICENSE subdirincludedir = $(includedir)/criterion/ subdirinclude_HEADERS = \ include/criterion/assert.h \ + include/criterion/abort.h \ include/criterion/common.h \ include/criterion/criterion.h \ include/criterion/event.h \ @@ -36,6 +37,8 @@ subdirinclude_HEADERS = \ include/criterion/stats.h libcriterion_la_SOURCES = \ + src/abort.c \ + src/abort.h \ src/event.c \ src/event.h \ src/report.c \ diff --git a/include/criterion/abort.h b/include/criterion/abort.h new file mode 100644 index 0000000..f20e300 --- /dev/null +++ b/include/criterion/abort.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_ABORT_H_ +# define CRITERION_ABORT_H_ + +# include "common.h" + +NORETURN void criterion_abort_test(void); + +#endif /* !CRITERION_ABORT_H_ */ diff --git a/include/criterion/assert.h b/include/criterion/assert.h index f17de27..7f37705 100644 --- a/include/criterion/assert.h +++ b/include/criterion/assert.h @@ -31,6 +31,7 @@ # include "stats.h" # include "hooks.h" # include "event.h" +# include "abort.h" enum criterion_assert_kind { NORMAL, @@ -60,7 +61,7 @@ struct criterion_assert_args { }; \ send_event(ASSERT, &stat, sizeof (stat)); \ if (!passed && (Kind) == FATAL) \ - return; \ + criterion_abort_test(); \ } while (0) // Common asserts diff --git a/include/criterion/common.h b/include/criterion/common.h index 342e6db..e5ebfd2 100644 --- a/include/criterion/common.h +++ b/include/criterion/common.h @@ -56,6 +56,7 @@ Type *const SECTION_END(Name) = &SECTION_END_(Name) # define UNUSED __attribute__((unused)) +# define NORETURN __attribute__((noreturn)) # ifdef _WIN32 # define SIZE_T_FORMAT "%Iu" diff --git a/src/abort.c b/src/abort.c new file mode 100644 index 0000000..ea61bb9 --- /dev/null +++ b/src/abort.c @@ -0,0 +1,35 @@ +/* + * 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 +#include "abort.h" + +static jmp_buf g_pre_test; + +int setup_abort_test(void) { + return !setjmp(g_pre_test); +} + +void criterion_abort_test(void) { + longjmp(g_pre_test, 1); +} diff --git a/src/abort.h b/src/abort.h new file mode 100644 index 0000000..4d85ba3 --- /dev/null +++ b/src/abort.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 ABORT_H_ +# define ABORT_H_ + +# include + +int setup_abort_test(void); + +#endif /* !ABORT_H_ */ diff --git a/src/runner.c b/src/runner.c index 4da3b28..b19ea48 100644 --- a/src/runner.c +++ b/src/runner.c @@ -34,6 +34,7 @@ #include "process.h" #include "timer.h" #include "posix-compat.h" +#include "abort.h" IMPL_SECTION_LIMITS(struct criterion_test, criterion_tests); IMPL_SECTION_LIMITS(struct criterion_suite, crit_suites); @@ -139,8 +140,11 @@ static void run_test_child(struct criterion_test *test, send_event(PRE_TEST, NULL, 0); struct timespec_compat ts; - timer_start(&ts); - (test->test ?: nothing)(); + if (setup_abort_test()) { + timer_start(&ts); + (test->test ?: nothing)(); + } + double elapsed_time; if (!timer_end(&elapsed_time, &ts)) elapsed_time = -1; From 589bcf60fd8d37dec3a29ed66385e3baded491af Mon Sep 17 00:00:00 2001 From: Snaipe Date: Tue, 14 Apr 2015 19:44:30 +0200 Subject: [PATCH 58/60] Added assert_null and structure arrays asserts --- include/criterion/assert.h | 97 +++++++++++++++++++++++++++++++++----- samples/asserts.c | 28 +++++++++++ 2 files changed, 114 insertions(+), 11 deletions(-) diff --git a/include/criterion/assert.h b/include/criterion/assert.h index 7f37705..4a5b2b4 100644 --- a/include/criterion/assert.h +++ b/include/criterion/assert.h @@ -111,6 +111,22 @@ struct criterion_assert_args { # define assert_geq(...) assert_op_(>=, __VA_ARGS__, .sentinel_ = 0) # define expect_geq(...) expect_op_(>=, __VA_ARGS__, .sentinel_ = 0) +# define assert_null_(Value, ...) \ + assert_impl(FATAL, (Value) == NULL, __VA_ARGS__) +# define expect_null_(Value, ...) \ + assert_impl(NORMAL, (Value) == NULL, __VA_ARGS__) + +# define assert_null(...) assert_null_(__VA_ARGS__, .sentinel_ = 0) +# define expect_null(...) expect_null_(__VA_ARGS__, .sentinel_ = 0) + +# define assert_not_null_(Value, ...) \ + assert_impl(FATAL, (Value) != NULL, __VA_ARGS__) +# define expect_not_null_(Value, ...) \ + assert_impl(NORMAL, (Value) != NULL, __VA_ARGS__) + +# define assert_not_null(...) assert_not_null_(__VA_ARGS__, .sentinel_ = 0) +# define expect_not_null(...) expect_not_null_(__VA_ARGS__, .sentinel_ = 0) + // Floating-point asserts # define assert_float_eq(...) \ @@ -173,23 +189,82 @@ struct criterion_assert_args { // Array asserts # define assert_arrays_eq(...) \ - assert_arrays_eq_(__VA_ARGS__, .sentinel = 0) + assert_arrays_eq_(__VA_ARGS__, .sentinel_ = 0) # define expect_arrays_eq(...) \ - expect_arrays_eq_(__VA_ARGS__, .sentinel = 0) + expect_arrays_eq_(__VA_ARGS__, .sentinel_ = 0) # define assert_arrays_neq(...) \ - assert_arrays_neq_(__VA_ARGS__, .sentinel = 0) + assert_arrays_neq_(__VA_ARGS__, .sentinel_ = 0) # define expect_arrays_neq(...) \ - expect_arrays_neq_(__VA_ARGS__, .sentinel = 0) + expect_arrays_neq_(__VA_ARGS__, .sentinel_ = 0) -# define assert_arrays_eq_(A, B, Size, ...) \ - assert_impl(FATAL, !memcmp((A), (B), (Size)), __VA_ARGS__) +# define assert_arrays_eq_(A, B, Size, ...) \ + assert_impl(FATAL, !memcmp((A), (B), (Size)), \ + .default_msg = "Arrays are not equal.", \ + __VA_ARGS__) # define expect_arrays_eq_(A, B, Size, ...) \ - assert_impl(NORMAL, !memcmp((A), (B), (Size)), __VA_ARGS__) + assert_impl(NORMAL, !memcmp((A), (B), (Size)), \ + .default_msg = "Arrays are not equal.", \ + __VA_ARGS__) -# define assert_arrays_neq_(A, B, Size, ...) \ - assert_impl(FATAL, memcmp((A), (B), (Size)), __VA_ARGS__) -# define expect_arrays_neq_(A, B, Size, ...) \ - assert_impl(NORMAL, memcmp((A), (B), (Size)), __VA_ARGS__) +# define assert_arrays_neq_(A, B, Size, ...) \ + assert_impl(FATAL, memcmp((A), (B), (Size)), \ + .default_msg = "Arrays are equal", \ + __VA_ARGS__) +# define expect_arrays_neq_(A, B, Size, ...) \ + assert_impl(NORMAL, memcmp((A), (B), (Size)), \ + .default_msg = "Arrays are equal", \ + __VA_ARGS__) + +# ifdef __GNUC__ +# define CRIT_ARR_COMPARE_(A, B, Size, Cmp, Result) \ + __typeof__(&(A)[0]) first = (A); \ + __typeof__(&(B)[0]) second = (B); \ + int equals = 1; \ + for (size_t i = 0, size = (Size); equals && i < size; ++i) \ + equals = equals && !Cmp(first + i, second + i) + +# define assert_arrays_eq_cmp_(A, B, Size, Cmp, ...) \ + do { \ + CRIT_ARR_COMPARE_(A, B, Size, Cmp, equals); \ + assert_impl(FATAL, equals, \ + .default_msg = "Arrays are not equal", \ + __VA_ARGS__); \ + } while (0) + +# define expect_arrays_eq_cmp_(A, B, Size, Cmp, ...) \ + do { \ + CRIT_ARR_COMPARE_(A, B, Size, Cmp, equals); \ + assert_impl(NORMAL, equals, \ + .default_msg = "Arrays are not equal", \ + __VA_ARGS__); \ + } while (0) + +# define assert_arrays_eq_cmp(...) \ + assert_arrays_eq_cmp_(__VA_ARGS__, .sentinel_ = 0) +# define expect_arrays_eq_cmp(...) \ + expect_arrays_eq_cmp_(__VA_ARGS__, .sentinel_ = 0) + +# define assert_arrays_neq_cmp_(A, B, Size, Cmp, ...) \ + do { \ + CRIT_ARR_COMPARE_(A, B, Size, Cmp, equals); \ + assert_impl(FATAL, !equals, \ + .default_msg = "Arrays not equal", \ + __VA_ARGS__); \ + } while (0) + +# define expect_arrays_neq_cmp_(A, B, Size, Cmp, ...) \ + do { \ + CRIT_ARR_COMPARE_(A, B, Size, Cmp, equals); \ + assert_impl(NORMAL, equals, \ + .default_msg = "Arrays not equal", \ + __VA_ARGS__); \ + } while (0) + +# define assert_arrays_neq_cmp(...) \ + assert_arrays_eq_cmp_(__VA_ARGS__, .sentinel_ = 0) +# define expect_arrays_neq_cmp(...) \ + expect_arrays_eq_cmp_(__VA_ARGS__, .sentinel_ = 0) +# endif /* !__GNUC__ */ #endif /* !CRITERION_ASSERT_H_ */ diff --git a/samples/asserts.c b/samples/asserts.c index 811824f..abd20b0 100644 --- a/samples/asserts.c +++ b/samples/asserts.c @@ -50,3 +50,31 @@ Test(asserts, float) { assert_neq(0.1 * 0.1, 0.01); assert_float_eq(0.1 * 0.1, 0.01, 0.001); } + +struct dummy_struct { + char a; + size_t b; +}; + +int eq_dummy(struct dummy_struct *a, struct dummy_struct *b) { + return a->a != b->a || a->b != b->b; +} + +Test(asserts, array) { + int arr1[] = {1, 2, 3, 4}; + int arr2[] = {4, 3, 2, 1}; + + struct dummy_struct s1[] = {{4, 2}, {2, 4}}; + struct dummy_struct s2[2]; + memset(s2, 0xFF, sizeof(s2)); + s2[0].a = 4; + s2[0].b = 2; + s2[1].a = 2; + s2[1].b = 4; + + assert_arrays_eq(arr1, arr1, 4); + assert_arrays_neq(arr1, arr2, 4); + + assert_arrays_neq(s1, s2, 2); + assert_arrays_eq_cmp(s1, s2, 2, eq_dummy); +} From dfda7b6f6717785fe6c2dc9dd41efc057d7a864f Mon Sep 17 00:00:00 2001 From: Snaipe Date: Wed, 15 Apr 2015 15:22:00 +0200 Subject: [PATCH 59/60] Refined a bit the documentation page on assertions --- doc/starter.rst | 54 ++++++++++++++++++++++++++++++++----------------- 1 file changed, 36 insertions(+), 18 deletions(-) diff --git a/doc/starter.rst b/doc/starter.rst index cd8890b..7021a38 100644 --- a/doc/starter.rst +++ b/doc/starter.rst @@ -50,25 +50,43 @@ parameter, and an optional failure message: On top of those, more assertions are available for common operations: -* ``{assert,expect}_not(Actual, Expected, [Message])`` -* ``{assert,expect}_eq(Actual, Expected, [Message])`` -* ``{assert,expect}_neq(Actual, Unexpected, [Message])`` -* ``{assert,expect}_lt(Actual, Expected, [Message])`` -* ``{assert,expect}_leq(Actual, Expected, [Message])`` -* ``{assert,expect}_gt(Actual, Expected, [Message])`` -* ``{assert,expect}_geq(Actual, Expected, [Message])`` -* ``{assert,expect}_float_eq(Actual, Expected, Epsilon, [Message])`` -* ``{assert,expect}_float_neq(Actual, Unexpected, Epsilon, [Message])`` -* ``{assert,expect}_strings_eq(Actual, Expected, [Message])`` -* ``{assert,expect}_strings_neq(Actual, Unexpected, [Message])`` -* ``{assert,expect}_strings_lt(Actual, Expected, [Message])`` -* ``{assert,expect}_strings_leq(Actual, Expected, [Message])`` -* ``{assert,expect}_strings_gt(Actual, Expected, [Message])`` -* ``{assert,expect}_strings_geq(Actual, Expected, [Message])`` -* ``{assert,expect}_arrays_eq(Actual, Expected, Size, [Message])`` -* ``{assert,expect}_arrays_neq(Actual, Unexpected, Size, [Message])`` +* ``assert_null(Ptr, [Message])``: passes if Ptr is NULL. +* ``assert_eq(Actual, Expected, [Message])``: passes if Actual == Expected. +* ``assert_lt(Actual, Expected, [Message])``: passes if Actual < Expected. +* ``assert_leq(Actual, Expected, [Message])``: passes if Actual <= Expected. +* ``assert_gt(Actual, Expected, [Message])``: passes if Actual > Expected. +* ``assert_geq(Actual, Expected, [Message])``: passes if Actual >= Expected. +* ``assert_float_eq(Actual, Expected, Epsilon, [Message])``: + passes if Actual == Expected with an error of Epsilon. +* ``assert_arrays_eq(Actual, Expected, Size, [Message])``: + passes if all elements of Actual (from 0 to Size - 1) are equals to those + of Expected. +* ``assert_arrays_eq_cmp(Actual, Expected, Size, Cmp, [Message])``: + Same as ``arrays_eq`` but equality is defined by the result of the binary + Cmp function. -Please note that ``arrays_(n)eq`` assertions should not be used for padded structures. +Equality and lexical comparison assertions are also available for strings: + +* ``assert_strings_eq(Actual, Expected, [Message])`` +* ``assert_strings_lt(Actual, Expected, [Message])`` +* ``assert_strings_leq(Actual, Expected, [Message])`` +* ``assert_strings_gt(Actual, Expected, [Message])`` +* ``assert_strings_geq(Actual, Expected, [Message])`` + +And some assertions have a logical negative counterpart: + +* ``assert_not(Condition, [Message])`` +* ``assert_not_null(Ptr, [Message])`` +* ``assert_neq(Actual, Unexpected, [Message])`` +* ``assert_float_neq(Actual, Unexpected, Epsilon, [Message])`` +* ``assert_strings_neq(Actual, Unexpected, [Message])`` +* ``assert_arrays_neq(Actual, Unexpected, Size, [Message])`` +* ``assert_arrays_neq_cmp(Actual, Unexpected, Size, Cmp, [Message])`` + +Of course, every ``assert`` has an ``expect`` counterpart. + +Please note that ``arrays_(n)eq`` assertions should not be used on padded +structures -- please use ``arrays_(n)eq_cmp`` instead. Configuring tests ----------------- From cc9ea9c1a67814422a1ada8d14be946dd2ccedd7 Mon Sep 17 00:00:00 2001 From: Snaipe Date: Wed, 15 Apr 2015 22:47:09 +0200 Subject: [PATCH 60/60] [v1.2.0] Version bump --- Makefile.am | 2 +- README.md | 8 ++++---- configure.ac | 2 +- doc/conf.py | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Makefile.am b/Makefile.am index 1bffb46..87b4321 100644 --- a/Makefile.am +++ b/Makefile.am @@ -15,7 +15,7 @@ libcriterion_la_CFLAGS = \ -I$(top_srcdir)/dependencies/csptr/include/ \ $(COVERAGE_CFLAGS) -libcriterion_la_LDFLAGS = $(COVERAGE_LDFLAGS) +libcriterion_la_LDFLAGS = $(COVERAGE_LDFLAGS) -version-info 1:0:0 # dirty but unless someone has a better alternative... libcriterion_la_LIBADD = dependencies/csptr/src/libcsptr_la-*.lo diff --git a/README.md b/README.md index 8e35b6e..5974341 100644 --- a/README.md +++ b/README.md @@ -35,10 +35,10 @@ the user would have with other frameworks: ## Downloads -* [Linux (x86_64)](https://github.com/Snaipe/Criterion/releases/download/v1.1.0/criterion-1.1.0-linux-x86_64.tar.bz2) -* [OS X (x86_64)](https://github.com/Snaipe/Criterion/releases/download/v1.1.0/criterion-1.1.0-osx-x86_64.tar.bz2) -* [Windows (x86_64)](https://github.com/Snaipe/Criterion/releases/download/v1.1.0/criterion-1.1.0-win-x86_64.tar.bz2) -* [FreeBSD (x86_64)](https://github.com/Snaipe/Criterion/releases/download/v1.1.0/criterion-1.1.0-freebsd-x86_64.tar.bz2) +* [Linux (x86_64)](https://github.com/Snaipe/Criterion/releases/download/v1.2.0/criterion-1.2.0-linux-x86_64.tar.bz2) +* [OS X (x86_64)](https://github.com/Snaipe/Criterion/releases/download/v1.2.0/criterion-1.2.0-osx-x86_64.tar.bz2) +* [Windows (x86_64)](https://github.com/Snaipe/Criterion/releases/download/v1.2.0/criterion-1.2.0-win-x86_64.tar.bz2) +* [FreeBSD (x86_64)](https://github.com/Snaipe/Criterion/releases/download/v1.2.0/criterion-1.2.0-freebsd-x86_64.tar.bz2) If you have a different platform, you can still [build the library from source](http://criterion.readthedocs.org/en/latest/setup.html#installation) diff --git a/configure.ac b/configure.ac index 836281f..49e3252 100644 --- a/configure.ac +++ b/configure.ac @@ -1,6 +1,6 @@ AC_PREREQ([2.60]) -AC_INIT([criterion], [1.1.0], [], [criterion], [franklinmathieu@gmail.com]) +AC_INIT([criterion], [1.2.0], [], [criterion], [franklinmathieu@gmail.com]) AC_CONFIG_SRCDIR([src/runner.c]) LT_PREREQ([2.2.4]) diff --git a/doc/conf.py b/doc/conf.py index aa60f50..2dd677a 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -39,7 +39,7 @@ copyright = u'2015, Franklin "Snaipe" Mathieu' # built documents. # # The short X.Y version. -version = '1.1.0' +version = '1.2.0' # The full version, including alpha/beta/rc tags. release = version