From 4da49ea4307c26e4e38e11beb4b3495886460e0e Mon Sep 17 00:00:00 2001 From: Snaipe Date: Tue, 14 Apr 2015 15:07:21 +0200 Subject: [PATCH 01/78] Removed csptr dependency, you must now install it beforehand --- .gitmodules | 3 --- dependencies/csptr | 1 - 2 files changed, 4 deletions(-) delete mode 100644 .gitmodules delete mode 160000 dependencies/csptr diff --git a/.gitmodules b/.gitmodules deleted file mode 100644 index fb15be4..0000000 --- a/.gitmodules +++ /dev/null @@ -1,3 +0,0 @@ -[submodule "dependencies/csptr"] - path = dependencies/csptr - url = https://github.com/Snaipe/c-smart-pointers.git diff --git a/dependencies/csptr b/dependencies/csptr deleted file mode 160000 index 4f3e63a..0000000 --- a/dependencies/csptr +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 4f3e63aca586939ed734f4e76c4f7f7f8c07d247 From 4d42af0fcb44e8948328c2ee6bca6f9b38812053 Mon Sep 17 00:00:00 2001 From: Snaipe Date: Tue, 14 Apr 2015 15:08:51 +0200 Subject: [PATCH 02/78] Switched the output to a shared library --- Makefile.am | 4 +--- configure.ac | 2 +- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/Makefile.am b/Makefile.am index bcc7f94..ca07f02 100644 --- a/Makefile.am +++ b/Makefile.am @@ -16,9 +16,7 @@ libcriterion_la_CFLAGS = \ $(COVERAGE_CFLAGS) libcriterion_la_LDFLAGS = $(COVERAGE_LDFLAGS) - -# dirty but unless someone has a better alternative... -libcriterion_la_LIBADD = dependencies/csptr/src/libcsptr_la-*.lo +libcriterion_la_LIBADD = -lcsptr EXTRA_DIST = config.rpath LICENSE diff --git a/configure.ac b/configure.ac index 836281f..4e3160f 100644 --- a/configure.ac +++ b/configure.ac @@ -7,7 +7,7 @@ LT_PREREQ([2.2.4]) AC_CANONICAL_SYSTEM AM_INIT_AUTOMAKE([dist-bzip2 no-dist-gzip foreign subdir-objects parallel-tests color-tests]) -LT_INIT([disable-shared]) +LT_INIT([disable-static]) AC_CONFIG_MACRO_DIR([m4]) AC_PROG_CC From 8bec0a72309ee33146022ce215aab1ab3aa96a8f Mon Sep 17 00:00:00 2001 From: Snaipe Date: Tue, 14 Apr 2015 17:14:42 +0200 Subject: [PATCH 03/78] Removed filesystem dependency to libcsptr and link to the static library --- Makefile.am | 4 +--- configure.ac | 6 ++++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Makefile.am b/Makefile.am index ca07f02..f16b156 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,6 +1,6 @@ ACLOCAL_AMFLAGS = -I m4 AM_CPPFLAGS = -DLOCALEDIR='"$(localedir)"' -SUBDIRS = po dependencies/csptr samples +SUBDIRS = po samples lib_LTLIBRARIES = libcriterion.la @@ -12,11 +12,9 @@ libcriterion_la_CFLAGS = \ -std=gnu11 \ -I$(top_srcdir)/src/ \ -I$(top_srcdir)/include/ \ - -I$(top_srcdir)/dependencies/csptr/include/ \ $(COVERAGE_CFLAGS) libcriterion_la_LDFLAGS = $(COVERAGE_LDFLAGS) -libcriterion_la_LIBADD = -lcsptr EXTRA_DIST = config.rpath LICENSE diff --git a/configure.ac b/configure.ac index 4e3160f..360c9c5 100644 --- a/configure.ac +++ b/configure.ac @@ -20,6 +20,10 @@ AC_PROG_LN_S AC_PROG_MAKE_SET AC_SUBST([LIBTOOL_DEPS]) +AC_CHECK_LIB([csptr], [smalloc], [], [AC_MSG_ERROR([Could not find libcsptr dependency. \ + Please go to https://github.com/Snaipe/c-smart-pointers.git \ + and follow the installation instructions.])]) + AC_FUNC_FNMATCH enable_rt_tests="no" @@ -43,6 +47,4 @@ AC_ARG_ENABLE([gcov], AC_CONFIG_HEADERS([src/config.h]) AC_CONFIG_FILES([Makefile samples/Makefile po/Makefile.in]) -AC_CONFIG_SUBDIRS([dependencies/csptr]) - AC_OUTPUT From e2f3daa07b3306108c28c89ff5067c252829e6ac Mon Sep 17 00:00:00 2001 From: Snaipe Date: Wed, 15 Apr 2015 00:19:10 +0200 Subject: [PATCH 04/78] Added libcsptr installation script --- .ci/install-libcsptr.sh | 14 ++++++++++++++ .travis.yml | 1 + appveyor.yml | 1 + 3 files changed, 16 insertions(+) create mode 100755 .ci/install-libcsptr.sh diff --git a/.ci/install-libcsptr.sh b/.ci/install-libcsptr.sh new file mode 100755 index 0000000..fd0f471 --- /dev/null +++ b/.ci/install-libcsptr.sh @@ -0,0 +1,14 @@ +#!/bin/bash +repo="https://github.com/Snaipe/libcsptr.git" +tag="v2.0.1" + +mkdir dependencies +git clone --branch ${tag} --depth 1 ${repo} dependencies/libcsptr && +( + cd dependencies/libcsptr && + ./autogen.sh && + ./configure --prefix=/usr && + make && + sudo make install +) +rm -Rf dependencies diff --git a/.travis.yml b/.travis.yml index 55f5f64..43565d4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,6 +7,7 @@ before_install: - 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 + - .ci/install-libcsptr.sh script: - ./autogen.sh && ./configure --enable-gcov CFLAGS="-g -O0" && make && make check after_success: diff --git a/appveyor.yml b/appveyor.yml index 76e605f..55db7d9 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -53,6 +53,7 @@ configuration: Release install: - 'set GCOV_PREFIX=%APPVEYOR_BUILD_FOLDER%' + - '%CYG_BASH% -lc "cd $APPVEYOR_BUILD_FOLDER; .ci/install-libcsptr.sh"' - "%CYG_BASH% -lc 'cd $APPVEYOR_BUILD_FOLDER; ./autogen.sh'" - '%CYG_BASH% -lc "cd $APPVEYOR_BUILD_FOLDER; exec 0 Date: Wed, 15 Apr 2015 13:06:55 +0200 Subject: [PATCH 05/78] Fixed bad file descriptor error on appveyor builds --- appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index 55db7d9..096f56e 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -53,7 +53,7 @@ configuration: Release install: - 'set GCOV_PREFIX=%APPVEYOR_BUILD_FOLDER%' - - '%CYG_BASH% -lc "cd $APPVEYOR_BUILD_FOLDER; .ci/install-libcsptr.sh"' + - '%CYG_BASH% -lc "cd $APPVEYOR_BUILD_FOLDER; exec 0 Date: Wed, 15 Apr 2015 13:34:34 +0200 Subject: [PATCH 06/78] Added sudo-less install for cygwin builds --- .ci/install-libcsptr.sh | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/.ci/install-libcsptr.sh b/.ci/install-libcsptr.sh index fd0f471..79b4d4d 100755 --- a/.ci/install-libcsptr.sh +++ b/.ci/install-libcsptr.sh @@ -9,6 +9,12 @@ git clone --branch ${tag} --depth 1 ${repo} dependencies/libcsptr && ./autogen.sh && ./configure --prefix=/usr && make && - sudo make install + { + if command -v sudo; then + sudo make install + else + make install + fi + } ) rm -Rf dependencies From 39c8dfd6af9c25d73373c26e9db5c1618655b65f Mon Sep 17 00:00:00 2001 From: Snaipe Date: Wed, 15 Apr 2015 17:26:16 +0200 Subject: [PATCH 07/78] Fixed libcsptr misinstalling on appveyor builds --- .ci/install-libcsptr.sh | 4 ++-- .travis.yml | 2 +- appveyor.yml | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.ci/install-libcsptr.sh b/.ci/install-libcsptr.sh index 79b4d4d..2826ec7 100755 --- a/.ci/install-libcsptr.sh +++ b/.ci/install-libcsptr.sh @@ -1,13 +1,13 @@ #!/bin/bash repo="https://github.com/Snaipe/libcsptr.git" -tag="v2.0.1" +tag="v2.0.2" mkdir dependencies git clone --branch ${tag} --depth 1 ${repo} dependencies/libcsptr && ( cd dependencies/libcsptr && ./autogen.sh && - ./configure --prefix=/usr && + ./configure "$@" && make && { if command -v sudo; then diff --git a/.travis.yml b/.travis.yml index 43565d4..f8901f3 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,7 +7,7 @@ before_install: - 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 - - .ci/install-libcsptr.sh + - .ci/install-libcsptr.sh --prefix=/usr script: - ./autogen.sh && ./configure --enable-gcov CFLAGS="-g -O0" && make && make check after_success: diff --git a/appveyor.yml b/appveyor.yml index 096f56e..1083154 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -53,7 +53,7 @@ configuration: Release install: - 'set GCOV_PREFIX=%APPVEYOR_BUILD_FOLDER%' - - '%CYG_BASH% -lc "cd $APPVEYOR_BUILD_FOLDER; exec 0 Date: Wed, 15 Apr 2015 17:50:33 +0200 Subject: [PATCH 08/78] Added -no-undefined link option for PE targets --- Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile.am b/Makefile.am index f16b156..54a5eb3 100644 --- a/Makefile.am +++ b/Makefile.am @@ -14,7 +14,7 @@ libcriterion_la_CFLAGS = \ -I$(top_srcdir)/include/ \ $(COVERAGE_CFLAGS) -libcriterion_la_LDFLAGS = $(COVERAGE_LDFLAGS) +libcriterion_la_LDFLAGS = $(COVERAGE_LDFLAGS) -no-undefined EXTRA_DIST = config.rpath LICENSE From 4472085c7db6ddfbb505622256a728f8e3a2bd4e Mon Sep 17 00:00:00 2001 From: offa Date: Mon, 27 Apr 2015 18:41:50 +0200 Subject: [PATCH 09/78] Possible leak fixed. --- src/event.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/event.c b/src/event.c index cca6ce6..6146c95 100644 --- a/src/event.c +++ b/src/event.c @@ -45,8 +45,10 @@ struct event *read_event(FILE *f) { case ASSERT: { const size_t assert_size = sizeof (struct criterion_assert_stats); unsigned char *buf = malloc(assert_size); - if (fread(buf, assert_size, 1, f) == 0) + if (fread(buf, assert_size, 1, f) == 0) { + free(buf); return NULL; + } return unique_ptr(struct event, .value = { .kind = kind, .data = buf }, @@ -54,8 +56,10 @@ struct event *read_event(FILE *f) { } case POST_TEST: { double *elapsed_time = malloc(sizeof (double)); - if (fread(elapsed_time, sizeof (double), 1, f) == 0) + if (fread(elapsed_time, sizeof (double), 1, f) == 0) { + free(elapsed_time); return NULL; + } return unique_ptr(struct event, .value = { .kind = kind, .data = elapsed_time }, From bff50816118175cf199ffb753a4949526fc65853 Mon Sep 17 00:00:00 2001 From: Snaipe Date: Sun, 3 May 2015 00:41:58 +0200 Subject: [PATCH 10/78] [Issue #24] Implemented extended shell pattern using a PCRE translator --- Makefile.am | 4 +- samples/Makefile.am | 2 +- src/extmatch.c | 200 ++++++++++++++++++++++++++++++++++++++++++++ src/extmatch.h | 6 ++ src/report.c | 4 +- 5 files changed, 212 insertions(+), 4 deletions(-) create mode 100644 src/extmatch.c create mode 100644 src/extmatch.h diff --git a/Makefile.am b/Makefile.am index 87b4321..63fc36e 100644 --- a/Makefile.am +++ b/Makefile.am @@ -18,7 +18,7 @@ libcriterion_la_CFLAGS = \ 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 +libcriterion_la_LIBADD = dependencies/csptr/src/libcsptr_la-*.lo -lpcre EXTRA_DIST = config.rpath LICENSE @@ -59,6 +59,8 @@ libcriterion_la_SOURCES = \ src/i18n.h \ src/ordered-set.c \ src/posix-compat.c \ + src/extmatch.c \ + src/extmatch.h \ src/main.c TARGET = $(PACKAGE)-$(VERSION) diff --git a/samples/Makefile.am b/samples/Makefile.am index 7ed5f12..e5c5a06 100644 --- a/samples/Makefile.am +++ b/samples/Makefile.am @@ -14,7 +14,7 @@ TESTS_ENVIRONMENT = CRITERION_ALWAYS_SUCCEED=1 check_PROGRAMS := $(BIN_TESTS) CFLAGS = -I$(top_srcdir)/include/ -std=c99 -Wall -Wextra -pedantic -LDADD = -L$(top_srcdir)/ -lcriterion +LDADD = -L$(top_srcdir)/ -lcriterion -lpcre if ENABLE_RT_TESTS BIN_TESTS += with-time diff --git a/src/extmatch.c b/src/extmatch.c new file mode 100644 index 0000000..e76ebec --- /dev/null +++ b/src/extmatch.c @@ -0,0 +1,200 @@ +#include +#include +#include + +#include +#include "criterion/common.h" + +struct context { + int depth; + char *dst; + const char *src; + char old, cur; + int eos; +}; + +void transform_impl(struct context *ctx); + +static inline void transform_rec(struct context *ctx) { + struct context new_ctx = { + .depth = ctx->depth + 1, + .dst = ctx->dst, + .src = ctx->src, + .old = ctx->old, + .eos = ctx->eos, + }; + transform_impl(&new_ctx); + ctx->dst = new_ctx.dst; + ctx->src = new_ctx.src; + ctx->old = new_ctx.old; + ctx->eos = new_ctx.eos; +} + +static inline char read_char(struct context *ctx) { + char c = *ctx->src; + ctx->old = ctx->cur; + ctx->cur = c; + if (c == '\0') + ctx->eos = 1; + ++ctx->src; + return c; +} + +static inline char peek_char(struct context *ctx) { + return *ctx->src; +} + +static inline void copy_char(struct context *ctx, char src) { + *ctx->dst = src; + ++ctx->dst; +} + +static inline void dup_char(struct context *ctx) { + copy_char(ctx, read_char(ctx)); +} + +static inline void copy_str(struct context *ctx, const char *src) { + size_t len = strlen(src); + strncpy(ctx->dst, src, len); + ctx->dst += len; +} + +#define PREPREFIX 0 +#define POSTPREFIX 1 +#define PRESUFFIX 2 +#define POSTSUFFIX 3 +#define ELSESTR 4 + +typedef struct { + int (*validator)(struct context *ctx); + char *str; +} handler_arg; + +static int active() { return 1; } +static int inactive() { return 0; } + +static int is_eos(struct context *ctx) { + return peek_char(ctx) == '\0'; +} + +static inline void handle_special(struct context *ctx, handler_arg strs[5]) { + if (peek_char(ctx) == '(') { + if ((strs[0].validator ?: inactive)(ctx)) + copy_str(ctx, strs[0].str); + dup_char(ctx); + if ((strs[1].validator ?: inactive)(ctx)) + copy_str(ctx, strs[1].str); + + transform_rec(ctx); + + if ((strs[2].validator ?: inactive)(ctx)) + copy_str(ctx,strs[2].str); + copy_char(ctx, ')'); + if ((strs[3].validator ?: inactive)(ctx)) + copy_str(ctx, strs[3].str); + } else if ((strs[4].validator ?: inactive)(ctx)) { + copy_str(ctx, strs[4].str); + } +} + +# define Handler(Name, ...) \ + static void Name(struct context *ctx, UNUSED char c) { \ + handle_special(ctx, (handler_arg[5]) { \ + __VA_ARGS__ \ + }); \ + } + +# define _ active +Handler(handle_plus, [POSTSUFFIX] = {_, "+"}, [ELSESTR] = {_, "+" }); +Handler(handle_star, [POSTSUFFIX] = {_, "*"}, [ELSESTR] = {_, ".*"}); +Handler(handle_wild, [POSTSUFFIX] = {_, "?"}, [ELSESTR] = {_, "." }); +Handler(handle_excl, + [POSTPREFIX] = {_, "?!"}, + [PRESUFFIX] = {is_eos, "$" }, + [POSTSUFFIX] = {_, ".*"}, + [ELSESTR] = {_, "!" } + ); +Handler(handle_at, [ELSESTR] = {_, "@"}); +# undef _ + +static void handle_rbra(struct context *ctx, UNUSED char c) { + copy_char(ctx, c); + if (peek_char(ctx) == '!') { + read_char(ctx); + copy_char(ctx, '^'); + } +} + +static void escape_char(struct context *ctx, char c) { + copy_char(ctx, '\\'); + copy_char(ctx, c); +} + +static void escape_pipe(struct context *ctx, UNUSED char c) { + if (ctx->depth == 0) + copy_char(ctx, '\\'); + copy_char(ctx, '|'); +} + +typedef void (*f_handler)(struct context *, char); + +void transform_impl(struct context *ctx) { + static f_handler handlers[] = { + ['+'] = handle_plus, + ['*'] = handle_star, + ['?'] = handle_wild, + ['!'] = handle_excl, + ['['] = handle_rbra, + ['@'] = handle_at, + + ['.'] = escape_char, + ['('] = escape_char, + [')'] = escape_char, + ['|'] = escape_pipe, + }; + for (char c = read_char(ctx); !ctx->eos; c = read_char(ctx)) { + f_handler handler = handlers[(unsigned char) c]; + + if (ctx->old == '\\') + handler = copy_char; + + if (c == ')' && ctx->depth > 0) + return; + + (handler ?: copy_char)(ctx, c); + + if (ctx->eos) + return; + } + if (ctx->depth > 0) { + puts("pattern error: mismatching parenthesis"); + exit(1); + } +} + +static void transform(const char *pattern, char *result) { + struct context ctx = { + .src = pattern, + .dst = result, + }; + copy_char(&ctx, '^'); + transform_impl(&ctx); + copy_char(&ctx, '$'); + copy_char(&ctx, '\0'); +} + +int extmatch(const char *pattern, const char *string) { + char regex[strlen(pattern) * 2]; + transform(pattern, regex); + + const char *errmsg; + int erroffset; + pcre *preg = pcre_compile(regex, 0, &errmsg, &erroffset, NULL); + if (preg) { + int res = pcre_exec(preg, NULL, string, strlen(string), 0, 0, NULL, 0); + pcre_free(preg); + return res; + } + printf("pattern error: %s\n", errmsg); + exit(1); +} diff --git a/src/extmatch.h b/src/extmatch.h new file mode 100644 index 0000000..3c6f528 --- /dev/null +++ b/src/extmatch.h @@ -0,0 +1,6 @@ +#ifndef EXTMATCH_H_ +# define EXTMATCH_H_ + +int extmatch(const char *pattern, const char *string); + +#endif /* !EXTMATCH_H_ */ diff --git a/src/report.c b/src/report.c index ea13806..847600d 100644 --- a/src/report.c +++ b/src/report.c @@ -33,7 +33,7 @@ #include "config.h" #ifdef HAVE_FNMATCH -#include +#include "extmatch.h" #endif #define IMPL_CALL_REPORT_HOOKS(Kind) \ @@ -60,7 +60,7 @@ void disable_unmatching(struct criterion_test_set *set) { continue; FOREACH_SET(struct criterion_test *test, s->tests) { - if (fnmatch(criterion_options.pattern, test->data->identifier_, 0)) + if (extmatch(criterion_options.pattern, test->data->identifier_)) test->data->disabled = true; } } From 1dcba90eb3b3d8f2315426cebf655d8fd3fa5ceb Mon Sep 17 00:00:00 2001 From: Snaipe Date: Sun, 3 May 2015 16:02:26 +0200 Subject: [PATCH 11/78] Added optimal max pattern length and proof, added better error handling --- src/extmatch.c | 94 ++++++++++++++++++++++++++++++++++++++------------ src/extmatch.h | 2 +- src/report.c | 8 ++++- 3 files changed, 80 insertions(+), 24 deletions(-) diff --git a/src/extmatch.c b/src/extmatch.c index e76ebec..486a612 100644 --- a/src/extmatch.c +++ b/src/extmatch.c @@ -1,6 +1,7 @@ #include #include #include +#include #include #include "criterion/common.h" @@ -11,6 +12,8 @@ struct context { const char *src; char old, cur; int eos; + const char **errmsg; + jmp_buf jmp; }; void transform_impl(struct context *ctx); @@ -167,34 +170,81 @@ void transform_impl(struct context *ctx) { return; } if (ctx->depth > 0) { - puts("pattern error: mismatching parenthesis"); - exit(1); + *ctx->errmsg = "mismatching parenthesis"; + longjmp(ctx->jmp, -1); // abort operation } } -static void transform(const char *pattern, char *result) { +static int transform(const char *pattern, char *result, const char **errmsg) { struct context ctx = { .src = pattern, .dst = result, + .errmsg = errmsg, }; - copy_char(&ctx, '^'); - transform_impl(&ctx); - copy_char(&ctx, '$'); - copy_char(&ctx, '\0'); -} - -int extmatch(const char *pattern, const char *string) { - char regex[strlen(pattern) * 2]; - transform(pattern, regex); - - const char *errmsg; - int erroffset; - pcre *preg = pcre_compile(regex, 0, &errmsg, &erroffset, NULL); - if (preg) { - int res = pcre_exec(preg, NULL, string, strlen(string), 0, 0, NULL, 0); - pcre_free(preg); - return res; + if (!setjmp(ctx.jmp)) { + copy_char(&ctx, '^'); + transform_impl(&ctx); + copy_char(&ctx, '$'); + copy_char(&ctx, '\0'); + return 0; } - printf("pattern error: %s\n", errmsg); - exit(1); + return -1; +} + +/* + * let T be the transformation function, + * let diff be the function that yields the greatest character difference + * before and after its parameter has been transformed by T. + * + * T('*') = '.*'; diff('*') = 1 + * T('!()') = '(?!).*' or '(?!$).*'; diff('!()') = 4 + * T('@') = '' or '@'; diff('@') = 0 + * T('|') = '|' or '\|'; diff('|') = 1 + * T('.') = '\.'; diff('.') = 1 + * T('(') = '\('; diff('(') = 1 + * T(')') = '\)'; diff(')') = 1 + * for every other 1 character string s, we have T(s) = s; hence diff(s) = 0 + * + * let num be the function that yields the number of occurences of a string. + * let spec be the set {(s, num(s)) | ∀s} + * ∀s, lenght(T(s)) = length(s) + Σ((c_i, n_i) ∈ spec, n_i * diff(c_i)) + * + * let S = {'*', '!()', '|', '.', '(', ')'}. + * since ∀s ∉ S, diff(s) = 0, we can simplify the above equation as: + * + * ∀s, lenght(T(s)) = length(s) + num('*') + num('|') + num('.') + * + num('(') + num(')') + 4 * num('!()'). + * + * We must now find the maximal length L such as ∀s, L >= length(T(s)) + * + * It is immediately apparent that the largest string will depend on the number + * of occurrences of '!()'. Hence, let s be a string that is a repeating + * sequence of '!()', + * + * let N = floor(length(s) / 3), + * let Q = length(s) mod 3, + * ∀s, num('!()') = N (1) + * + * ∀s, length(T(s)) <= length(s) + 4 * N + * <= 3 * N + Q + 4 * N + * <= 7 * N + 2 + * <= 7 * floor(length(s) / 3) + 2 + * + */ +static inline size_t max_length(size_t len) { + return 7 * len / 3 + 2; +} + +int extmatch(const char *pattern, const char *string, const char **errmsg) { + char regex[max_length(strlen(pattern))]; + if (transform(pattern, regex, errmsg) != -1) { + int erroffset; + pcre *preg = pcre_compile(regex, 0, errmsg, &erroffset, NULL); + if (preg) { + int res = pcre_exec(preg, NULL, string, strlen(string), 0, 0, NULL, 0); + pcre_free(preg); + return res; + } + } + return -10; } diff --git a/src/extmatch.h b/src/extmatch.h index 3c6f528..d65eeb1 100644 --- a/src/extmatch.h +++ b/src/extmatch.h @@ -1,6 +1,6 @@ #ifndef EXTMATCH_H_ # define EXTMATCH_H_ -int extmatch(const char *pattern, const char *string); +int extmatch(const char *pattern, const char *string, const char **errmsg); #endif /* !EXTMATCH_H_ */ diff --git a/src/report.c b/src/report.c index 847600d..4ebbd8f 100644 --- a/src/report.c +++ b/src/report.c @@ -60,8 +60,14 @@ void disable_unmatching(struct criterion_test_set *set) { continue; FOREACH_SET(struct criterion_test *test, s->tests) { - if (extmatch(criterion_options.pattern, test->data->identifier_)) + const char *errmsg; + int ret = extmatch(criterion_options.pattern, test->data->identifier_, &errmsg); + if (ret == -10) { + printf("pattern error: %s\n", errmsg); + exit(1); + } else if (ret < 0) { test->data->disabled = true; + } } } } From e8443cd07126425aad3f97fd734582e48e4bf712 Mon Sep 17 00:00:00 2001 From: Snaipe Date: Sun, 3 May 2015 16:19:23 +0200 Subject: [PATCH 12/78] Fixed wrong step in max_length proof --- src/extmatch.c | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/src/extmatch.c b/src/extmatch.c index 486a612..f03154d 100644 --- a/src/extmatch.c +++ b/src/extmatch.c @@ -218,21 +218,26 @@ static int transform(const char *pattern, char *result, const char **errmsg) { * We must now find the maximal length L such as ∀s, L >= length(T(s)) * * It is immediately apparent that the largest string will depend on the number - * of occurrences of '!()'. Hence, let s be a string that is a repeating - * sequence of '!()', + * of occurrences of '!()'. Hence, let u be a string that is a repeating + * sequence of '!()' padded by '.' to a multiple of 3, * - * let N = floor(length(s) / 3), - * let Q = length(s) mod 3, - * ∀s, num('!()') = N (1) + * let N = floor(length(u) / 3), + * let Q = length(u) mod 3, + * hence num('!()') = N. * - * ∀s, length(T(s)) <= length(s) + 4 * N - * <= 3 * N + Q + 4 * N - * <= 7 * N + 2 - * <= 7 * floor(length(s) / 3) + 2 + * ∀s | lenght(s) = length(u), + * length(T(s)) <= length(T(u)) + * <= length(u) | the original length + * + 4 * N | the expansion of all '!()' + * + Q * diff('.') | the expansion of Q '.' + * <= 3 * N + Q + 4 * N + Q + * <= 7 * N + 4 + * <= 7 * floor(length(u) / 3) + 4 + * <= 7 * floor(length(s) / 3) + 4 * */ static inline size_t max_length(size_t len) { - return 7 * len / 3 + 2; + return 7 * len / 3 + 4; } int extmatch(const char *pattern, const char *string, const char **errmsg) { From 6ba229cae37f61e6bae189573f4dc66fb553b67c Mon Sep 17 00:00:00 2001 From: Snaipe Date: Sun, 3 May 2015 23:10:14 +0200 Subject: [PATCH 13/78] Temporarly dropped support for windows --- README.md | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 8e35b6e..3c30899 100644 --- a/README.md +++ b/README.md @@ -31,13 +31,12 @@ 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 MinGW or Cygwin). +* [x] Runs on Linux, FreeBSD, and Mac OS X (Windows is currenly not completely supported). ## 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) If you have a different platform, you can still [build the library from source](http://criterion.readthedocs.org/en/latest/setup.html#installation) @@ -99,8 +98,8 @@ 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 MinGW and Cygwin ports of GCC). + most \*nix systems; Mac OS X Yosemite 10.10, and FreeBSD 10.0. + Windows is currently not supported, but it being worked on. [online-docs]: http://criterion.readthedocs.org/ [pdf-docs]: http://readthedocs.org/projects/criterion/downloads/pdf/latest/ From 0020f1aa27674141c81bf3339a40d14edc55423a Mon Sep 17 00:00:00 2001 From: Snaipe Date: Mon, 4 May 2015 00:05:52 +0200 Subject: [PATCH 14/78] Added autoconf conditional for PCRE --- configure.ac | 4 ++-- src/main.c | 8 ++++---- src/report.c | 6 +++--- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/configure.ac b/configure.ac index a0d8d93..4d9b7a0 100644 --- a/configure.ac +++ b/configure.ac @@ -24,13 +24,13 @@ AC_CHECK_LIB([csptr], [smalloc], [], [AC_MSG_ERROR([Could not find libcsptr depe Please go to https://github.com/Snaipe/c-smart-pointers.git \ and follow the installation instructions.])]) -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"]) +AC_CHECK_LIB([pcre], [pcre_compile], [AC_DEFINE([HAVE_PCRE], [1], [Define to 1 if you have the `pcre` library (-lpcre)])]) + AM_GNU_GETTEXT([external]) AM_GNU_GETTEXT_VERSION([0.18]) diff --git a/src/main.c b/src/main.c index 32859c9..0402d71 100644 --- a/src/main.c +++ b/src/main.c @@ -38,7 +38,7 @@ # define VERSION_MSG "Tests compiled with Criterion v" VERSION "\n" -#ifdef HAVE_FNMATCH +#ifdef HAVE_PCRE # define PATTERN_USAGE \ " --pattern [PATTERN]: run tests matching the " \ "given pattern\n" @@ -124,7 +124,7 @@ 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 +#ifdef HAVE_PCRE {"pattern", required_argument, 0, 'p'}, #endif {"always-succeed", no_argument, 0, 'y'}, @@ -146,7 +146,7 @@ int main(int argc, char *argv[]) { 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 +#ifdef HAVE_PCRE opt->pattern = getenv("CRITERION_TEST_PATTERN"); #endif @@ -162,7 +162,7 @@ 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 +#ifdef HAVE_PCRE case 'p': criterion_options.pattern = optarg; break; #endif case 't': use_tap = true; break; diff --git a/src/report.c b/src/report.c index 4ebbd8f..59e3738 100644 --- a/src/report.c +++ b/src/report.c @@ -32,7 +32,7 @@ #include "report.h" #include "config.h" -#ifdef HAVE_FNMATCH +#ifdef HAVE_PCRE #include "extmatch.h" #endif @@ -53,7 +53,7 @@ __attribute__((always_inline)) static inline void nothing() {} -#ifdef HAVE_FNMATCH +#ifdef HAVE_PCRE 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) @@ -74,7 +74,7 @@ void disable_unmatching(struct criterion_test_set *set) { #endif IMPL_REPORT_HOOK(PRE_ALL)(struct criterion_test_set *set) { -#ifdef HAVE_FNMATCH +#ifdef HAVE_PCRE if (criterion_options.pattern) { disable_unmatching(set); } From dd5e4eea234fdbde70ca057386ecf01c732102fc Mon Sep 17 00:00:00 2001 From: Snaipe Date: Tue, 30 Jun 2015 14:18:21 +0200 Subject: [PATCH 15/78] [Issue #28] Added test name in the setup/teardown crash message --- po/fr.po | 12 +++++++----- src/log/normal.c | 5 +++-- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/po/fr.po b/po/fr.po index ffbd217..f9627f7 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 23:08+0200\n" +"POT-Creation-Date: 2015-06-30 12:07+0200\n" "PO-Revision-Date: 2015-04-03 17:58+0200\n" "Last-Translator: \n" "Language-Team: French\n" @@ -70,8 +70,10 @@ 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" +#, fuzzy, c-format +msgid "" +"%1$sWarning! The test `%2$s::%3$s` crashed during its setup or teardown." +"%4$s\n" msgstr "" -"%1$sAttention! Ce test a planté pendant son initialisation ou sa " -"finalisation.%2$s\n" +"%1$sAttention! Le test `%2$s::%3$s` a planté pendant son initialisation ou " +"sa finalisation.%4$s\n" diff --git a/src/log/normal.c b/src/log/normal.c index 42645be..8b0f2cc 100644 --- a/src/log/normal.c +++ b/src/log/normal.c @@ -136,8 +136,9 @@ void normal_log_test_crash(struct criterion_test_stats *stats) { 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); + _("%1$sWarning! The test `%2$s::%3$s` crashed during its " + "setup or teardown.%4$s\n"), + FG_BOLD, stats->test->category, stats->test->name, RESET); } void normal_log_pre_suite(struct criterion_suite_set *set) { From e48bd7c0379618d11fc094c39d1cb677371d5b23 Mon Sep 17 00:00:00 2001 From: Snaipe Date: Tue, 28 Jul 2015 19:03:46 +0200 Subject: [PATCH 16/78] Switched build system to cmake --- .cmake/Modules/FindGettext.cmake | 285 ++++++++++++++++++++++++++++++ .cmake/Modules/FindLibcsptr.cmake | 31 ++++ .cmake/Modules/FindPCRE.cmake | 37 ++++ .cmake/Modules/uninstall.cmake | 23 +++ .gitignore | 5 +- CMakeLists.txt | 90 ++++++++++ Makefile.am | 75 -------- autogen.sh | 4 - configure.ac | 50 ------ samples/CMakeLists.txt | 24 +++ 10 files changed, 492 insertions(+), 132 deletions(-) create mode 100644 .cmake/Modules/FindGettext.cmake create mode 100644 .cmake/Modules/FindLibcsptr.cmake create mode 100644 .cmake/Modules/FindPCRE.cmake create mode 100644 .cmake/Modules/uninstall.cmake create mode 100644 CMakeLists.txt delete mode 100644 Makefile.am delete mode 100755 autogen.sh delete mode 100644 configure.ac create mode 100644 samples/CMakeLists.txt diff --git a/.cmake/Modules/FindGettext.cmake b/.cmake/Modules/FindGettext.cmake new file mode 100644 index 0000000..553b13d --- /dev/null +++ b/.cmake/Modules/FindGettext.cmake @@ -0,0 +1,285 @@ +# Copyright (c) 2012, Jarryd Beck +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. + + +# This module creates build rules for updating translation files made +# with gettext +# In your top level CMakeLists.txt, do +# include(GettextTranslate) +# then in any po directory where you want things to be translated, write +# GettextTranslate() +# +# This module also finds the gettext binaries. If these are in a non-standard +# location, you can define the following variables to provide paths to search +# in +# GettextTranslate_BINARIES --- a path in which to look for every program +# GettextTranslate_XGETTEXT --- the xgettext program +# GettextTranslate_MSGINIT --- the msginit program +# GettextTranslate_MSGFILTER --- the msgfilter program +# GettextTranslate_MSGCONV --- the msgconv program +# GettextTranslate_MSGMERGE --- the msgmerge program +# GettextTranslate_MSGFMT --- the msgfmt program +# these are searched first before $PATH, so set this if you have your own +# version that overrides the system version +# +# it reads variables from Makevars, one of the most important being DOMAIN +# it reads the languages to generate from LINGUAS +# +# it adds the following targets +# update-po +# update-gmo +# ${DOMAIN}-pot.update +# generate-${DOMAIN}-${lang}-po +# generate-${DOMAIN}-${lang}-gmo +# +# where ${DOMAIN} is the DOMAIN variable read from Makevars +# and ${lang} is each language mentioned in LINGUAS +# +# if you want update-gmo to be added to the "all" target, then define the +# variable GettextTranslate_ALL before including this file +# +# by default, the gmo files are built in the source directory. If you want +# them to be built in the binary directory, then define the variable +# GettextTranslate_GMO_BINARY + + + +# add the update-po and update-gmo targets, the actual files that need to +# depend on this will be added as we go + +if (DEFINED GettextTranslate_ALL) + set(_addToALL "ALL") +endif() + +add_custom_target(update-po) +add_custom_target(update-gmo ${_addToALL}) + +#look for all the programs +#xgettext, msginit, msgfilter, msgconv, msgmerge, msgfmt + +function(REQUIRE_BINARY binname varname) + if (defined ${${varname}-NOTFOUND}) + message(FATAL_ERROR "Could not find " binname) + endif() +endfunction() + +find_program(GettextTranslate_XGETTEXT_EXECUTABLE xgettext + HINTS ${GettextTranslate_XGETTEXT} ${GettextTranslate_BINARIES} +) +REQUIRE_BINARY(xgettext GettextTranslate_XGETTEXT_EXECUTABLE) + +find_program(GettextTranslate_MSGINIT_EXECUTABLE msginit + HINTS ${GettextTranslate_MSGINIT} ${GettextTranslate_BINARIES} +) +REQUIRE_BINARY(msginit GettextTranslate_MSGINIT_EXECUTABLE) + +find_program(GettextTranslate_MSGFILTER_EXECUTABLE msgfilter + HINTS ${GettextTranslate_MSGFILTER} ${GettextTranslate_BINARIES} +) +REQUIRE_BINARY(msgfilter GettextTranslate_MSGFILTER_EXECUTABLE) + +find_program(GettextTranslate_MSGCONV_EXECUTABLE msgconv + HINTS ${GettextTranslate_MSGCONV} ${GettextTranslate_BINARIES} +) +REQUIRE_BINARY(msgconv GettextTranslate_MSGCONV_EXECUTABLE) + +find_program(GettextTranslate_MSGMERGE_EXECUTABLE msgmerge + HINTS ${GettextTranslate_MSGMERGE} ${GettextTranslate_BINARIES} +) +REQUIRE_BINARY(msgmerge GettextTranslate_MSGMERGE_EXECUTABLE) + +find_program(GettextTranslate_MSGFMT_EXECUTABLE msgfmt + HINTS ${GettextTranslate_MSGFMT} ${GettextTranslate_BINARIES} +) +REQUIRE_BINARY(msgfmt GettextTranslate_MSGFMT_EXECUTABLE) + +mark_as_advanced( + GettextTranslate_MSGCONV_EXECUTABLE + GettextTranslate_MSGFILTER_EXECUTABLE + GettextTranslate_MSGFMT_EXECUTABLE + GettextTranslate_MSGINIT_EXECUTABLE + GettextTranslate_MSGMERGE_EXECUTABLE + GettextTranslate_XGETTEXT_EXECUTABLE +) + +macro(GettextTranslate) + + if(GettextTranslate_GMO_BINARY) + set (GMO_BUILD_DIR ${CMAKE_CURRENT_BINARY_DIR}) + else() + set (GMO_BUILD_DIR ${CMAKE_CURRENT_SOURCE_DIR}) + endif() + + if (NOT EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/POTFILES.in) + message(FATAL_ERROR "There is no POTFILES.in in + ${CMAKE_CURRENT_SOURCE_DIR}") + endif() + + if (NOT EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/Makevars) + message(FATAL_ERROR "There is no Makevars in ${CMAKE_CURRENT_SOURCE_DIR}") + endif() + + file(STRINGS ${CMAKE_CURRENT_SOURCE_DIR}/Makevars makevars + REGEX "^[^=]+=(.*)$" + ) + + foreach(makevar ${makevars}) + string(REGEX REPLACE "^([^= ]+) =[ ]?(.*)$" "\\1" MAKEVAR_KEY ${makevar}) + string(REGEX REPLACE "^([^= ]+) =[ ]?(.*)$" "\\2" + MAKEVAR_${MAKEVAR_KEY} ${makevar}) + endforeach() + + configure_file(${CMAKE_CURRENT_SOURCE_DIR}/POTFILES.in + ${CMAKE_CURRENT_BINARY_DIR}/POTFILES + COPYONLY + ) + + configure_file(${CMAKE_CURRENT_SOURCE_DIR}/LINGUAS + ${CMAKE_CURRENT_BINARY_DIR}/LINGUAS + COPYONLY + ) + + #set the directory to not clean + #set_property(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + # PROPERTY CLEAN_NO_CUSTOM true) + + file(STRINGS ${CMAKE_CURRENT_SOURCE_DIR}/POTFILES.in potfiles + REGEX "^[^#].*" + ) + + foreach(potfile ${potfiles}) + list(APPEND source_translatable + ${CMAKE_CURRENT_SOURCE_DIR}/${MAKEVAR_top_builddir}/${potfile}) + endforeach() + + set(TEMPLATE_FILE ${MAKEVAR_DOMAIN}.pot) + set(TEMPLATE_FILE_ABS ${CMAKE_CURRENT_SOURCE_DIR}/${TEMPLATE_FILE}) + string(REGEX MATCHALL "[^ ]+" XGETTEXT_OPTS ${MAKEVAR_XGETTEXT_OPTIONS}) + #add_custom_target(${MAKEVAR_DOMAIN}.pot-update DEPENDS + # ${TEMPLATE_FILE_ABS} + #) + + add_custom_target(${MAKEVAR_DOMAIN}.pot-update + COMMAND ${GettextTranslate_XGETTEXT_EXECUTABLE} ${XGETTEXT_OPTS} + -o ${TEMPLATE_FILE_ABS} + --default-domain=${MAKEVAR_DOMAIN} + --add-comments=TRANSLATORS: + --copyright-holder=${MAKEVAR_COPYRIGHT_HOLDER} + --msgid-bugs-address="${MAKEVAR_MSGID_BUGS_ADDRESS}" + --directory=${MAKEVAR_top_builddir} + --files-from=${CMAKE_CURRENT_BINARY_DIR}/POTFILES + --package-version=${VERSION} + --package-name=${CMAKE_PROJECT_NAME} + DEPENDS ${source_translatable} + ${CMAKE_CURRENT_SOURCE_DIR}/POTFILES.in + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + ) + + #add_custom_command(OUTPUT ${TEMPLATE_FILE_ABS} + # COMMAND ${GettextTranslate_XGETTEXT_EXECUTABLE} ${XGETTEXT_OPTS} + # -o ${TEMPLATE_FILE_ABS} + # --default-domain=${MAKEVAR_DOMAIN} + # --add-comments=TRANSLATORS: + # --copyright-holder=${MAKEVAR_COPYRIGHT_HOLDER} + # --msgid-bugs-address="${MAKEVAR_MSGID_BUGS_ADDRESS}" + # --directory=${MAKEVAR_top_builddir} + # --files-from=${CMAKE_CURRENT_BINARY_DIR}/POTFILES + # --package-version=${VERSION} + # --package-name=${CMAKE_PROJECT_NAME} + # DEPENDS ${source_translatable} + # ${CMAKE_CURRENT_SOURCE_DIR}/POTFILES.in + # WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + #) + + #add_dependencies(update-po ${MAKEVAR_DOMAIN}.pot-update) + + file(STRINGS ${CMAKE_CURRENT_SOURCE_DIR}/LINGUAS LINGUAS + REGEX "^[^#].*") + string(REGEX MATCHALL "[^ ]+" languages ${LINGUAS}) + + foreach(lang ${languages}) + set(PO_FILE_NAME "${CMAKE_CURRENT_SOURCE_DIR}/${lang}.po") + set(GMO_FILE_NAME "${GMO_BUILD_DIR}/${lang}.gmo") + set(PO_TARGET "generate-${MAKEVAR_DOMAIN}-${lang}-po") + set(GMO_TARGET "generate-${MAKEVAR_DOMAIN}-${lang}-gmo") + list(APPEND po_files ${PO_TARGET}) + list(APPEND gmo_files ${GMO_TARGET}) + + if(${lang} MATCHES "en@(.*)quot") + + add_custom_command(OUTPUT ${lang}.insert-header + COMMAND + sed -e "'/^#/d'" -e 's/HEADER/${lang}.header/g' + ${CMAKE_CURRENT_SOURCE_DIR}/insert-header.sin > ${lang}.insert-header + ) + + #generate the en@quot files + add_custom_target(${PO_TARGET} + COMMAND + ${GettextTranslate_MSGINIT_EXECUTABLE} -i ${TEMPLATE_FILE_ABS} + --no-translator -l ${lang} + -o - 2>/dev/null + | sed -f ${CMAKE_CURRENT_BINARY_DIR}/${lang}.insert-header + | ${GettextTranslate_MSGCONV_EXECUTABLE} -t UTF-8 + | ${GettextTranslate_MSGFILTER_EXECUTABLE} sed -f + ${CMAKE_CURRENT_SOURCE_DIR}/`echo ${lang} + | sed -e 's/.*@//'`.sed 2>/dev/null > + ${PO_FILE_NAME} + DEPENDS ${lang}.insert-header ${TEMPLATE_FILE_ABS} + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + ) + + else() + + add_custom_target(${PO_TARGET} + COMMAND ${GettextTranslate_MSGMERGE_EXECUTABLE} --lang=${lang} + ${PO_FILE_NAME} ${TEMPLATE_FILE_ABS} + -o ${PO_FILE_NAME}.new + COMMAND mv ${PO_FILE_NAME}.new ${PO_FILE_NAME} + DEPENDS ${TEMPLATE_FILE_ABS} + ) + + endif() + + add_custom_target(${GMO_TARGET} + COMMAND ${GettextTranslate_MSGFMT_EXECUTABLE} -c --statistics --verbose + -o ${GMO_FILE_NAME} ${PO_FILE_NAME} + DEPENDS ${PO_TARGET} + ) + + add_dependencies(${PO_TARGET} ${MAKEVAR_DOMAIN}.pot-update) + + install(FILES ${GMO_FILE_NAME} DESTINATION + ${LOCALEDIR}/${lang}/LC_MESSAGES + RENAME ${MAKEVAR_DOMAIN}.mo + ) + + endforeach() + + add_dependencies(update-po ${po_files}) + add_dependencies(update-gmo ${gmo_files}) + +#string(REGEX MATCH "^[^=]+=(.*)$" parsed_variables ${makevars}) + +endmacro() diff --git a/.cmake/Modules/FindLibcsptr.cmake b/.cmake/Modules/FindLibcsptr.cmake new file mode 100644 index 0000000..cd5e52e --- /dev/null +++ b/.cmake/Modules/FindLibcsptr.cmake @@ -0,0 +1,31 @@ +# Copyright (C) 2015 Franklin "Snaipe" Mathieu. +# Redistribution and use of this file is allowed according to the terms of the MIT license. +# For details see the LICENSE file distributed with Criterion. + +# - Find libcsptr +# Find the native libcsptr headers and libraries. +# +# CSPTR_INCLUDE_DIRS - where to find smart_ptr.h, etc. +# CSPTR_LIBRARIES - List of libraries when using libcsptr. +# CSPTR_FOUND - True if libcsptr has been found. + +# Look for the header file. +FIND_PATH(CSPTR_INCLUDE_DIR csptr/smart_ptr.h PATH_SUFFIXES csptr) + +# Look for the library. +FIND_LIBRARY(CSPTR_LIBRARY NAMES csptr) + +# Handle the QUIETLY and REQUIRED arguments and set CSPTR_FOUND to TRUE if all listed variables are TRUE. +INCLUDE(FindPackageHandleStandardArgs) +FIND_PACKAGE_HANDLE_STANDARD_ARGS(CSPTR DEFAULT_MSG CSPTR_LIBRARY CSPTR_INCLUDE_DIR) + +# Copy the results to the output variables. +IF(CSPTR_FOUND) + SET(CSPTR_LIBRARIES ${CSPTR_LIBRARY}) + SET(CSPTR_INCLUDE_DIRS ${CSPTR_INCLUDE_DIR}) +ELSE(CSPTR_FOUND) + SET(CSPTR_LIBRARIES) + SET(CSPTR_INCLUDE_DIRS) +ENDIF(CSPTR_FOUND) + +MARK_AS_ADVANCED(CSPTR_INCLUDE_DIRS CSPTR_LIBRARIES) diff --git a/.cmake/Modules/FindPCRE.cmake b/.cmake/Modules/FindPCRE.cmake new file mode 100644 index 0000000..dbbd60a --- /dev/null +++ b/.cmake/Modules/FindPCRE.cmake @@ -0,0 +1,37 @@ +# Copyright (C) 2007-2009 LuaDist. +# Created by Peter Kapec +# Redistribution and use of this file is allowed according to the terms of the MIT license. +# For details see the COPYRIGHT file distributed with LuaDist. +# Note: +# Searching headers and libraries is very simple and is NOT as powerful as scripts +# distributed with CMake, because LuaDist defines directories to search for. +# Everyone is encouraged to contact the author with improvements. Maybe this file +# becomes part of CMake distribution sometimes. + +# - Find pcre +# Find the native PCRE headers and libraries. +# +# PCRE_INCLUDE_DIRS - where to find pcre.h, etc. +# PCRE_LIBRARIES - List of libraries when using pcre. +# PCRE_FOUND - True if pcre found. + +# Look for the header file. +FIND_PATH(PCRE_INCLUDE_DIR NAMES pcre.h) + +# Look for the library. +FIND_LIBRARY(PCRE_LIBRARY NAMES pcre) + +# Handle the QUIETLY and REQUIRED arguments and set PCRE_FOUND to TRUE if all listed variables are TRUE. +INCLUDE(FindPackageHandleStandardArgs) +FIND_PACKAGE_HANDLE_STANDARD_ARGS(PCRE DEFAULT_MSG PCRE_LIBRARY PCRE_INCLUDE_DIR) + +# Copy the results to the output variables. +IF(PCRE_FOUND) + SET(PCRE_LIBRARIES ${PCRE_LIBRARY}) + SET(PCRE_INCLUDE_DIRS ${PCRE_INCLUDE_DIR}) +ELSE(PCRE_FOUND) + SET(PCRE_LIBRARIES) + SET(PCRE_INCLUDE_DIRS) +ENDIF(PCRE_FOUND) + +MARK_AS_ADVANCED(PCRE_INCLUDE_DIRS PCRE_LIBRARIES) diff --git a/.cmake/Modules/uninstall.cmake b/.cmake/Modules/uninstall.cmake new file mode 100644 index 0000000..e5ed88e --- /dev/null +++ b/.cmake/Modules/uninstall.cmake @@ -0,0 +1,23 @@ +set(MANIFEST "${CMAKE_CURRENT_BINARY_DIR}/install_manifest.txt") + +if(NOT EXISTS ${MANIFEST}) +message(FATAL_ERROR "Cannot find install manifest: '${MANIFEST}'") +endif() + +file(STRINGS ${MANIFEST} files) +foreach(file ${files}) +if(EXISTS ${file}) +message(STATUS "Removing file: '${file}'") + +exec_program( +${CMAKE_COMMAND} ARGS "-E remove ${file}" +OUTPUT_VARIABLE stdout +RETURN_VALUE result +) +if(NOT "${result}" STREQUAL 0) +message(FATAL_ERROR "Failed to remove file: '${file}'.") +endif() +else() +MESSAGE(STATUS "File '${file}' does not exist.") +endif() +endforeach(file) diff --git a/.gitignore b/.gitignore index f9e0c45..c73d0b5 100644 --- a/.gitignore +++ b/.gitignore @@ -14,9 +14,8 @@ !HEADER !ChangeLog -!Makefile.am -!configure.ac -!autogen.sh +!CMakeLists.txt +!.cmake/* src/config.h diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..730257c --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,90 @@ +cmake_minimum_required(VERSION 3.2.2) +cmake_policy(SET CMP0048 NEW) + +project(Criterion VERSION 1.2.2) + +set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/.cmake/Modules/") + +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -Werror -g -std=gnu11") +set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,-no-undefined") + +include(CheckLibraryExists) +CHECK_LIBRARY_EXISTS(rt clock_gettime "time.h" HAVE_CLOCK_GETTIME) + +find_package(PCRE) +find_package(Gettext REQUIRED) +find_package(Libcsptr) + +configure_file( + "${CMAKE_SOURCE_DIR}/src/config.h.in" + "${CMAKE_SOURCE_DIR}/src/config.h" +) + +set(SOURCE_FILES + src/abort.c + src/abort.h + src/event.c + src/event.h + src/report.c + src/report.h + src/runner.c + src/runner.h + src/process.c + src/process.h + src/stats.c + src/stats.h + src/log/logging.c + src/log/tap.c + src/log/normal.c + src/options.c + src/timer.c + src/timer.h + src/i18n.c + src/i18n.h + src/ordered-set.c + src/posix-compat.c + src/extmatch.c + src/extmatch.h + src/main.c +) + +set(INTERFACE_FILES + include/criterion/assert.h + include/criterion/abort.h + include/criterion/common.h + include/criterion/criterion.h + include/criterion/event.h + include/criterion/hooks.h + include/criterion/logging.h + include/criterion/types.h + include/criterion/options.h + include/criterion/ordered-set.h + include/criterion/stats.h +) + +add_subdirectory(samples) +#add_subdirectory(po) + +include_directories(include src) +add_library(criterion SHARED ${SOURCE_FILES} ${INTERFACE_FILES}) + +link_directories(/usr/lib) + +target_link_libraries(criterion csptr) + +if (HAVE_CLOCK_GETTIME) + target_link_libraries(criterion rt) +endif() + +if (PCRE_FOUND) + target_link_libraries(criterion pcre) +endif() + +install(FILES ${INTERFACE_FILES} DESTINATION include/insight) +install(TARGETS criterion + LIBRARY DESTINATION lib +) + +add_custom_target(uninstall + "${CMAKE_COMMAND}" -P "${CMAKE_MODULE_PATH}/uninstall.cmake" +) diff --git a/Makefile.am b/Makefile.am deleted file mode 100644 index 02b5f23..0000000 --- a/Makefile.am +++ /dev/null @@ -1,75 +0,0 @@ -ACLOCAL_AMFLAGS = -I m4 -AM_CPPFLAGS = -DLOCALEDIR='"$(localedir)"' -SUBDIRS = po samples - -lib_LTLIBRARIES = libcriterion.la - -WARNINGS = -Wall -Wextra \ - -Wno-unused-result - -libcriterion_la_CFLAGS = \ - $(WARNINGS) \ - -std=gnu11 \ - -I$(top_srcdir)/src/ \ - -I$(top_srcdir)/include/ \ - $(COVERAGE_CFLAGS) - -libcriterion_la_LDFLAGS = $(COVERAGE_LDFLAGS) -no-undefined -version-info 1:0:0 -libcriterion_la_LIBADD = -lpcre - -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 \ - include/criterion/hooks.h \ - include/criterion/logging.h \ - include/criterion/types.h \ - include/criterion/options.h \ - include/criterion/ordered-set.h \ - include/criterion/stats.h - -libcriterion_la_SOURCES = \ - src/abort.c \ - src/abort.h \ - src/event.c \ - src/event.h \ - src/report.c \ - src/report.h \ - src/runner.c \ - src/runner.h \ - src/process.c \ - src/process.h \ - src/stats.c \ - src/stats.h \ - src/log/logging.c \ - src/log/tap.c \ - src/log/normal.c \ - src/options.c \ - src/timer.c \ - src/timer.h \ - src/i18n.c \ - src/i18n.h \ - src/ordered-set.c \ - src/posix-compat.c \ - src/extmatch.c \ - src/extmatch.h \ - src/main.c - -TARGET = $(PACKAGE)-$(VERSION) - -package: all - rm -Rf $(TARGET) - mkdir -p $(TARGET) - cp -Rf .libs $(TARGET)/lib/ - rm -f $(TARGET)/lib/libcriterion.la - cp -f libcriterion.la $(TARGET)/lib - cp -Rf include $(TARGET) - tar -cvjf $(TARGET).tar.bz2 $(TARGET) - -clean-local: - rm -Rf $(TARGET) $(TARGET).tar.bz2 diff --git a/autogen.sh b/autogen.sh deleted file mode 100755 index 886e91f..0000000 --- a/autogen.sh +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/sh -git submodule update --init --recursive -autopoint -autoreconf -i diff --git a/configure.ac b/configure.ac deleted file mode 100644 index 4d9b7a0..0000000 --- a/configure.ac +++ /dev/null @@ -1,50 +0,0 @@ -AC_PREREQ([2.60]) - -AC_INIT([criterion], [1.2.1], [], [criterion], [franklinmathieu@gmail.com]) -AC_CONFIG_SRCDIR([src/runner.c]) - -LT_PREREQ([2.2.4]) -AC_CANONICAL_SYSTEM - -AM_INIT_AUTOMAKE([dist-bzip2 no-dist-gzip foreign subdir-objects parallel-tests color-tests]) -LT_INIT([disable-static]) -AC_CONFIG_MACRO_DIR([m4]) - -AC_PROG_CC -AM_PROG_CC_C_O - -AC_PROG_LIBTOOL -AC_PROG_INSTALL -AC_PROG_LN_S - -AC_PROG_MAKE_SET -AC_SUBST([LIBTOOL_DEPS]) - -AC_CHECK_LIB([csptr], [smalloc], [], [AC_MSG_ERROR([Could not find libcsptr dependency. \ - Please go to https://github.com/Snaipe/c-smart-pointers.git \ - and follow the installation instructions.])]) - -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"]) - -AC_CHECK_LIB([pcre], [pcre_compile], [AC_DEFINE([HAVE_PCRE], [1], [Define to 1 if you have the `pcre` library (-lpcre)])]) - -AM_GNU_GETTEXT([external]) -AM_GNU_GETTEXT_VERSION([0.18]) - -AC_ARG_ENABLE([gcov], - [AS_HELP_STRING([--enable-gcov], - [Compile the project with converage enabled])], - [COVERAGE_CFLAGS="-O0 -fprofile-arcs -ftest-coverage" - COVERAGE_LDFLAGS="-lgcov" - AC_SUBST([COVERAGE_CFLAGS]) - AC_SUBST([COVERAGE_LDFLAGS]) - ], - []) - -AC_CONFIG_HEADERS([src/config.h]) -AC_CONFIG_FILES([Makefile samples/Makefile po/Makefile.in]) - -AC_OUTPUT diff --git a/samples/CMakeLists.txt b/samples/CMakeLists.txt new file mode 100644 index 0000000..a0ccb37 --- /dev/null +++ b/samples/CMakeLists.txt @@ -0,0 +1,24 @@ +cmake_minimum_required(VERSION 3.1) +project(criterion_samples) + +set(CMAKE_C_FLAGS "-std=c99 -Wall -Wextra -pedantic") + +include_directories(../include) + +set(SAMPLES + signal + report + suites + fixtures + asserts + more-suites + long-messages + description + other-crashes + simple +) + +foreach(sample ${SAMPLES}) + add_executable(${sample} ${sample}.c) + target_link_libraries(${sample} criterion) +endforeach() From 5f3842c822774401419406f8ad6b8759ae41c09a Mon Sep 17 00:00:00 2001 From: Snaipe Date: Tue, 28 Jul 2015 19:05:38 +0200 Subject: [PATCH 17/78] Removed m4 folder --- m4/.keep | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 m4/.keep diff --git a/m4/.keep b/m4/.keep deleted file mode 100644 index e69de29..0000000 From e0d93f53c7506603d081dc48dbff5f57671fb64f Mon Sep 17 00:00:00 2001 From: Snaipe Date: Tue, 28 Jul 2015 19:11:28 +0200 Subject: [PATCH 18/78] Added basic config.h.in --- .gitignore | 1 + src/config.h.in | 6 ++++++ 2 files changed, 7 insertions(+) create mode 100644 src/config.h.in diff --git a/.gitignore b/.gitignore index c73d0b5..6050bee 100644 --- a/.gitignore +++ b/.gitignore @@ -17,6 +17,7 @@ !CMakeLists.txt !.cmake/* +!src/config.h.in src/config.h *~ diff --git a/src/config.h.in b/src/config.h.in new file mode 100644 index 0000000..881c4b5 --- /dev/null +++ b/src/config.h.in @@ -0,0 +1,6 @@ +#ifndef CONFIG_H_IN_ +# define CONFIG_H_IN_ + +# define VERSION "${PACKAGE_VERSION}" + +#endif /* !CONFIG_H_IN_ */ From 1bc6bf59fef1a7a58a519feb471527c52ef7c767 Mon Sep 17 00:00:00 2001 From: Snaipe Date: Tue, 28 Jul 2015 22:44:28 +0200 Subject: [PATCH 19/78] Integrated gettext into the build system --- ...indGettext.cmake => GettextTranslate.cmake} | 0 CMakeLists.txt | 18 +++++++++++++++--- po/CMakeLists.txt | 1 + po/Makevars | 2 +- po/fr.po | 2 +- src/config.h.in | 6 +++++- 6 files changed, 23 insertions(+), 6 deletions(-) rename .cmake/Modules/{FindGettext.cmake => GettextTranslate.cmake} (100%) create mode 100644 po/CMakeLists.txt diff --git a/.cmake/Modules/FindGettext.cmake b/.cmake/Modules/GettextTranslate.cmake similarity index 100% rename from .cmake/Modules/FindGettext.cmake rename to .cmake/Modules/GettextTranslate.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index 730257c..b16eb48 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,17 +2,30 @@ cmake_minimum_required(VERSION 3.2.2) cmake_policy(SET CMP0048 NEW) project(Criterion VERSION 1.2.2) +get_cmake_property(_variableNames VARIABLES) +foreach (_variableName ${_variableNames}) + message(STATUS "${_variableName}=${${_variableName}}") +endforeach() +set(LOCALEDIR ${CMAKE_INSTALL_PREFIX}/share/locale) +set(GettextTranslate_ALL) +set(GettextTranslate_GMO_BINARY) set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/.cmake/Modules/") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -Werror -g -std=gnu11") set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,-no-undefined") +find_package(Gettext) +if (GETTEXT_FOUND) + include(GettextTranslate) + add_subdirectory(po) + set(ENABLE_NLS 1) +endif () + include(CheckLibraryExists) CHECK_LIBRARY_EXISTS(rt clock_gettime "time.h" HAVE_CLOCK_GETTIME) find_package(PCRE) -find_package(Gettext REQUIRED) find_package(Libcsptr) configure_file( @@ -63,7 +76,6 @@ set(INTERFACE_FILES ) add_subdirectory(samples) -#add_subdirectory(po) include_directories(include src) add_library(criterion SHARED ${SOURCE_FILES} ${INTERFACE_FILES}) @@ -80,7 +92,7 @@ if (PCRE_FOUND) target_link_libraries(criterion pcre) endif() -install(FILES ${INTERFACE_FILES} DESTINATION include/insight) +install(FILES ${INTERFACE_FILES} DESTINATION include/criterion) install(TARGETS criterion LIBRARY DESTINATION lib ) diff --git a/po/CMakeLists.txt b/po/CMakeLists.txt new file mode 100644 index 0000000..892654a --- /dev/null +++ b/po/CMakeLists.txt @@ -0,0 +1 @@ +GettextTranslate() diff --git a/po/Makevars b/po/Makevars index 70daf30..036417c 100644 --- a/po/Makevars +++ b/po/Makevars @@ -1,7 +1,7 @@ # Makefile variables for PO directory in any package using GNU gettext. # Usually the message domain is the same as the package name. -DOMAIN = $(PACKAGE) +DOMAIN = Criterion # These two variables depend on the location of this directory. subdir = po diff --git a/po/fr.po b/po/fr.po index f9627f7..7727e40 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-06-30 12:07+0200\n" +"POT-Creation-Date: 2015-07-28 22:17+0200\n" "PO-Revision-Date: 2015-04-03 17:58+0200\n" "Last-Translator: \n" "Language-Team: French\n" diff --git a/src/config.h.in b/src/config.h.in index 881c4b5..194430a 100644 --- a/src/config.h.in +++ b/src/config.h.in @@ -1,6 +1,10 @@ #ifndef CONFIG_H_IN_ # define CONFIG_H_IN_ -# define VERSION "${PACKAGE_VERSION}" +#cmakedefine ENABLE_NLS @ENABLE_NLS@ + +# define LOCALEDIR "${LOCALEDIR}" +# define PACKAGE "${PROJECT_NAME}" +# define VERSION "${PROJECT_VERSION}" #endif /* !CONFIG_H_IN_ */ From 30515e5bcca3f758c0727296a06d766cc3f5bb42 Mon Sep 17 00:00:00 2001 From: Snaipe Date: Tue, 28 Jul 2015 22:45:18 +0200 Subject: [PATCH 20/78] Excluded out-of-source build folder from gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 6050bee..48d1edb 100644 --- a/.gitignore +++ b/.gitignore @@ -20,5 +20,6 @@ !src/config.h.in src/config.h +build *~ *.swp From b20c42059b0fe914e4face4ef3c438fa6834ad46 Mon Sep 17 00:00:00 2001 From: Snaipe Date: Wed, 29 Jul 2015 11:58:51 +0200 Subject: [PATCH 21/78] Added tests again in the build system --- CMakeLists.txt | 6 ++---- samples/CMakeLists.txt | 18 ++++++++++++++++++ 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b16eb48..7e2d919 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,10 +2,6 @@ cmake_minimum_required(VERSION 3.2.2) cmake_policy(SET CMP0048 NEW) project(Criterion VERSION 1.2.2) -get_cmake_property(_variableNames VARIABLES) -foreach (_variableName ${_variableNames}) - message(STATUS "${_variableName}=${${_variableName}}") -endforeach() set(LOCALEDIR ${CMAKE_INSTALL_PREFIX}/share/locale) set(GettextTranslate_ALL) @@ -75,6 +71,8 @@ set(INTERFACE_FILES include/criterion/stats.h ) +enable_testing() + add_subdirectory(samples) include_directories(include src) diff --git a/samples/CMakeLists.txt b/samples/CMakeLists.txt index a0ccb37..42aee2d 100644 --- a/samples/CMakeLists.txt +++ b/samples/CMakeLists.txt @@ -18,7 +18,25 @@ set(SAMPLES simple ) +set(SCRIPTS + tap_test + early_exit + verbose + list + pattern + fail_fast + help +) + foreach(sample ${SAMPLES}) add_executable(${sample} ${sample}.c) target_link_libraries(${sample} criterion) + add_test(${sample} ${sample}) + set_property(TEST ${sample} PROPERTY + ENVIRONMENT "CRITERION_ALWAYS_SUCCEED=1" + ) +endforeach() + +foreach(script ${SCRIPTS}) + add_test(${script} ${CMAKE_CURRENT_LIST_DIR}/tests/${script}.sh) endforeach() From b66afed4cc10eae879ccc9fe93f9d4c1ef987427 Mon Sep 17 00:00:00 2001 From: Snaipe Date: Wed, 29 Jul 2015 12:26:13 +0200 Subject: [PATCH 22/78] Fixed travis build --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 3b19d71..20a0717 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,12 +4,12 @@ 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 gettext autopoint + - sudo apt-get -qq install -y check gcc-4.9 gettext cmake - sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-4.9 90 - sudo pip install cpp-coveralls - .ci/install-libcsptr.sh --prefix=/usr script: - - ./autogen.sh && ./configure --enable-gcov CFLAGS="-g -O0" && make && make -C samples check + - mkdir -p build && cd $_ && cmake .. && make && make -C samples test after_success: - coveralls --gcov gcov-4.9 --exclude samples --exclude dependencies --gcov-options '\-lp' -b . after_failure: From 8acb2f5dc2edc645315d613788a0a4c12f36f1e8 Mon Sep 17 00:00:00 2001 From: Snaipe Date: Wed, 29 Jul 2015 13:32:49 +0200 Subject: [PATCH 23/78] Provided non-positional format strings when gettext is not available (hint: windows) --- src/log/normal.c | 78 ++++++++++++++++++++++++++++++++++-------------- 1 file changed, 55 insertions(+), 23 deletions(-) diff --git a/src/log/normal.c b/src/log/normal.c index 8b0f2cc..1d6609e 100644 --- a/src/log/normal.c +++ b/src/log/normal.c @@ -34,23 +34,63 @@ #include "config.h" #include "i18n.h" +typedef const char *const msg_t; + +static msg_t msg_pre_all = "Criterion v%s\n"; +static msg_t msg_desc = " %s\n"; + +#if ENABLE_NLS +static msg_t msg_pre_init = "%1$s::%2$s\n"; +static msg_t msg_post_test_timed = "%1$s::%2$s: (%3$3.2fs)\n"; +static msg_t msg_post_test = "%1$s::%2$s\n"; +static msg_t msg_post_suite_test = "%1$s::%2$s: Test is disabled\n"; +static msg_t msg_post_suite_suite = "%1$s::%2$s: Suite is disabled\n"; +static msg_t msg_assert_fail = "%1$s%2$s%3$s:%4$s%5$d%6$s: Assertion failed: %7$s\n"; +static msg_t msg_test_crash_line = "%1$s%2$s%3$s:%4$s%5$u%6$s: Unexpected signal caught below this line!\n"; +static msg_t msg_test_crash = "%1$s::%2$s: CRASH!\n"; +static msg_t msg_test_other_crash = "%1$sWarning! The test `%2$s::%3$s` crashed during its setup or teardown.%4$s\n"; +static msg_t msg_pre_suite = "Running %1$s%2$lu%3$s test from %4$s%5$s%6$s:\n"; +static msg_t msg_pre_suite_pl = "Running %1$s%2$lu%3$s tests from %4$s%5$s%6$s:\n"; +static msg_t msg_post_all = "%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"; +#else +static msg_t msg_pre_init = "%s::%s\n"; +static msg_t msg_post_test_timed = "%s::%s: (%3.2fs)\n"; +static msg_t msg_post_test = "%s::%s\n"; +static msg_t msg_post_suite_test = "%s::%s: Test is disabled\n"; +static msg_t msg_post_suite_suite = "%s::%s: Suite is disabled\n"; +static msg_t msg_assert_fail = "%s%s%s:%s%d%s: Assertion failed: %s\n"; +static msg_t msg_test_crash_line = "%s%s%s:%s%u%s: Unexpected signal caught below this line!\n"; +static msg_t msg_test_crash = "%s::%s: CRASH!\n"; +static msg_t msg_test_other_crash = "%sWarning! The test `%s::%s` crashed during its setup or teardown.%s\n"; +static msg_t msg_pre_suite = "Running %s%lu%s test from %s%s%s:\n"; +static msg_t msg_pre_suite_pl = "Running %s%lu%s tests from %s%s%s:\n"; +static msg_t msg_post_all = "%sSynthesis: Tested: %s%lu%s " + "| Passing: %s%lu%s " + "| Failing: %s%lu%s " + "| Crashing: %s%lu%s " + "%s\n"; +#endif + void normal_log_pre_all(UNUSED struct criterion_test_set *set) { - criterion_pinfo(CRITERION_PREFIX_DASHES, _("Criterion v%s\n"), VERSION); + criterion_pinfo(CRITERION_PREFIX_DASHES, _(msg_pre_all), VERSION); } void normal_log_pre_init(struct criterion_test *test) { - criterion_pinfo(CRITERION_PREFIX_RUN, _("%1$s::%2$s\n"), + criterion_pinfo(CRITERION_PREFIX_RUN, _(msg_pre_init), test->category, test->name); if (test->data->description) - criterion_pinfo(CRITERION_PREFIX_RUN, _(" %s\n"), + criterion_pinfo(CRITERION_PREFIX_RUN, _(msg_desc), 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() ? msg_post_test_timed : msg_post_test; const enum criterion_logging_level level = stats->failed ? CRITERION_IMPORTANT : CRITERION_INFO; @@ -73,15 +113,15 @@ 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)) { const char *format = ts->test->data->disabled - ? _("%1$s::%2$s: Test is disabled\n") - : _("%1$s::%2$s: Suite is disabled\n"); + ? _(msg_post_suite_test) + : _(msg_post_suite_suite); criterion_pinfo(CRITERION_PREFIX_SKIP, format, ts->test->category, ts->test->name); if (ts->test->data->description) - criterion_pinfo(CRITERION_PREFIX_DASHES, " %s\n", + criterion_pinfo(CRITERION_PREFIX_DASHES, msg_desc, ts->test->data->description); } } @@ -91,11 +131,7 @@ 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 " - "| Failing: %8$s%9$lu%10$s " - "| Crashing: %11$s%12$lu%13$s " - "%14$s\n"), + _(msg_post_all), FG_BOLD, FG_BLUE, (unsigned long) tested, FG_BOLD, FG_GREEN, (unsigned long) stats->tests_passed, FG_BOLD, @@ -112,40 +148,36 @@ void normal_log_assert(struct criterion_assert_stats *stats) { 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"), + _(msg_assert_fail), FG_BOLD, stats->file, RESET, FG_RED, stats->line, RESET, line); while ((line = strtok_r(NULL, "\n", &saveptr))) - criterion_pimportant(CRITERION_PREFIX_DASHES, _(" %s\n"), line); + criterion_pimportant(CRITERION_PREFIX_DASHES, _(msg_desc), line); free(dup); } } void normal_log_test_crash(struct criterion_test_stats *stats) { criterion_pimportant(CRITERION_PREFIX_DASHES, - _("%1$s%2$s%3$s:%4$s%5$u%6$s: " - "Unexpected signal caught below this line!\n"), + _(msg_test_crash_line), FG_BOLD, stats->file, RESET, FG_RED, stats->progress, RESET); - criterion_pimportant(CRITERION_PREFIX_FAIL, _("%1$s::%2$s: CRASH!\n"), + criterion_pimportant(CRITERION_PREFIX_FAIL, _(msg_test_crash), stats->test->category, stats->test->name); } void normal_log_other_crash(UNUSED struct criterion_test_stats *stats) { criterion_pimportant(CRITERION_PREFIX_DASHES, - _("%1$sWarning! The test `%2$s::%3$s` crashed during its " - "setup or teardown.%4$s\n"), + _(msg_test_other_crash), FG_BOLD, stats->test->category, stats->test->name, 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", - "Running %1$s%2$lu%3$s tests from %4$s%5$s%6$s:\n", - set->tests->size), + _s(msg_pre_suite, msg_pre_suite_pl, set->tests->size), FG_BLUE, (unsigned long) set->tests->size, RESET, FG_GOLD, set->suite.name, RESET); } From 1a86d27ccda2bbd06084ee04cfd968e2bd5b2c53 Mon Sep 17 00:00:00 2001 From: Snaipe Date: Wed, 29 Jul 2015 17:22:49 +0200 Subject: [PATCH 24/78] Fixed cmake version & switched travis config to use containers --- .ci/install-libcsptr.sh | 10 ++-------- .travis.yml | 24 +++++++++++++++++------- CMakeLists.txt | 2 +- samples/CMakeLists.txt | 1 - 4 files changed, 20 insertions(+), 17 deletions(-) diff --git a/.ci/install-libcsptr.sh b/.ci/install-libcsptr.sh index 2826ec7..0e98b2c 100755 --- a/.ci/install-libcsptr.sh +++ b/.ci/install-libcsptr.sh @@ -7,14 +7,8 @@ git clone --branch ${tag} --depth 1 ${repo} dependencies/libcsptr && ( cd dependencies/libcsptr && ./autogen.sh && - ./configure "$@" && + ./configure --prefix=$HOME && make && - { - if command -v sudo; then - sudo make install - else - make install - fi - } + make install ) rm -Rf dependencies diff --git a/.travis.yml b/.travis.yml index 20a0717..f8eb968 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,15 +1,25 @@ language: c compiler: - gcc +addons: + apt: + sources: + - ubuntu-toolchain-r-test + packages: + - check + - gcc-4.9 + - gettext + - cmake 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 gettext cmake - - sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-4.9 90 - - sudo pip install cpp-coveralls - - .ci/install-libcsptr.sh --prefix=/usr + - pip install --user cpp-coveralls + - .ci/install-libcsptr.sh + - export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$HOME/lib + - export LIBRARY_PATH=$LIBRARY_PATH:$HOME/lib script: - - mkdir -p build && cd $_ && cmake .. && make && make -C samples test + - mkdir -p build && cd $_ + - cmake .. + - make + - make -C samples test after_success: - coveralls --gcov gcov-4.9 --exclude samples --exclude dependencies --gcov-options '\-lp' -b . after_failure: diff --git a/CMakeLists.txt b/CMakeLists.txt index 7e2d919..d4aca14 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.2.2) +cmake_minimum_required(VERSION 2.8) cmake_policy(SET CMP0048 NEW) project(Criterion VERSION 1.2.2) diff --git a/samples/CMakeLists.txt b/samples/CMakeLists.txt index 42aee2d..ead99be 100644 --- a/samples/CMakeLists.txt +++ b/samples/CMakeLists.txt @@ -1,4 +1,3 @@ -cmake_minimum_required(VERSION 3.1) project(criterion_samples) set(CMAKE_C_FLAGS "-std=c99 -Wall -Wextra -pedantic") From d4b960fe618713e35c001e92a457616f2d07a63b Mon Sep 17 00:00:00 2001 From: Snaipe Date: Wed, 29 Jul 2015 17:53:58 +0200 Subject: [PATCH 25/78] Made the build system cmake 2.8 compliant --- .travis.yml | 1 + CMakeLists.txt | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index f8eb968..4ccf67e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,7 @@ language: c compiler: - gcc +sudo: false addons: apt: sources: diff --git a/CMakeLists.txt b/CMakeLists.txt index d4aca14..46292b0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,8 +1,8 @@ cmake_minimum_required(VERSION 2.8) -cmake_policy(SET CMP0048 NEW) -project(Criterion VERSION 1.2.2) +project(Criterion C) +set(PROJECT_VERSION "1.2.2") set(LOCALEDIR ${CMAKE_INSTALL_PREFIX}/share/locale) set(GettextTranslate_ALL) set(GettextTranslate_GMO_BINARY) From 2965f85b4a712a595db72897e8fc5adc7a39cf7a Mon Sep 17 00:00:00 2001 From: Snaipe Date: Wed, 29 Jul 2015 18:22:47 +0200 Subject: [PATCH 26/78] Updated travis build to use GCC5 --- .travis.yml | 13 +++++-------- CMakeLists.txt | 11 +++++------ 2 files changed, 10 insertions(+), 14 deletions(-) diff --git a/.travis.yml b/.travis.yml index 4ccf67e..07f6a1b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,26 +1,23 @@ language: c compiler: - - gcc + - gcc-5 sudo: false addons: apt: sources: - ubuntu-toolchain-r-test - packages: + packages: - check - - gcc-4.9 + - gcc-5 - gettext - cmake before_install: - pip install --user cpp-coveralls - .ci/install-libcsptr.sh - export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$HOME/lib - - export LIBRARY_PATH=$LIBRARY_PATH:$HOME/lib + - export CFLAGS="-g -O0" script: - - mkdir -p build && cd $_ - - cmake .. - - make - - make -C samples test + - mkdir -p build && cd $_ && cmake -DCMAKE_PREFIX_PATH=$HOME .. && make && make -C samples test after_success: - coveralls --gcov gcov-4.9 --exclude samples --exclude dependencies --gcov-options '\-lp' -b . after_failure: diff --git a/CMakeLists.txt b/CMakeLists.txt index 46292b0..7721909 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -22,7 +22,7 @@ include(CheckLibraryExists) CHECK_LIBRARY_EXISTS(rt clock_gettime "time.h" HAVE_CLOCK_GETTIME) find_package(PCRE) -find_package(Libcsptr) +find_package(Libcsptr REQUIRED) configure_file( "${CMAKE_SOURCE_DIR}/src/config.h.in" @@ -75,19 +75,18 @@ enable_testing() add_subdirectory(samples) -include_directories(include src) +include_directories(include src ${CSPTR_INCLUDE_DIRS}) + add_library(criterion SHARED ${SOURCE_FILES} ${INTERFACE_FILES}) -link_directories(/usr/lib) - -target_link_libraries(criterion csptr) +target_link_libraries(criterion ${CSPTR_LIBRARIES}) if (HAVE_CLOCK_GETTIME) target_link_libraries(criterion rt) endif() if (PCRE_FOUND) - target_link_libraries(criterion pcre) + target_link_libraries(criterion ${PCRE_LIBRARIES}) endif() install(FILES ${INTERFACE_FILES} DESTINATION include/criterion) From d435c34d364251cabc5b4319b97f2a952d47767a Mon Sep 17 00:00:00 2001 From: Snaipe Date: Thu, 30 Jul 2015 12:20:40 +0200 Subject: [PATCH 27/78] Fixed coverage on travis builds --- .travis.yml | 4 ++-- CMakeLists.txt | 6 ++++++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 07f6a1b..69cc33d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -17,8 +17,8 @@ before_install: - export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$HOME/lib - export CFLAGS="-g -O0" script: - - mkdir -p build && cd $_ && cmake -DCMAKE_PREFIX_PATH=$HOME .. && make && make -C samples test + - mkdir -p build && cd $_ && cmake -Dcoverage=on -DCMAKE_PREFIX_PATH=$HOME .. && make && make -C samples test after_success: - - coveralls --gcov gcov-4.9 --exclude samples --exclude dependencies --gcov-options '\-lp' -b . + - coveralls --gcov gcov-5 --exclude samples --exclude dependencies --gcov-options '\-lp' -b . after_failure: - cat $(find samples -iname '*.log') /dev/null diff --git a/CMakeLists.txt b/CMakeLists.txt index 7721909..2404e31 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -71,6 +71,12 @@ set(INTERFACE_FILES include/criterion/stats.h ) +option(coverage "coverage" OFF) +if (coverage) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fprofile-arcs -ftest-coverage") + set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -fprofile-arcs -ftest-coverage") +endif() + enable_testing() add_subdirectory(samples) From 94eb430dd051a6f46343f063dd0e03cb446b0f36 Mon Sep 17 00:00:00 2001 From: Snaipe Date: Thu, 30 Jul 2015 13:09:18 +0200 Subject: [PATCH 28/78] switched coveralls upload job to a cmake solution --- .cmake/Modules/Coveralls.cmake | 128 ++++++ .cmake/Modules/CoverallsClear.cmake | 31 ++ .cmake/Modules/CoverallsGenerateGcov.cmake | 438 +++++++++++++++++++++ .travis.yml | 8 +- CMakeLists.txt | 40 +- 5 files changed, 628 insertions(+), 17 deletions(-) create mode 100644 .cmake/Modules/Coveralls.cmake create mode 100644 .cmake/Modules/CoverallsClear.cmake create mode 100644 .cmake/Modules/CoverallsGenerateGcov.cmake diff --git a/.cmake/Modules/Coveralls.cmake b/.cmake/Modules/Coveralls.cmake new file mode 100644 index 0000000..4250397 --- /dev/null +++ b/.cmake/Modules/Coveralls.cmake @@ -0,0 +1,128 @@ +# +# The MIT License (MIT) +# +# 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. +# +# Copyright (C) 2014 Joakim Söderberg +# + +set(_CMAKE_SCRIPT_PATH ${CMAKE_CURRENT_LIST_DIR}) # must be outside coveralls_setup() to get correct path + +# +# Param _COVERAGE_SRCS A list of source files that coverage should be collected for. +# Param _COVERALLS_UPLOAD Upload the result to coveralls? +# + +function(coveralls_setup _COVERAGE_SRCS _COVERALLS_UPLOAD) + + if (ARGC GREATER 2) + set(_CMAKE_SCRIPT_PATH ${ARGN}) + message(STATUS "Coveralls: Using alternate CMake script dir: ${_CMAKE_SCRIPT_PATH}") + endif() + + if (NOT EXISTS "${_CMAKE_SCRIPT_PATH}/CoverallsClear.cmake") + message(FATAL_ERROR "Coveralls: Missing ${_CMAKE_SCRIPT_PATH}/CoverallsClear.cmake") + endif() + + if (NOT EXISTS "${_CMAKE_SCRIPT_PATH}/CoverallsGenerateGcov.cmake") + message(FATAL_ERROR "Coveralls: Missing ${_CMAKE_SCRIPT_PATH}/CoverallsGenerateGcov.cmake") + endif() + + # When passing a CMake list to an external process, the list + # will be converted from the format "1;2;3" to "1 2 3". + # This means the script we're calling won't see it as a list + # of sources, but rather just one long path. We remedy this + # by replacing ";" with "*" and then reversing that in the script + # that we're calling. + # http://cmake.3232098.n2.nabble.com/Passing-a-CMake-list-quot-as-is-quot-to-a-custom-target-td6505681.html + set(COVERAGE_SRCS_TMP ${_COVERAGE_SRCS}) + set(COVERAGE_SRCS "") + foreach (COVERAGE_SRC ${COVERAGE_SRCS_TMP}) + set(COVERAGE_SRCS "${COVERAGE_SRCS}*${COVERAGE_SRC}") + endforeach() + + #message("Coverage sources: ${COVERAGE_SRCS}") + set(COVERALLS_FILE ${PROJECT_BINARY_DIR}/coveralls.json) + + add_custom_target(coveralls_generate + + # Zero the coverage counters. + COMMAND ${CMAKE_COMMAND} -DPROJECT_BINARY_DIR="${PROJECT_BINARY_DIR}" -P "${_CMAKE_SCRIPT_PATH}/CoverallsClear.cmake" + + # Run regress tests. + COMMAND ${CMAKE_CTEST_COMMAND} --output-on-failure + + # Generate Gcov and translate it into coveralls JSON. + # We do this by executing an external CMake script. + # (We don't want this to run at CMake generation time, but after compilation and everything has run). + COMMAND ${CMAKE_COMMAND} + -DCOVERAGE_SRCS="${COVERAGE_SRCS}" # TODO: This is passed like: "a b c", not "a;b;c" + -DCOVERALLS_OUTPUT_FILE="${COVERALLS_FILE}" + -DCOV_PATH="${PROJECT_BINARY_DIR}" + -DPROJECT_ROOT="${PROJECT_SOURCE_DIR}" + -P "${_CMAKE_SCRIPT_PATH}/CoverallsGenerateGcov.cmake" + + WORKING_DIRECTORY ${PROJECT_BINARY_DIR} + COMMENT "Generating coveralls output..." + ) + + if (_COVERALLS_UPLOAD) + message("COVERALLS UPLOAD: ON") + + find_program(CURL_EXECUTABLE curl) + + if (NOT CURL_EXECUTABLE) + message(FATAL_ERROR "Coveralls: curl not found! Aborting") + endif() + + add_custom_target(coveralls_upload + # Upload the JSON to coveralls. + COMMAND ${CURL_EXECUTABLE} + -S -F json_file=@${COVERALLS_FILE} + https://coveralls.io/api/v1/jobs + + DEPENDS coveralls_generate + + WORKING_DIRECTORY ${PROJECT_BINARY_DIR} + COMMENT "Uploading coveralls output...") + + add_custom_target(coveralls DEPENDS coveralls_upload) + else() + message("COVERALLS UPLOAD: OFF") + add_custom_target(coveralls DEPENDS coveralls_generate) + endif() + +endfunction() + +macro(coveralls_turn_on_coverage) + if(NOT (CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX) + AND (NOT "${CMAKE_C_COMPILER_ID}" STREQUAL "Clang")) + message(FATAL_ERROR "Coveralls: Compiler ${CMAKE_C_COMPILER_ID} is not GNU gcc! Aborting... You can set this on the command line using CC=/usr/bin/gcc CXX=/usr/bin/g++ cmake ..") + endif() + + if(NOT CMAKE_BUILD_TYPE STREQUAL "Debug") + message(FATAL_ERROR "Coveralls: Code coverage results with an optimised (non-Debug) build may be misleading! Add -DCMAKE_BUILD_TYPE=Debug") + endif() + + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -O0 -fprofile-arcs -ftest-coverage") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g -O0 -fprofile-arcs -ftest-coverage") +endmacro() + + + diff --git a/.cmake/Modules/CoverallsClear.cmake b/.cmake/Modules/CoverallsClear.cmake new file mode 100644 index 0000000..7206886 --- /dev/null +++ b/.cmake/Modules/CoverallsClear.cmake @@ -0,0 +1,31 @@ +# +# The MIT License (MIT) +# +# 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. +# +# Copyright (C) 2014 Joakim Söderberg +# + +# do not follow symlinks in file(GLOB_RECURSE ...) +cmake_policy(SET CMP0009 NEW) + +file(GLOB_RECURSE GCDA_FILES "${PROJECT_BINARY_DIR}/*.gcda") +if(NOT GCDA_FILES STREQUAL "") + file(REMOVE ${GCDA_FILES}) +endif() diff --git a/.cmake/Modules/CoverallsGenerateGcov.cmake b/.cmake/Modules/CoverallsGenerateGcov.cmake new file mode 100644 index 0000000..21b827a --- /dev/null +++ b/.cmake/Modules/CoverallsGenerateGcov.cmake @@ -0,0 +1,438 @@ +# +# The MIT License (MIT) +# +# 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. +# +# Copyright (C) 2014 Joakim Söderberg +# +# This is intended to be run by a custom target in a CMake project like this. +# 0. Compile program with coverage support. +# 1. Clear coverage data. (Recursively delete *.gcda in build dir) +# 2. Run the unit tests. +# 3. Run this script specifying which source files the coverage should be performed on. +# +# This script will then use gcov to generate .gcov files in the directory specified +# via the COV_PATH var. This should probably be the same as your cmake build dir. +# +# It then parses the .gcov files to convert them into the Coveralls JSON format: +# https://coveralls.io/docs/api +# +# Example for running as standalone CMake script from the command line: +# (Note it is important the -P is at the end...) +# $ cmake -DCOV_PATH=$(pwd) +# -DCOVERAGE_SRCS="catcierge_rfid.c;catcierge_timer.c" +# -P ../cmake/CoverallsGcovUpload.cmake +# +CMAKE_MINIMUM_REQUIRED(VERSION 2.8) + + +# +# Make sure we have the needed arguments. +# +if (NOT COVERALLS_OUTPUT_FILE) + message(FATAL_ERROR "Coveralls: No coveralls output file specified. Please set COVERALLS_OUTPUT_FILE") +endif() + +if (NOT COV_PATH) + message(FATAL_ERROR "Coveralls: Missing coverage directory path where gcov files will be generated. Please set COV_PATH") +endif() + +if (NOT COVERAGE_SRCS) + message(FATAL_ERROR "Coveralls: Missing the list of source files that we should get the coverage data for COVERAGE_SRCS") +endif() + +if (NOT PROJECT_ROOT) + message(FATAL_ERROR "Coveralls: Missing PROJECT_ROOT.") +endif() + +# Since it's not possible to pass a CMake list properly in the +# "1;2;3" format to an external process, we have replaced the +# ";" with "*", so reverse that here so we get it back into the +# CMake list format. +string(REGEX REPLACE "\\*" ";" COVERAGE_SRCS ${COVERAGE_SRCS}) + +if (NOT DEFINED ENV{GCOV}) + find_program(GCOV_EXECUTABLE gcov) +else() + find_program(GCOV_EXECUTABLE $ENV{GCOV}) +endif() + +if (NOT GCOV_EXECUTABLE) + message(FATAL_ERROR "gcov not found! Aborting...") +endif() + +find_package(Git) + +# TODO: Add these git things to the coveralls json. +if (GIT_FOUND) + # Branch. + execute_process( + COMMAND ${GIT_EXECUTABLE} rev-parse --abbrev-ref HEAD + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} + OUTPUT_VARIABLE GIT_BRANCH + OUTPUT_STRIP_TRAILING_WHITESPACE + ) + + macro (git_log_format FORMAT_CHARS VAR_NAME) + execute_process( + COMMAND ${GIT_EXECUTABLE} log -1 --pretty=format:%${FORMAT_CHARS} + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} + OUTPUT_VARIABLE ${VAR_NAME} + OUTPUT_STRIP_TRAILING_WHITESPACE + ) + endmacro() + + git_log_format(an GIT_AUTHOR_NAME) + git_log_format(ae GIT_AUTHOR_EMAIL) + git_log_format(cn GIT_COMMITTER_NAME) + git_log_format(ce GIT_COMMITTER_EMAIL) + git_log_format(B GIT_COMMIT_MESSAGE) + + message("Git exe: ${GIT_EXECUTABLE}") + message("Git branch: ${GIT_BRANCH}") + message("Git author: ${GIT_AUTHOR_NAME}") + message("Git e-mail: ${GIT_AUTHOR_EMAIL}") + message("Git commiter name: ${GIT_COMMITTER_NAME}") + message("Git commiter e-mail: ${GIT_COMMITTER_EMAIL}") + message("Git commit message: ${GIT_COMMIT_MESSAGE}") + +endif() + +############################# Macros ######################################### + +# +# This macro converts from the full path format gcov outputs: +# +# /path/to/project/root/build/#path#to#project#root#subdir#the_file.c.gcov +# +# to the original source file path the .gcov is for: +# +# /path/to/project/root/subdir/the_file.c +# +macro(get_source_path_from_gcov_filename _SRC_FILENAME _GCOV_FILENAME) + + # /path/to/project/root/build/#path#to#project#root#subdir#the_file.c.gcov + # -> + # #path#to#project#root#subdir#the_file.c.gcov + get_filename_component(_GCOV_FILENAME_WEXT ${_GCOV_FILENAME} NAME) + + # #path#to#project#root#subdir#the_file.c.gcov -> /path/to/project/root/subdir/the_file.c + string(REGEX REPLACE "\\.gcov$" "" SRC_FILENAME_TMP ${_GCOV_FILENAME_WEXT}) + string(REGEX REPLACE "\#" "/" SRC_FILENAME_TMP ${SRC_FILENAME_TMP}) + set(${_SRC_FILENAME} "${SRC_FILENAME_TMP}") +endmacro() + +############################################################################## + +# Get the coverage data. +file(GLOB_RECURSE GCDA_FILES "${COV_PATH}/*.gcda") +message("GCDA files:") + +# Get a list of all the object directories needed by gcov +# (The directories the .gcda files and .o files are found in) +# and run gcov on those. +foreach(GCDA ${GCDA_FILES}) + message("Process: ${GCDA}") + message("------------------------------------------------------------------------------") + get_filename_component(GCDA_DIR ${GCDA} PATH) + + # + # The -p below refers to "Preserve path components", + # This means that the generated gcov filename of a source file will + # keep the original files entire filepath, but / is replaced with #. + # Example: + # + # /path/to/project/root/build/CMakeFiles/the_file.dir/subdir/the_file.c.gcda + # ------------------------------------------------------------------------------ + # File '/path/to/project/root/subdir/the_file.c' + # Lines executed:68.34% of 199 + # /path/to/project/root/subdir/the_file.c:creating '#path#to#project#root#subdir#the_file.c.gcov' + # + # If -p is not specified then the file is named only "the_file.c.gcov" + # + execute_process( + COMMAND ${GCOV_EXECUTABLE} -p -o ${GCDA_DIR} ${GCDA} + WORKING_DIRECTORY ${COV_PATH} + ) +endforeach() + +# TODO: Make these be absolute path +file(GLOB ALL_GCOV_FILES ${COV_PATH}/*.gcov) + +# Get only the filenames to use for filtering. +#set(COVERAGE_SRCS_NAMES "") +#foreach (COVSRC ${COVERAGE_SRCS}) +# get_filename_component(COVSRC_NAME ${COVSRC} NAME) +# message("${COVSRC} -> ${COVSRC_NAME}") +# list(APPEND COVERAGE_SRCS_NAMES "${COVSRC_NAME}") +#endforeach() + +# +# Filter out all but the gcov files we want. +# +# We do this by comparing the list of COVERAGE_SRCS filepaths that the +# user wants the coverage data for with the paths of the generated .gcov files, +# so that we only keep the relevant gcov files. +# +# Example: +# COVERAGE_SRCS = +# /path/to/project/root/subdir/the_file.c +# +# ALL_GCOV_FILES = +# /path/to/project/root/build/#path#to#project#root#subdir#the_file.c.gcov +# /path/to/project/root/build/#path#to#project#root#subdir#other_file.c.gcov +# +# Result should be: +# GCOV_FILES = +# /path/to/project/root/build/#path#to#project#root#subdir#the_file.c.gcov +# +set(GCOV_FILES "") +#message("Look in coverage sources: ${COVERAGE_SRCS}") +message("\nFilter out unwanted GCOV files:") +message("===============================") + +set(COVERAGE_SRCS_REMAINING ${COVERAGE_SRCS}) + +foreach (GCOV_FILE ${ALL_GCOV_FILES}) + + # + # /path/to/project/root/build/#path#to#project#root#subdir#the_file.c.gcov + # -> + # /path/to/project/root/subdir/the_file.c + get_source_path_from_gcov_filename(GCOV_SRC_PATH ${GCOV_FILE}) + + # Is this in the list of source files? + # TODO: We want to match against relative path filenames from the source file root... + list(FIND COVERAGE_SRCS ${GCOV_SRC_PATH} WAS_FOUND) + + if (NOT WAS_FOUND EQUAL -1) + message("YES: ${GCOV_FILE}") + list(APPEND GCOV_FILES ${GCOV_FILE}) + + # We remove it from the list, so we don't bother searching for it again. + # Also files left in COVERAGE_SRCS_REMAINING after this loop ends should + # have coverage data generated from them (no lines are covered). + list(REMOVE_ITEM COVERAGE_SRCS_REMAINING ${GCOV_SRC_PATH}) + else() + message("NO: ${GCOV_FILE}") + endif() +endforeach() + +# TODO: Enable setting these +set(JSON_SERVICE_NAME "travis-ci") +set(JSON_SERVICE_JOB_ID $ENV{TRAVIS_JOB_ID}) +set(JSON_REPO_TOKEN $ENV{COVERALLS_REPO_TOKEN}) + +set(JSON_TEMPLATE +"{ + \"repo_token\": \"\@JSON_REPO_TOKEN\@\", + \"service_name\": \"\@JSON_SERVICE_NAME\@\", + \"service_job_id\": \"\@JSON_SERVICE_JOB_ID\@\", + \"source_files\": \@JSON_GCOV_FILES\@ +}" +) + +set(SRC_FILE_TEMPLATE +"{ + \"name\": \"\@GCOV_SRC_REL_PATH\@\", + \"source_digest\": \"\@GCOV_CONTENTS_MD5\@\", + \"coverage\": \@GCOV_FILE_COVERAGE\@ + }" +) + +message("\nGenerate JSON for files:") +message("=========================") + +set(JSON_GCOV_FILES "[") + +# Read the GCOV files line by line and get the coverage data. +foreach (GCOV_FILE ${GCOV_FILES}) + + get_source_path_from_gcov_filename(GCOV_SRC_PATH ${GCOV_FILE}) + file(RELATIVE_PATH GCOV_SRC_REL_PATH "${PROJECT_ROOT}" "${GCOV_SRC_PATH}") + + # The new coveralls API doesn't need the entire source (Yay!) + # However, still keeping that part for now. Will cleanup in the future. + file(MD5 "${GCOV_SRC_PATH}" GCOV_CONTENTS_MD5) + message("MD5: ${GCOV_SRC_PATH} = ${GCOV_CONTENTS_MD5}") + + # Loads the gcov file as a list of lines. + # (We first open the file and replace all occurences of [] with _ + # because CMake will fail to parse a line containing unmatched brackets... + # also the \ to escaped \n in macros screws up things.) + # https://public.kitware.com/Bug/view.php?id=15369 + file(READ ${GCOV_FILE} GCOV_CONTENTS) + string(REPLACE "[" "_" GCOV_CONTENTS "${GCOV_CONTENTS}") + string(REPLACE "]" "_" GCOV_CONTENTS "${GCOV_CONTENTS}") + string(REPLACE "\\" "_" GCOV_CONTENTS "${GCOV_CONTENTS}") + file(WRITE ${GCOV_FILE}_tmp "${GCOV_CONTENTS}") + + file(STRINGS ${GCOV_FILE}_tmp GCOV_LINES) + list(LENGTH GCOV_LINES LINE_COUNT) + + # Instead of trying to parse the source from the + # gcov file, simply read the file contents from the source file. + # (Parsing it from the gcov is hard because C-code uses ; in many places + # which also happens to be the same as the CMake list delimeter). + file(READ ${GCOV_SRC_PATH} GCOV_FILE_SOURCE) + + string(REPLACE "\\" "\\\\" GCOV_FILE_SOURCE "${GCOV_FILE_SOURCE}") + string(REGEX REPLACE "\"" "\\\\\"" GCOV_FILE_SOURCE "${GCOV_FILE_SOURCE}") + string(REPLACE "\t" "\\\\t" GCOV_FILE_SOURCE "${GCOV_FILE_SOURCE}") + string(REPLACE "\r" "\\\\r" GCOV_FILE_SOURCE "${GCOV_FILE_SOURCE}") + string(REPLACE "\n" "\\\\n" GCOV_FILE_SOURCE "${GCOV_FILE_SOURCE}") + # According to http://json.org/ these should be escaped as well. + # Don't know how to do that in CMake however... + #string(REPLACE "\b" "\\\\b" GCOV_FILE_SOURCE "${GCOV_FILE_SOURCE}") + #string(REPLACE "\f" "\\\\f" GCOV_FILE_SOURCE "${GCOV_FILE_SOURCE}") + #string(REGEX REPLACE "\u([a-fA-F0-9]{4})" "\\\\u\\1" GCOV_FILE_SOURCE "${GCOV_FILE_SOURCE}") + + # We want a json array of coverage data as a single string + # start building them from the contents of the .gcov + set(GCOV_FILE_COVERAGE "[") + + set(GCOV_LINE_COUNT 1) # Line number for the .gcov. + set(DO_SKIP 0) + foreach (GCOV_LINE ${GCOV_LINES}) + #message("${GCOV_LINE}") + # Example of what we're parsing: + # Hitcount |Line | Source + # " 8: 26: if (!allowed || (strlen(allowed) == 0))" + string(REGEX REPLACE + "^([^:]*):([^:]*):(.*)$" + "\\1;\\2;\\3" + RES + "${GCOV_LINE}") + + # Check if we should exclude lines using the Lcov syntax. + string(REGEX MATCH "LCOV_EXCL_START" START_SKIP "${GCOV_LINE}") + string(REGEX MATCH "LCOV_EXCL_END" END_SKIP "${GCOV_LINE}") + string(REGEX MATCH "LCOV_EXCL_LINE" LINE_SKIP "${GCOV_LINE}") + + set(RESET_SKIP 0) + if (LINE_SKIP AND NOT DO_SKIP) + set(DO_SKIP 1) + set(RESET_SKIP 1) + endif() + + if (START_SKIP) + set(DO_SKIP 1) + message("${GCOV_LINE_COUNT}: Start skip") + endif() + + if (END_SKIP) + set(DO_SKIP 0) + endif() + + list(LENGTH RES RES_COUNT) + + if (RES_COUNT GREATER 2) + list(GET RES 0 HITCOUNT) + list(GET RES 1 LINE) + list(GET RES 2 SOURCE) + + string(STRIP ${HITCOUNT} HITCOUNT) + string(STRIP ${LINE} LINE) + + # Lines with 0 line numbers are metadata and can be ignored. + if (NOT ${LINE} EQUAL 0) + + if (DO_SKIP) + set(GCOV_FILE_COVERAGE "${GCOV_FILE_COVERAGE}null, ") + else() + # Translate the hitcount into valid JSON values. + if (${HITCOUNT} STREQUAL "#####" OR ${HITCOUNT} STREQUAL "=====") + set(GCOV_FILE_COVERAGE "${GCOV_FILE_COVERAGE}0, ") + elseif (${HITCOUNT} STREQUAL "-") + set(GCOV_FILE_COVERAGE "${GCOV_FILE_COVERAGE}null, ") + else() + set(GCOV_FILE_COVERAGE "${GCOV_FILE_COVERAGE}${HITCOUNT}, ") + endif() + endif() + endif() + else() + message(WARNING "Failed to properly parse line (RES_COUNT = ${RES_COUNT}) ${GCOV_FILE}:${GCOV_LINE_COUNT}\n-->${GCOV_LINE}") + endif() + + if (RESET_SKIP) + set(DO_SKIP 0) + endif() + math(EXPR GCOV_LINE_COUNT "${GCOV_LINE_COUNT}+1") + endforeach() + + message("${GCOV_LINE_COUNT} of ${LINE_COUNT} lines read!") + + # Advanced way of removing the trailing comma in the JSON array. + # "[1, 2, 3, " -> "[1, 2, 3" + string(REGEX REPLACE ",[ ]*$" "" GCOV_FILE_COVERAGE ${GCOV_FILE_COVERAGE}) + + # Append the trailing ] to complete the JSON array. + set(GCOV_FILE_COVERAGE "${GCOV_FILE_COVERAGE}]") + + # Generate the final JSON for this file. + message("Generate JSON for file: ${GCOV_SRC_REL_PATH}...") + string(CONFIGURE ${SRC_FILE_TEMPLATE} FILE_JSON) + + set(JSON_GCOV_FILES "${JSON_GCOV_FILES}${FILE_JSON}, ") +endforeach() + +# Loop through all files we couldn't find any coverage for +# as well, and generate JSON for those as well with 0% coverage. +foreach(NOT_COVERED_SRC ${COVERAGE_SRCS_REMAINING}) + + # Loads the source file as a list of lines. + file(STRINGS ${PROJECT_ROOT}/${NOT_COVERED_SRC} SRC_LINES) + + set(GCOV_FILE_COVERAGE "[") + set(GCOV_FILE_SOURCE "") + + foreach (SOURCE ${SRC_LINES}) + set(GCOV_FILE_COVERAGE "${GCOV_FILE_COVERAGE}0, ") + + string(REPLACE "\\" "\\\\" SOURCE "${SOURCE}") + string(REGEX REPLACE "\"" "\\\\\"" SOURCE "${SOURCE}") + string(REPLACE "\t" "\\\\t" SOURCE "${SOURCE}") + string(REPLACE "\r" "\\\\r" SOURCE "${SOURCE}") + set(GCOV_FILE_SOURCE "${GCOV_FILE_SOURCE}${SOURCE}\\n") + endforeach() + + # Remove trailing comma, and complete JSON array with ] + string(REGEX REPLACE ",[ ]*$" "" GCOV_FILE_COVERAGE ${GCOV_FILE_COVERAGE}) + set(GCOV_FILE_COVERAGE "${GCOV_FILE_COVERAGE}]") + + # Generate the final JSON for this file. + message("Generate JSON for non-gcov file: ${NOT_COVERED_SRC}...") + string(CONFIGURE ${SRC_FILE_TEMPLATE} FILE_JSON) + set(JSON_GCOV_FILES "${JSON_GCOV_FILES}${FILE_JSON}, ") +endforeach() + +# Get rid of trailing comma. +string(REGEX REPLACE ",[ ]*$" "" JSON_GCOV_FILES ${JSON_GCOV_FILES}) +set(JSON_GCOV_FILES "${JSON_GCOV_FILES}]") + +# Generate the final complete JSON! +message("Generate final JSON...") +string(CONFIGURE ${JSON_TEMPLATE} JSON) + +file(WRITE "${COVERALLS_OUTPUT_FILE}" "${JSON}") +message("###########################################################################") +message("Generated coveralls JSON containing coverage data:") +message("${COVERALLS_OUTPUT_FILE}") +message("###########################################################################") + diff --git a/.travis.yml b/.travis.yml index 69cc33d..f12bd95 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,6 @@ language: c compiler: - - gcc-5 + - gcc-5 sudo: false addons: apt: @@ -12,13 +12,13 @@ addons: - gettext - cmake before_install: - - pip install --user cpp-coveralls - .ci/install-libcsptr.sh - export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$HOME/lib - export CFLAGS="-g -O0" + - export GCOV=gcov-5 script: - - mkdir -p build && cd $_ && cmake -Dcoverage=on -DCMAKE_PREFIX_PATH=$HOME .. && make && make -C samples test + - mkdir -p build && cd $_ && cmake -DCOVERALLS=ON -DCMAKE_BUILD_TYPE=Debug -DCMAKE_PREFIX_PATH=$HOME .. && make && make -C samples test after_success: - - coveralls --gcov gcov-5 --exclude samples --exclude dependencies --gcov-options '\-lp' -b . + - make coveralls after_failure: - cat $(find samples -iname '*.log') /dev/null diff --git a/CMakeLists.txt b/CMakeLists.txt index 2404e31..2f12347 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,15 +2,33 @@ cmake_minimum_required(VERSION 2.8) project(Criterion C) +# Project setup & environment variables + +enable_testing() +add_subdirectory(samples) + set(PROJECT_VERSION "1.2.2") set(LOCALEDIR ${CMAKE_INSTALL_PREFIX}/share/locale) set(GettextTranslate_ALL) set(GettextTranslate_GMO_BINARY) -set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/.cmake/Modules/") +set(MODULE_DIR "${CMAKE_SOURCE_DIR}/.cmake/Modules") +set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${MODULE_DIR}) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -Werror -g -std=gnu11") set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,-no-undefined") +# Setup coveralls + +option(COVERALLS "Turn on coveralls support" OFF) +option(COVERALLS_UPLOAD "Upload the generated coveralls json" ON) + +if (COVERALLS) + include(Coveralls) + coveralls_turn_on_coverage() +endif() + +# Find dependencies + find_package(Gettext) if (GETTEXT_FOUND) include(GettextTranslate) @@ -24,11 +42,15 @@ CHECK_LIBRARY_EXISTS(rt clock_gettime "time.h" HAVE_CLOCK_GETTIME) find_package(PCRE) find_package(Libcsptr REQUIRED) +# Generate the configure file + configure_file( "${CMAKE_SOURCE_DIR}/src/config.h.in" "${CMAKE_SOURCE_DIR}/src/config.h" ) +# List sources and headers + set(SOURCE_FILES src/abort.c src/abort.h @@ -71,20 +93,8 @@ set(INTERFACE_FILES include/criterion/stats.h ) -option(coverage "coverage" OFF) -if (coverage) - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fprofile-arcs -ftest-coverage") - set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -fprofile-arcs -ftest-coverage") -endif() - -enable_testing() - -add_subdirectory(samples) - include_directories(include src ${CSPTR_INCLUDE_DIRS}) - add_library(criterion SHARED ${SOURCE_FILES} ${INTERFACE_FILES}) - target_link_libraries(criterion ${CSPTR_LIBRARIES}) if (HAVE_CLOCK_GETTIME) @@ -95,6 +105,10 @@ if (PCRE_FOUND) target_link_libraries(criterion ${PCRE_LIBRARIES}) endif() +if (COVERALLS) + coveralls_setup("${SOURCE_FILES}" ${COVERALLS_UPLOAD}) +endif() + install(FILES ${INTERFACE_FILES} DESTINATION include/criterion) install(TARGETS criterion LIBRARY DESTINATION lib From 5b8a03dfdf0de81ba3c33386d762f5021355840f Mon Sep 17 00:00:00 2001 From: Snaipe Date: Thu, 30 Jul 2015 13:49:24 +0200 Subject: [PATCH 29/78] Manually added coveralls repo token --- .travis.yml | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/.travis.yml b/.travis.yml index f12bd95..bb6a894 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,6 @@ language: c compiler: - - gcc-5 +- gcc-5 sudo: false addons: apt: @@ -12,13 +12,17 @@ addons: - gettext - cmake before_install: - - .ci/install-libcsptr.sh - - export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$HOME/lib - - export CFLAGS="-g -O0" - - export GCOV=gcov-5 +- ".ci/install-libcsptr.sh" +- export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$HOME/lib +- export CFLAGS="-g -O0" +- export GCOV=gcov-5 script: - - mkdir -p build && cd $_ && cmake -DCOVERALLS=ON -DCMAKE_BUILD_TYPE=Debug -DCMAKE_PREFIX_PATH=$HOME .. && make && make -C samples test +- mkdir -p build && cd $_ && cmake -DCOVERALLS=ON -DCMAKE_BUILD_TYPE=Debug -DCMAKE_PREFIX_PATH=$HOME + .. && make && make -C samples test after_success: - - make coveralls +- make coveralls after_failure: - - cat $(find samples -iname '*.log') /dev/null +- cat $(find samples -iname '*.log') /dev/null +env: + global: + secure: bzZcWjdqoTgceC40kEBucx7NuWYJPk+rxgF3UJJDXi+ijQAFYPv70p5eVsGR6rfc+XgqXCxcUFQtuL4ZVt7QEfVk1ZOJITNeHbKIeKaEYS4nX8mFf+CBeEm9bJGZ04KiQJdJu5mzzAHvXbW7roGXDGWe1Bjnk5wwA+dNUCa7H04= From 5cf91b1310c72ba75937467fcfc9b72fb58f663b Mon Sep 17 00:00:00 2001 From: Snaipe Date: Thu, 30 Jul 2015 14:00:08 +0200 Subject: [PATCH 30/78] Fixed bumpversion --- .bumpversion.cfg | 4 ++-- appveyor.yml | 2 +- doc/conf.py | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.bumpversion.cfg b/.bumpversion.cfg index bbcb195..b86b6f3 100644 --- a/.bumpversion.cfg +++ b/.bumpversion.cfg @@ -1,8 +1,8 @@ [bumpversion] -current_version = 1.2.1 +current_version = 1.2.2 commit = True -[bumpversion:file:configure.ac] +[bumpversion:file:CMakeLists.txt] [bumpversion:file:doc/conf.py] diff --git a/appveyor.yml b/appveyor.yml index 6762854..63f90c4 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,4 +1,4 @@ -version: 1.2.1_b{build}-{branch} +version: 1.2.2_b{build}-{branch} os: Windows Server 2012 diff --git a/doc/conf.py b/doc/conf.py index a4d0f24..b2e3e18 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.2.1' +version = '1.2.2' # The full version, including alpha/beta/rc tags. release = version From 2b2bdcde14ce4b32a0a9cc0e8b9f1b77bb8bf679 Mon Sep 17 00:00:00 2001 From: Snaipe Date: Thu, 30 Jul 2015 14:00:29 +0200 Subject: [PATCH 31/78] =?UTF-8?q?Bump=20version:=201.2.2=20=E2=86=92=201.2?= =?UTF-8?q?.3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .bumpversion.cfg | 2 +- CMakeLists.txt | 2 +- appveyor.yml | 2 +- doc/conf.py | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.bumpversion.cfg b/.bumpversion.cfg index b86b6f3..6ea2abb 100644 --- a/.bumpversion.cfg +++ b/.bumpversion.cfg @@ -1,5 +1,5 @@ [bumpversion] -current_version = 1.2.2 +current_version = 1.2.3 commit = True [bumpversion:file:CMakeLists.txt] diff --git a/CMakeLists.txt b/CMakeLists.txt index 2f12347..7e9bc5a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,7 +7,7 @@ project(Criterion C) enable_testing() add_subdirectory(samples) -set(PROJECT_VERSION "1.2.2") +set(PROJECT_VERSION "1.2.3") set(LOCALEDIR ${CMAKE_INSTALL_PREFIX}/share/locale) set(GettextTranslate_ALL) set(GettextTranslate_GMO_BINARY) diff --git a/appveyor.yml b/appveyor.yml index 63f90c4..50a3af0 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,4 +1,4 @@ -version: 1.2.2_b{build}-{branch} +version: 1.2.3_b{build}-{branch} os: Windows Server 2012 diff --git a/doc/conf.py b/doc/conf.py index b2e3e18..81ae850 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.2.2' +version = '1.2.3' # The full version, including alpha/beta/rc tags. release = version From 0fde580e068931cbd4b161a0e7c2c54183567d89 Mon Sep 17 00:00:00 2001 From: Snaipe Date: Thu, 30 Jul 2015 15:25:40 +0200 Subject: [PATCH 32/78] Fixed Coveralls cmake module --- .cmake/Modules/CoverallsGenerateGcov.cmake | 24 ++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/.cmake/Modules/CoverallsGenerateGcov.cmake b/.cmake/Modules/CoverallsGenerateGcov.cmake index 21b827a..9bdd3ee 100644 --- a/.cmake/Modules/CoverallsGenerateGcov.cmake +++ b/.cmake/Modules/CoverallsGenerateGcov.cmake @@ -67,6 +67,17 @@ endif() # CMake list format. string(REGEX REPLACE "\\*" ";" COVERAGE_SRCS ${COVERAGE_SRCS}) +# convert all paths in COVERAGE_SRCS to absolute paths +set(COVERAGE_SRCS_TMP "") +foreach (COVERAGE_SRC ${COVERAGE_SRCS}) + if (NOT "${COVERAGE_SRC}" MATCHES "^/") + set(COVERAGE_SRC ${PROJECT_ROOT}/${COVERAGE_SRC}) + endif() + list(APPEND COVERAGE_SRCS_TMP ${COVERAGE_SRC}) +endforeach() +set(COVERAGE_SRCS ${COVERAGE_SRCS_TMP}) +unset(COVERAGE_SRCS_TMP) + if (NOT DEFINED ENV{GCOV}) find_program(GCOV_EXECUTABLE gcov) else() @@ -216,6 +227,7 @@ foreach (GCOV_FILE ${ALL_GCOV_FILES}) # -> # /path/to/project/root/subdir/the_file.c get_source_path_from_gcov_filename(GCOV_SRC_PATH ${GCOV_FILE}) + file(RELATIVE_PATH GCOV_SRC_REL_PATH "${PROJECT_ROOT}" "${GCOV_SRC_PATH}") # Is this in the list of source files? # TODO: We want to match against relative path filenames from the source file root... @@ -281,6 +293,9 @@ foreach (GCOV_FILE ${GCOV_FILES}) string(REPLACE "[" "_" GCOV_CONTENTS "${GCOV_CONTENTS}") string(REPLACE "]" "_" GCOV_CONTENTS "${GCOV_CONTENTS}") string(REPLACE "\\" "_" GCOV_CONTENTS "${GCOV_CONTENTS}") + + # Remove file contents to avoid encoding issues (cmake 2.8 has no ENCODING option) + string(REGEX REPLACE "([^:]*):([^:]*):([^\n]*)\n" "\\1:\\2: \n" GCOV_CONTENTS "${GCOV_CONTENTS}") file(WRITE ${GCOV_FILE}_tmp "${GCOV_CONTENTS}") file(STRINGS ${GCOV_FILE}_tmp GCOV_LINES) @@ -396,14 +411,19 @@ endforeach() # as well, and generate JSON for those as well with 0% coverage. foreach(NOT_COVERED_SRC ${COVERAGE_SRCS_REMAINING}) + # Set variables for json replacement + set(GCOV_SRC_PATH ${NOT_COVERED_SRC}) + file(MD5 "${GCOV_SRC_PATH}" GCOV_CONTENTS_MD5) + file(RELATIVE_PATH GCOV_SRC_REL_PATH "${PROJECT_ROOT}" "${GCOV_SRC_PATH}") + # Loads the source file as a list of lines. - file(STRINGS ${PROJECT_ROOT}/${NOT_COVERED_SRC} SRC_LINES) + file(STRINGS ${NOT_COVERED_SRC} SRC_LINES) set(GCOV_FILE_COVERAGE "[") set(GCOV_FILE_SOURCE "") foreach (SOURCE ${SRC_LINES}) - set(GCOV_FILE_COVERAGE "${GCOV_FILE_COVERAGE}0, ") + set(GCOV_FILE_COVERAGE "${GCOV_FILE_COVERAGE}null, ") string(REPLACE "\\" "\\\\" SOURCE "${SOURCE}") string(REGEX REPLACE "\"" "\\\\\"" SOURCE "${SOURCE}") From b8577506cdead5889b7c5a370861d693d5b037e5 Mon Sep 17 00:00:00 2001 From: Snaipe Date: Thu, 30 Jul 2015 16:57:37 +0200 Subject: [PATCH 33/78] Added git details to coveralls upload --- .cmake/Modules/CoverallsGenerateGcov.cmake | 25 ++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/.cmake/Modules/CoverallsGenerateGcov.cmake b/.cmake/Modules/CoverallsGenerateGcov.cmake index 9bdd3ee..fced087 100644 --- a/.cmake/Modules/CoverallsGenerateGcov.cmake +++ b/.cmake/Modules/CoverallsGenerateGcov.cmake @@ -90,7 +90,22 @@ endif() find_package(Git) -# TODO: Add these git things to the coveralls json. +set(JSON_REPO_TEMPLATE + "{ + \"head\": { + \"id\": \"\@GIT_COMMIT_HASH\@\", + \"author_name\": \"\@GIT_AUTHOR_NAME\@\", + \"author_email\": \"\@GIT_AUTHOR_EMAIL\@\", + \"committer_name\": \"\@GIT_COMMITTER_NAME\@\", + \"committer_email\": \"\@GIT_COMMITTER_EMAIL\@\", + \"message\": \"\@GIT_COMMIT_MESSAGE\@\" + }, + \"branch\": \"@GIT_BRANCH@\", + \"remotes\": [] + }" +) + +# TODO: Fill in git remote data if (GIT_FOUND) # Branch. execute_process( @@ -114,6 +129,7 @@ if (GIT_FOUND) git_log_format(cn GIT_COMMITTER_NAME) git_log_format(ce GIT_COMMITTER_EMAIL) git_log_format(B GIT_COMMIT_MESSAGE) + git_log_format(H GIT_COMMIT_HASH) message("Git exe: ${GIT_EXECUTABLE}") message("Git branch: ${GIT_BRANCH}") @@ -121,8 +137,12 @@ if (GIT_FOUND) message("Git e-mail: ${GIT_AUTHOR_EMAIL}") message("Git commiter name: ${GIT_COMMITTER_NAME}") message("Git commiter e-mail: ${GIT_COMMITTER_EMAIL}") + message("Git commit hash: ${GIT_COMMIT_HASH}") message("Git commit message: ${GIT_COMMIT_MESSAGE}") + string(CONFIGURE ${JSON_REPO_TEMPLATE} JSON_REPO_DATA) +else() + set(JSON_REPO_DATA "{}") endif() ############################# Macros ######################################### @@ -256,7 +276,8 @@ set(JSON_TEMPLATE \"repo_token\": \"\@JSON_REPO_TOKEN\@\", \"service_name\": \"\@JSON_SERVICE_NAME\@\", \"service_job_id\": \"\@JSON_SERVICE_JOB_ID\@\", - \"source_files\": \@JSON_GCOV_FILES\@ + \"source_files\": \@JSON_GCOV_FILES\@, + \"git\": \@JSON_REPO_DATA\@ }" ) From c22af6bb3764745297807162ae5a28f6ceef79dd Mon Sep 17 00:00:00 2001 From: Snaipe Date: Thu, 30 Jul 2015 20:30:01 +0200 Subject: [PATCH 34/78] (Hopefully) fixed appveyor & windows builds --- .ci/install-libcsptr.sh | 2 +- CMakeLists.txt | 1 + appveyor.yml | 50 +++++++---------------------------------- 3 files changed, 10 insertions(+), 43 deletions(-) diff --git a/.ci/install-libcsptr.sh b/.ci/install-libcsptr.sh index 0e98b2c..6b3527d 100755 --- a/.ci/install-libcsptr.sh +++ b/.ci/install-libcsptr.sh @@ -7,7 +7,7 @@ git clone --branch ${tag} --depth 1 ${repo} dependencies/libcsptr && ( cd dependencies/libcsptr && ./autogen.sh && - ./configure --prefix=$HOME && + ./configure --prefix=$HOME "$@" && make && make install ) diff --git a/CMakeLists.txt b/CMakeLists.txt index 7e9bc5a..0ca9a1b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -112,6 +112,7 @@ endif() install(FILES ${INTERFACE_FILES} DESTINATION include/criterion) install(TARGETS criterion LIBRARY DESTINATION lib + ARCHIVE DESTINATION lib ) add_custom_target(uninstall diff --git a/appveyor.yml b/appveyor.yml index 50a3af0..4f33076 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -3,44 +3,14 @@ version: 1.2.3_b{build}-{branch} os: Windows Server 2012 init: - - ps: (New-Object System.Net.WebClient).DownloadFile("https://cygwin.com/setup-x86.exe", "c:\setup-x86.exe") - git config --global core.autocrlf input - - c:\setup-x86.exe -qnNdO -R %CYG_ROOT% -s %CYG_MIRROR% -l %CYG_CACHE% \ - -P autoconf \ - -P automake \ - -P gcc-core \ - -P mingw-runtime \ - -P mingw-binutils \ - -P mingw-gcc-core \ - -P mingw-pthreads \ - -P mingw-w32api \ - -P mingw64-i686-gcc-core \ - -P libtool \ - -P make \ - -P python3 \ - -P gettext-devel \ - -P gettext \ - -P expat \ - -P intltool \ - -P libiconv \ - -P pkg-config \ - -P check \ - -P git \ - -P wget \ - -P curl + - C:\MinGW\bin\mingw-get install mingw32-autotools curl + - 'SET PATH=%PATH%;C:\MinGW\msys\1.0\bin;C:\MinGW\bin' environment: - global: - CYG_ROOT: C:\cygwin - 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%' - clone_depth: 5 matrix: @@ -53,23 +23,19 @@ configuration: Release install: - 'set GCOV_PREFIX=%APPVEYOR_BUILD_FOLDER%' - - '%CYG_BASH% -lc "cd $APPVEYOR_BUILD_FOLDER; exec 0 Date: Thu, 30 Jul 2015 22:40:00 +0200 Subject: [PATCH 35/78] Switched to gcc 4.8 --- .travis.yml | 9 ++------- CMakeLists.txt | 2 +- 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/.travis.yml b/.travis.yml index bb6a894..a1bca84 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,24 +1,19 @@ language: c compiler: -- gcc-5 +- gcc sudo: false addons: apt: - sources: - - ubuntu-toolchain-r-test packages: - check - - gcc-5 - gettext - cmake before_install: - ".ci/install-libcsptr.sh" - export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$HOME/lib - export CFLAGS="-g -O0" -- export GCOV=gcov-5 script: -- mkdir -p build && cd $_ && cmake -DCOVERALLS=ON -DCMAKE_BUILD_TYPE=Debug -DCMAKE_PREFIX_PATH=$HOME - .. && make && make -C samples test +- mkdir -p build && cd $_ && cmake -DCOVERALLS=ON -DCMAKE_BUILD_TYPE=Debug -DCMAKE_PREFIX_PATH=$HOME .. && make && make -C samples test after_success: - make coveralls after_failure: diff --git a/CMakeLists.txt b/CMakeLists.txt index 0ca9a1b..1eb7db7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -14,7 +14,7 @@ set(GettextTranslate_GMO_BINARY) set(MODULE_DIR "${CMAKE_SOURCE_DIR}/.cmake/Modules") set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${MODULE_DIR}) -set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -Werror -g -std=gnu11") +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -Werror -g -std=gnu99") set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,-no-undefined") # Setup coveralls From a8bec0a0f6a0266723db59da475cb28f2a801684 Mon Sep 17 00:00:00 2001 From: Snaipe Date: Thu, 30 Jul 2015 23:08:06 +0200 Subject: [PATCH 36/78] Updated libcsptr to use gcc 4.6 --- .ci/install-libcsptr.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.ci/install-libcsptr.sh b/.ci/install-libcsptr.sh index 6b3527d..ae68416 100755 --- a/.ci/install-libcsptr.sh +++ b/.ci/install-libcsptr.sh @@ -1,6 +1,6 @@ #!/bin/bash repo="https://github.com/Snaipe/libcsptr.git" -tag="v2.0.2" +tag="v2.0.4" mkdir dependencies git clone --branch ${tag} --depth 1 ${repo} dependencies/libcsptr && From 4553a50f462ca0d2e295348f336ab1a644c2d507 Mon Sep 17 00:00:00 2001 From: Snaipe Date: Thu, 30 Jul 2015 23:17:03 +0200 Subject: [PATCH 37/78] Fixed missing initializer warning --- src/log/logging.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/log/logging.c b/src/log/logging.c index 5d2bc8d..623b2a9 100644 --- a/src/log/logging.c +++ b/src/log/logging.c @@ -38,7 +38,7 @@ const struct criterion_prefix_data g_criterion_logging_prefixes[] = { [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 } + { NULL, NULL } }; void criterion_plog(enum criterion_logging_level level, const struct criterion_prefix_data *prefix, const char *msg, ...) { From a58dd92c8491d2eaadb875b001814d426120043e Mon Sep 17 00:00:00 2001 From: Snaipe Date: Fri, 31 Jul 2015 00:31:45 +0200 Subject: [PATCH 38/78] Fixed appveyor build & libcsptr installation --- .ci/install-libcsptr.sh | 6 +++--- appveyor.yml | 14 ++++++-------- 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/.ci/install-libcsptr.sh b/.ci/install-libcsptr.sh index ae68416..9e0d17d 100755 --- a/.ci/install-libcsptr.sh +++ b/.ci/install-libcsptr.sh @@ -6,9 +6,9 @@ mkdir dependencies git clone --branch ${tag} --depth 1 ${repo} dependencies/libcsptr && ( cd dependencies/libcsptr && - ./autogen.sh && - ./configure --prefix=$HOME "$@" && + mkdir build && + cd $_ && + cmake -DCMAKE_INSTALL_PREFIX=$HOME "$@" .. && make && make install ) -rm -Rf dependencies diff --git a/appveyor.yml b/appveyor.yml index 4f33076..ebe230c 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -4,7 +4,6 @@ os: Windows Server 2012 init: - git config --global core.autocrlf input - - C:\MinGW\bin\mingw-get install mingw32-autotools curl - 'SET PATH=%PATH%;C:\MinGW\msys\1.0\bin;C:\MinGW\bin' environment: @@ -23,19 +22,18 @@ configuration: Release install: - 'set GCOV_PREFIX=%APPVEYOR_BUILD_FOLDER%' - - 'bash -lc "cd $APPVEYOR_BUILD_FOLDER; exec 0 Date: Fri, 31 Jul 2015 02:46:54 +0200 Subject: [PATCH 39/78] Fixed libcsptr not being detected in the CI cmake script --- .ci/install-libcsptr.sh | 2 +- .travis.yml | 1 + appveyor.yml | 3 ++- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/.ci/install-libcsptr.sh b/.ci/install-libcsptr.sh index 9e0d17d..088f06b 100755 --- a/.ci/install-libcsptr.sh +++ b/.ci/install-libcsptr.sh @@ -8,7 +8,7 @@ git clone --branch ${tag} --depth 1 ${repo} dependencies/libcsptr && cd dependencies/libcsptr && mkdir build && cd $_ && - cmake -DCMAKE_INSTALL_PREFIX=$HOME "$@" .. && + cmake -DCMAKE_INSTALL_PREFIX=$LOCAL_INSTALL "$@" .. && make && make install ) diff --git a/.travis.yml b/.travis.yml index a1bca84..b9bc2f5 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,6 +9,7 @@ addons: - gettext - cmake before_install: +- export LOCAL_INSTALL="$HOME" - ".ci/install-libcsptr.sh" - export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$HOME/lib - export CFLAGS="-g -O0" diff --git a/appveyor.yml b/appveyor.yml index ebe230c..2ade1ff 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -22,9 +22,10 @@ configuration: Release install: - 'set GCOV_PREFIX=%APPVEYOR_BUILD_FOLDER%' + - 'set LOCAL_INSTALL=%APPVEYOR_BUILD_FOLDER%' - 'bash -lc "cd $APPVEYOR_BUILD_FOLDER; exec 0 Date: Fri, 31 Jul 2015 03:15:41 +0200 Subject: [PATCH 40/78] Aliased strtok_s to strtok_r for windows builds --- src/log/normal.c | 7 +++++++ src/log/tap.c | 7 +++++++ 2 files changed, 14 insertions(+) diff --git a/src/log/normal.c b/src/log/normal.c index 1d6609e..f1a67d6 100644 --- a/src/log/normal.c +++ b/src/log/normal.c @@ -33,6 +33,13 @@ #include "timer.h" #include "config.h" #include "i18n.h" +#include "posix-compat.h" + +#ifdef VANILLA_WIN32 +// provided by windows' libc implementation +char *strtok_s(char *strToken, const char *strDelimit, char **context); +# define strtok_r strtok_s +#endif typedef const char *const msg_t; diff --git a/src/log/tap.c b/src/log/tap.c index 822b92f..43768f7 100644 --- a/src/log/tap.c +++ b/src/log/tap.c @@ -31,6 +31,13 @@ #include "criterion/ordered-set.h" #include "timer.h" #include "config.h" +#include "posix-compat.h" + +#ifdef VANILLA_WIN32 +// provided by windows' libc implementation +char *strtok_s(char *strToken, const char *strDelimit, char **context); +# define strtok_r strtok_s +#endif void tap_log_pre_all(struct criterion_test_set *set) { size_t enabled_count = 0; From 86e059b403d66102d3cfae28703243c5b971170a Mon Sep 17 00:00:00 2001 From: Snaipe Date: Fri, 31 Jul 2015 04:21:40 +0200 Subject: [PATCH 41/78] Fixed GetProcessId include compatibility for windows server 2012 & windows 8 --- src/posix-compat.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/posix-compat.c b/src/posix-compat.c index e68f848..020d61f 100644 --- a/src/posix-compat.c +++ b/src/posix-compat.c @@ -4,6 +4,8 @@ #ifdef VANILLA_WIN32 # define VC_EXTRALEAN # define WIN32_LEAN_AND_MEAN +# undef _WIN32_WINNT +# define _WIN32_WINNT 0x0502 # include # include # include From f8bb64ace7e28aeb92edb70ac670db3bac5efd04 Mon Sep 17 00:00:00 2001 From: Snaipe Date: Fri, 31 Jul 2015 07:44:32 +0200 Subject: [PATCH 42/78] Added conditional extmatch.{c,h} compilation if PCRE is here or not --- CMakeLists.txt | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 1eb7db7..b36e3dc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -74,11 +74,16 @@ set(SOURCE_FILES src/i18n.h src/ordered-set.c src/posix-compat.c - src/extmatch.c - src/extmatch.h src/main.c ) +if (PCRE_FOUND) + set (SOURCE_FILES ${SOURCE_FILES} + src/extmatch.c + src/extmatch.h + ) +endif () + set(INTERFACE_FILES include/criterion/assert.h include/criterion/abort.h From 0e879aa34b200b7d583befdbd3ea366a8ff09cc7 Mon Sep 17 00:00:00 2001 From: Snaipe Date: Fri, 31 Jul 2015 08:02:09 +0200 Subject: [PATCH 43/78] Added libintl checks & linking for ENABLE_NLS --- .cmake/Modules/FindLibintl.cmake | 62 ++++++++++++++++++++++++++++++++ CMakeLists.txt | 7 +++- 2 files changed, 68 insertions(+), 1 deletion(-) create mode 100644 .cmake/Modules/FindLibintl.cmake diff --git a/.cmake/Modules/FindLibintl.cmake b/.cmake/Modules/FindLibintl.cmake new file mode 100644 index 0000000..dad2634 --- /dev/null +++ b/.cmake/Modules/FindLibintl.cmake @@ -0,0 +1,62 @@ +# Try to find Libintl functionality +# Once done this will define +# +# LIBINTL_FOUND - system has Libintl +# LIBINTL_INCLUDE_DIR - Libintl include directory +# LIBINTL_LIBRARIES - Libraries needed to use Libintl +# +# TODO: This will enable translations only if Gettext functionality is +# present in libc. Must have more robust system for release, where Gettext +# functionality can also reside in standalone Gettext library, or the one +# embedded within kdelibs (cf. gettext.m4 from Gettext source). + +# Copyright (c) 2006, Chusslove Illich, +# Copyright (c) 2007, Alexander Neundorf, +# +# Redistribution and use is allowed according to the terms of the BSD license. +# For details see the accompanying COPYING-CMAKE-SCRIPTS file. + + +SET(LIBINTL_SEARCH_PATHS + /usr/local/opt/ + /usr/local/ + /usr/ +) + +if(LIBINTL_INCLUDE_DIR AND LIBINTL_LIB_FOUND) + set(Libintl_FIND_QUIETLY TRUE) +endif(LIBINTL_INCLUDE_DIR AND LIBINTL_LIB_FOUND) + +find_path(LIBINTL_INCLUDE_DIR libintl.h + HINTS + PATH_SUFFIXES gettext/include + PATHS ${LIBINTL_SEARCH_PATHS} +) + +set(LIBINTL_LIB_FOUND FALSE) + +if(LIBINTL_INCLUDE_DIR) + include(CheckFunctionExists) + check_function_exists(dgettext LIBINTL_LIBC_HAS_DGETTEXT) + + if (LIBINTL_LIBC_HAS_DGETTEXT) + set(LIBINTL_LIBRARIES) + set(LIBINTL_LIB_FOUND TRUE) + else (LIBINTL_LIBC_HAS_DGETTEXT) + find_library(LIBINTL_LIBRARIES + NAMES intl + HINTS + PATH_SUFFIXES gettext/lib + PATHS ${LIBINTL_SEARCH_PATHS} + ) + if(LIBINTL_LIBRARIES) + set(LIBINTL_LIB_FOUND TRUE) + endif(LIBINTL_LIBRARIES) + endif (LIBINTL_LIBC_HAS_DGETTEXT) + +endif(LIBINTL_INCLUDE_DIR) + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(Libintl DEFAULT_MSG LIBINTL_INCLUDE_DIR LIBINTL_LIB_FOUND) + +mark_as_advanced(LIBINTL_INCLUDE_DIR LIBINTL_LIBRARIES LIBINTL_LIBC_HAS_DGETTEXT LIBINTL_LIB_FOUND) diff --git a/CMakeLists.txt b/CMakeLists.txt index b36e3dc..503d13e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -30,7 +30,8 @@ endif() # Find dependencies find_package(Gettext) -if (GETTEXT_FOUND) +find_package(Libintl) +if (GETTEXT_FOUND AND Libintl_FOUND) include(GettextTranslate) add_subdirectory(po) set(ENABLE_NLS 1) @@ -110,6 +111,10 @@ if (PCRE_FOUND) target_link_libraries(criterion ${PCRE_LIBRARIES}) endif() +if (LIBINTL_FOUND) + target_link_libraries(criterion ${LIBINTL_LIBRARIES}) +endif() + if (COVERALLS) coveralls_setup("${SOURCE_FILES}" ${COVERALLS_UPLOAD}) endif() From 9f26b192ecf5cab1f4cd530ad815c793bbf9331e Mon Sep 17 00:00:00 2001 From: Snaipe Date: Fri, 31 Jul 2015 08:17:19 +0200 Subject: [PATCH 44/78] Added fallback to strtok on windows since strtok_s is not available on all windows platforms --- src/log/normal.c | 16 +++++++++++++--- src/log/tap.c | 17 ++++++++++------- 2 files changed, 23 insertions(+), 10 deletions(-) diff --git a/src/log/normal.c b/src/log/normal.c index f1a67d6..004c448 100644 --- a/src/log/normal.c +++ b/src/log/normal.c @@ -35,10 +35,11 @@ #include "i18n.h" #include "posix-compat.h" +#define USED __attribute__ ((used)) + #ifdef VANILLA_WIN32 -// provided by windows' libc implementation -char *strtok_s(char *strToken, const char *strDelimit, char **context); -# define strtok_r strtok_s +// fallback to strtok on windows since strtok_s is not available everywhere +# define strtok_r(str, delim, saveptr) strtok(str, delim) #endif typedef const char *const msg_t; @@ -151,8 +152,13 @@ void normal_log_assert(struct criterion_assert_stats *stats) { if (!stats->passed) { char *dup = strdup(*stats->message ? stats->message : stats->condition); + +#ifdef VANILLA_WIN32 + char *line = strtok(dup, "\n"); +#else char *saveptr = NULL; char *line = strtok_r(dup, "\n", &saveptr); +#endif criterion_pimportant(CRITERION_PREFIX_DASHES, _(msg_assert_fail), @@ -160,7 +166,11 @@ void normal_log_assert(struct criterion_assert_stats *stats) { FG_RED, stats->line, RESET, line); +#ifdef VANILLA_WIN32 + while ((line = strtok(NULL, "\n"))) +#else while ((line = strtok_r(NULL, "\n", &saveptr))) +#endif criterion_pimportant(CRITERION_PREFIX_DASHES, _(msg_desc), line); free(dup); } diff --git a/src/log/tap.c b/src/log/tap.c index 43768f7..e8a9d97 100644 --- a/src/log/tap.c +++ b/src/log/tap.c @@ -33,12 +33,6 @@ #include "config.h" #include "posix-compat.h" -#ifdef VANILLA_WIN32 -// provided by windows' libc implementation -char *strtok_s(char *strToken, const char *strDelimit, char **context); -# define strtok_r strtok_s -#endif - void tap_log_pre_all(struct criterion_test_set *set) { size_t enabled_count = 0; FOREACH_SET(struct criterion_suite_set *s, set->suites) { @@ -88,13 +82,22 @@ void tap_log_post_test(struct criterion_test_stats *stats) { stats->elapsed_time); for (struct criterion_assert_stats *asrt = stats->asserts; asrt; asrt = asrt->next) { if (!asrt->passed) { - char *dup = strdup(*asrt->message ? asrt->message : asrt->condition), *saveptr = NULL; + char *dup = strdup(*asrt->message ? asrt->message : asrt->condition); +#ifdef VANILLA_WIN32 + char *line = strtok(dup, "\n"); +#else + char *saveptr = NULL; char *line = strtok_r(dup, "\n", &saveptr); +#endif criterion_important(" %s:%u: Assertion failed: %s\n", asrt->file, asrt->line, line); +#ifdef VANILLA_WIN32 + while ((line = strtok(NULL, "\n"))) +#else while ((line = strtok_r(NULL, "\n", &saveptr))) +#endif criterion_important(" %s\n", line); free(dup); } From 9fa44c1b1c8fbcc84da2a7398cb0bf3e93d54ee0 Mon Sep 17 00:00:00 2001 From: Snaipe Date: Fri, 31 Jul 2015 09:06:32 +0200 Subject: [PATCH 45/78] Fixed libintl not being found in libc & made the test scripts call sh on windows --- .cmake/Modules/FindLibintl.cmake | 4 ++-- samples/CMakeLists.txt | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.cmake/Modules/FindLibintl.cmake b/.cmake/Modules/FindLibintl.cmake index dad2634..90c9d85 100644 --- a/.cmake/Modules/FindLibintl.cmake +++ b/.cmake/Modules/FindLibintl.cmake @@ -36,8 +36,8 @@ find_path(LIBINTL_INCLUDE_DIR libintl.h set(LIBINTL_LIB_FOUND FALSE) if(LIBINTL_INCLUDE_DIR) - include(CheckFunctionExists) - check_function_exists(dgettext LIBINTL_LIBC_HAS_DGETTEXT) + include(CheckSymbolExists) + check_symbol_exists(dgettext libintl.h LIBINTL_LIBC_HAS_DGETTEXT) if (LIBINTL_LIBC_HAS_DGETTEXT) set(LIBINTL_LIBRARIES) diff --git a/samples/CMakeLists.txt b/samples/CMakeLists.txt index ead99be..116c8a9 100644 --- a/samples/CMakeLists.txt +++ b/samples/CMakeLists.txt @@ -37,5 +37,5 @@ foreach(sample ${SAMPLES}) endforeach() foreach(script ${SCRIPTS}) - add_test(${script} ${CMAKE_CURRENT_LIST_DIR}/tests/${script}.sh) + add_test(${script} sh ${CMAKE_CURRENT_LIST_DIR}/tests/${script}.sh) endforeach() From 4901e8b0292ac7fe32770077359739ae1f646c67 Mon Sep 17 00:00:00 2001 From: Snaipe Date: Fri, 31 Jul 2015 09:48:47 +0200 Subject: [PATCH 46/78] Display after-failure test logs on CI scripts --- .travis.yml | 2 +- appveyor.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index b9bc2f5..8d5ebee 100644 --- a/.travis.yml +++ b/.travis.yml @@ -18,7 +18,7 @@ script: after_success: - make coveralls after_failure: -- cat $(find samples -iname '*.log') /dev/null +- cat build/Testing/Temporary/LastTest.log env: global: secure: bzZcWjdqoTgceC40kEBucx7NuWYJPk+rxgF3UJJDXi+ijQAFYPv70p5eVsGR6rfc+XgqXCxcUFQtuL4ZVt7QEfVk1ZOJITNeHbKIeKaEYS4nX8mFf+CBeEm9bJGZ04KiQJdJu5mzzAHvXbW7roGXDGWe1Bjnk5wwA+dNUCa7H04= diff --git a/appveyor.yml b/appveyor.yml index 2ade1ff..935ee58 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -31,7 +31,7 @@ build_script: - 'make' test_script: - - 'make test' + - 'make test || bash -lc "cat $APPVEYOR_BUILD_FOLDER/build/Testing/Temporary/LastTest.log"' after_test: - 'make coveralls' From 59e58360468722b4fcd54a6588d5c3e2096164df Mon Sep 17 00:00:00 2001 From: Snaipe Date: Fri, 31 Jul 2015 11:54:10 +0200 Subject: [PATCH 47/78] Fixed extmatch functionality always being ignored --- CMakeLists.txt | 1 + src/config.h.in | 1 + 2 files changed, 2 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 503d13e..4bce470 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -83,6 +83,7 @@ if (PCRE_FOUND) src/extmatch.c src/extmatch.h ) + set(HAVE_PCRE 1) endif () set(INTERFACE_FILES diff --git a/src/config.h.in b/src/config.h.in index 194430a..5928b0b 100644 --- a/src/config.h.in +++ b/src/config.h.in @@ -2,6 +2,7 @@ # define CONFIG_H_IN_ #cmakedefine ENABLE_NLS @ENABLE_NLS@ +#cmakedefine HAVE_PCRE @HAVE_PCRE@ # define LOCALEDIR "${LOCALEDIR}" # define PACKAGE "${PROJECT_NAME}" From e093954b5682b89d202e1515fd0bd3933be354ad Mon Sep 17 00:00:00 2001 From: Snaipe Date: Fri, 31 Jul 2015 12:01:02 +0200 Subject: [PATCH 48/78] Fixed typo in cmake tests & reordered configuration file generation to execute after option handling --- CMakeLists.txt | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 4bce470..c676d20 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -31,7 +31,7 @@ endif() find_package(Gettext) find_package(Libintl) -if (GETTEXT_FOUND AND Libintl_FOUND) +if (GETTEXT_FOUND AND LIBINTL_LIB_FOUND) include(GettextTranslate) add_subdirectory(po) set(ENABLE_NLS 1) @@ -43,13 +43,6 @@ CHECK_LIBRARY_EXISTS(rt clock_gettime "time.h" HAVE_CLOCK_GETTIME) find_package(PCRE) find_package(Libcsptr REQUIRED) -# Generate the configure file - -configure_file( - "${CMAKE_SOURCE_DIR}/src/config.h.in" - "${CMAKE_SOURCE_DIR}/src/config.h" -) - # List sources and headers set(SOURCE_FILES @@ -100,6 +93,13 @@ set(INTERFACE_FILES include/criterion/stats.h ) +# Generate the configure file + +configure_file( + "${CMAKE_SOURCE_DIR}/src/config.h.in" + "${CMAKE_SOURCE_DIR}/src/config.h" +) + include_directories(include src ${CSPTR_INCLUDE_DIRS}) add_library(criterion SHARED ${SOURCE_FILES} ${INTERFACE_FILES}) target_link_libraries(criterion ${CSPTR_LIBRARIES}) @@ -112,7 +112,7 @@ if (PCRE_FOUND) target_link_libraries(criterion ${PCRE_LIBRARIES}) endif() -if (LIBINTL_FOUND) +if (LIBINTL_LIB_FOUND) target_link_libraries(criterion ${LIBINTL_LIBRARIES}) endif() From 0d7033cfd5120b3340dfdf1acdba7bbe05d77d88 Mon Sep 17 00:00:00 2001 From: Snaipe Date: Sat, 1 Aug 2015 13:44:58 +0200 Subject: [PATCH 49/78] Made windows dynamically resolve the section limits at runtime --- include/criterion/types.h | 1 + src/posix-compat.c | 14 ++++++++++++++ src/posix-compat.h | 10 ++++++++++ src/report.c | 17 +++++++++-------- src/runner.h | 13 +++++++------ 5 files changed, 41 insertions(+), 14 deletions(-) diff --git a/include/criterion/types.h b/include/criterion/types.h index 6e7dae2..f508174 100644 --- a/include/criterion/types.h +++ b/include/criterion/types.h @@ -26,6 +26,7 @@ # include # include +# include "common.h" struct criterion_test_extra_data { int sentinel_; diff --git a/src/posix-compat.c b/src/posix-compat.c index 020d61f..21378aa 100644 --- a/src/posix-compat.c +++ b/src/posix-compat.c @@ -208,3 +208,17 @@ bool is_current_process(s_proc_handle *proc) { return proc->pid == getpid(); #endif } + +#ifdef VANILLA_WIN32 +void *get_win_section_start(const char *section) { + char symbol[64]; + sprintf(symbol, "g_%s_section_start", section); + return (void*) GetProcAddress(GetModuleHandle(NULL), symbol); +} + +void *get_win_section_end(const char *section) { + char symbol[64]; + sprintf(symbol, "g_%s_section_end", section); + return (void*) GetProcAddress(GetModuleHandle(NULL), symbol); +} +#endif diff --git a/src/posix-compat.h b/src/posix-compat.h index 477361e..3ad0525 100644 --- a/src/posix-compat.h +++ b/src/posix-compat.h @@ -53,4 +53,14 @@ void wait_process(s_proc_handle *handle, int *status); s_proc_handle *get_current_process(); bool is_current_process(s_proc_handle *proc); +# ifdef VANILLA_WIN32 +void *get_win_section_start(const char *section); +void *get_win_section_end(const char *section); +# define GET_SECTION_START(Name) get_win_section_start(Name) +# define GET_SECTION_END(Name) get_win_section_end(Name) +# else +# define GET_SECTION_START(Name) SECTION_START(Name) +# define GET_SECTION_END(Name) SECTION_END(Name) +# endif + #endif /* !POSIX_COMPAT_H_ */ diff --git a/src/report.c b/src/report.c index 59e3738..8bdab4d 100644 --- a/src/report.c +++ b/src/report.c @@ -31,19 +31,20 @@ #include "criterion/ordered-set.h" #include "report.h" #include "config.h" +#include "posix-compat.h" #ifdef HAVE_PCRE #include "extmatch.h" #endif -#define IMPL_CALL_REPORT_HOOKS(Kind) \ - IMPL_SECTION_LIMITS(f_report_hook, crit_ ## Kind); \ - void call_report_hooks_##Kind(void *data) { \ - for (f_report_hook *hook = SECTION_START(crit_ ## Kind); \ - hook < SECTION_END(crit_ ## Kind); \ - ++hook) { \ - (*hook)(data); \ - } \ +#define IMPL_CALL_REPORT_HOOKS(Kind) \ + IMPL_SECTION_LIMITS(f_report_hook, crit_ ## Kind); \ + void call_report_hooks_##Kind(void *data) { \ + for (f_report_hook *hook = GET_SECTION_START(crit_ ## Kind); \ + hook < GET_SECTION_END(crit_ ## Kind); \ + ++hook) { \ + (*hook)(data); \ + } \ } #define IMPL_REPORT_HOOK(Type) \ diff --git a/src/runner.h b/src/runner.h index 9cb4156..0d47b89 100644 --- a/src/runner.h +++ b/src/runner.h @@ -25,20 +25,21 @@ # define CRITERION_RUNNER_H_ # include "criterion/types.h" +# include "posix-compat.h" DECL_SECTION_LIMITS(struct criterion_test, criterion_tests); DECL_SECTION_LIMITS(struct criterion_suite, crit_suites); struct criterion_test_set *criterion_init(void); -# define FOREACH_TEST_SEC(Test) \ - for (struct criterion_test *Test = SECTION_START(criterion_tests); \ - Test < SECTION_END(criterion_tests); \ +# define FOREACH_TEST_SEC(Test) \ + for (struct criterion_test *Test = GET_SECTION_START(criterion_tests); \ + Test < GET_SECTION_END(criterion_tests); \ ++Test) -# define FOREACH_SUITE_SEC(Suite) \ - for (struct criterion_suite *Suite = SECTION_START(crit_suites); \ - Suite < SECTION_END(crit_suites); \ +# define FOREACH_SUITE_SEC(Suite) \ + for (struct criterion_suite *Suite = GET_SECTION_START(crit_suites); \ + Suite < GET_SECTION_END(crit_suites); \ ++Suite) #endif /* !CRITERION_RUNNER_H_ */ From 2fcb89c7ef211657c317663f2d01d57e480a3162 Mon Sep 17 00:00:00 2001 From: Snaipe Date: Sat, 1 Aug 2015 13:54:46 +0200 Subject: [PATCH 50/78] Fixed typo & added pointer cast for explicit comparison in section entry iterations --- src/posix-compat.h | 4 ++-- src/report.c | 2 +- src/runner.h | 8 ++++---- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/posix-compat.h b/src/posix-compat.h index 3ad0525..0ee7a57 100644 --- a/src/posix-compat.h +++ b/src/posix-compat.h @@ -56,8 +56,8 @@ bool is_current_process(s_proc_handle *proc); # ifdef VANILLA_WIN32 void *get_win_section_start(const char *section); void *get_win_section_end(const char *section); -# define GET_SECTION_START(Name) get_win_section_start(Name) -# define GET_SECTION_END(Name) get_win_section_end(Name) +# define GET_SECTION_START(Name) get_win_section_start(#Name) +# define GET_SECTION_END(Name) get_win_section_end(#Name) # else # define GET_SECTION_START(Name) SECTION_START(Name) # define GET_SECTION_END(Name) SECTION_END(Name) diff --git a/src/report.c b/src/report.c index 8bdab4d..f57758b 100644 --- a/src/report.c +++ b/src/report.c @@ -41,7 +41,7 @@ IMPL_SECTION_LIMITS(f_report_hook, crit_ ## Kind); \ void call_report_hooks_##Kind(void *data) { \ for (f_report_hook *hook = GET_SECTION_START(crit_ ## Kind); \ - hook < GET_SECTION_END(crit_ ## Kind); \ + hook < (f_report_hook*) GET_SECTION_END(crit_ ## Kind); \ ++hook) { \ (*hook)(data); \ } \ diff --git a/src/runner.h b/src/runner.h index 0d47b89..f021ee4 100644 --- a/src/runner.h +++ b/src/runner.h @@ -32,14 +32,14 @@ DECL_SECTION_LIMITS(struct criterion_suite, crit_suites); struct criterion_test_set *criterion_init(void); -# define FOREACH_TEST_SEC(Test) \ - for (struct criterion_test *Test = GET_SECTION_START(criterion_tests); \ - Test < GET_SECTION_END(criterion_tests); \ +# define FOREACH_TEST_SEC(Test) \ + for (struct criterion_test *Test = GET_SECTION_START(criterion_tests); \ + Test < (struct criterion_test*) GET_SECTION_END(criterion_tests); \ ++Test) # define FOREACH_SUITE_SEC(Suite) \ for (struct criterion_suite *Suite = GET_SECTION_START(crit_suites); \ - Suite < GET_SECTION_END(crit_suites); \ + Suite < (struct criterion_suite*) GET_SECTION_END(crit_suites); \ ++Suite) #endif /* !CRITERION_RUNNER_H_ */ From cb9e62ccf57a0f959a6ad7977613c263f93e77b3 Mon Sep 17 00:00:00 2001 From: Snaipe Date: Sat, 1 Aug 2015 17:26:18 +0200 Subject: [PATCH 51/78] Added logo to README --- README.md | 2 +- doc/criterion-title.png | Bin 0 -> 77874 bytes 2 files changed, 1 insertion(+), 1 deletion(-) create mode 100644 doc/criterion-title.png diff --git a/README.md b/README.md index 58b8369..79488f2 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ -Criterion +Criterion Logo ========= [![Build Status](https://travis-ci.org/Snaipe/Criterion.svg?branch=bleeding)](https://travis-ci.org/Snaipe/Criterion) diff --git a/doc/criterion-title.png b/doc/criterion-title.png new file mode 100644 index 0000000000000000000000000000000000000000..01d5bed35d481fa42be6ee3ce0f526123fbdde94 GIT binary patch literal 77874 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 uep3Vi+B|MrdC1@HYkdn&nj)4A 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%0Dh5d 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 literal 0 HcmV?d00001 From 9f974b248b08a2b5e8becbaa5f525e3cf684cb73 Mon Sep 17 00:00:00 2001 From: Snaipe Date: Sat, 1 Aug 2015 17:50:33 +0200 Subject: [PATCH 52/78] Added logo credits --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index 79488f2..f60bc3c 100644 --- a/README.md +++ b/README.md @@ -101,6 +101,10 @@ 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, and FreeBSD 10.0. Windows is currently not supported, but it being worked on. +## Credits + +Logo done by [Greehm](http://www.cargocollective.com/pbouigue) + [online-docs]: http://criterion.readthedocs.org/ [pdf-docs]: http://readthedocs.org/projects/criterion/downloads/pdf/latest/ [zip-docs]: http://readthedocs.org/projects/criterion/downloads/htmlzip/latest/ From 7dd294a4380e47e6a51ffaa5c54a7059cd2ed37d Mon Sep 17 00:00:00 2001 From: Snaipe Date: Mon, 3 Aug 2015 14:15:28 +0200 Subject: [PATCH 53/78] Moved logging out of report hooks since report hooks are overriden in the test executable --- src/report.c | 93 +++++++++++----------------------------------------- src/runner.c | 72 +++++++++++++++++++++++++++++++++------- 2 files changed, 80 insertions(+), 85 deletions(-) diff --git a/src/report.c b/src/report.c index 59e3738..92852da 100644 --- a/src/report.c +++ b/src/report.c @@ -32,10 +32,6 @@ #include "report.h" #include "config.h" -#ifdef HAVE_PCRE -#include "extmatch.h" -#endif - #define IMPL_CALL_REPORT_HOOKS(Kind) \ IMPL_SECTION_LIMITS(f_report_hook, crit_ ## Kind); \ void call_report_hooks_##Kind(void *data) { \ @@ -46,74 +42,25 @@ } \ } -#define IMPL_REPORT_HOOK(Type) \ - IMPL_CALL_REPORT_HOOKS(Type); \ - ReportHook(Type) +IMPL_CALL_REPORT_HOOKS(PRE_ALL); +IMPL_CALL_REPORT_HOOKS(PRE_SUITE); +IMPL_CALL_REPORT_HOOKS(PRE_INIT); +IMPL_CALL_REPORT_HOOKS(PRE_TEST); +IMPL_CALL_REPORT_HOOKS(ASSERT); +IMPL_CALL_REPORT_HOOKS(TEST_CRASH); +IMPL_CALL_REPORT_HOOKS(POST_TEST); +IMPL_CALL_REPORT_HOOKS(POST_FINI); +IMPL_CALL_REPORT_HOOKS(POST_SUITE); +IMPL_CALL_REPORT_HOOKS(POST_ALL); -__attribute__((always_inline)) -static inline void nothing() {} +ReportHook(PRE_ALL)() {} +ReportHook(PRE_SUITE)() {} +ReportHook(PRE_INIT)() {} +ReportHook(PRE_TEST)() {} +ReportHook(ASSERT)() {} +ReportHook(TEST_CRASH)() {} +ReportHook(POST_TEST)() {} +ReportHook(POST_FINI)() {} +ReportHook(POST_SUITE)() {} +ReportHook(POST_ALL)() {} -#ifdef HAVE_PCRE -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) { - const char *errmsg; - int ret = extmatch(criterion_options.pattern, test->data->identifier_, &errmsg); - if (ret == -10) { - printf("pattern error: %s\n", errmsg); - exit(1); - } else if (ret < 0) { - test->data->disabled = true; - } - } - } -} -#endif - -IMPL_REPORT_HOOK(PRE_ALL)(struct criterion_test_set *set) { -#ifdef HAVE_PCRE - if (criterion_options.pattern) { - disable_unmatching(set); - } -#endif - log(pre_all, set); -} - -IMPL_REPORT_HOOK(PRE_SUITE)(struct criterion_suite_set *set) { - log(pre_suite, set); -} - -IMPL_REPORT_HOOK(PRE_INIT)(struct criterion_test *test) { - log(pre_init, test); -} - -IMPL_REPORT_HOOK(PRE_TEST)(struct criterion_test *test) { - log(pre_test, test); -} - -IMPL_REPORT_HOOK(ASSERT)(struct criterion_assert_stats *stats) { - log(assert, stats); -} - -IMPL_REPORT_HOOK(TEST_CRASH)(struct criterion_test_stats *stats) { - log(test_crash, stats); -} - -IMPL_REPORT_HOOK(POST_TEST)(struct criterion_test_stats *stats) { - log(post_test, stats); -} - -IMPL_REPORT_HOOK(POST_FINI)(struct criterion_test_stats *stats) { - log(post_fini, stats); -} - -IMPL_REPORT_HOOK(POST_SUITE)(struct criterion_suite_stats *stats) { - log(post_suite, stats); -} - -IMPL_REPORT_HOOK(POST_ALL)(struct criterion_global_stats *stats) { - log(post_all, stats); -} diff --git a/src/runner.c b/src/runner.c index b19ea48..408554f 100644 --- a/src/runner.c +++ b/src/runner.c @@ -27,6 +27,7 @@ #include "criterion/criterion.h" #include "criterion/options.h" #include "criterion/ordered-set.h" +#include "criterion/logging.h" #include "stats.h" #include "runner.h" #include "report.h" @@ -36,6 +37,10 @@ #include "posix-compat.h" #include "abort.h" +#ifdef HAVE_PCRE +#include "extmatch.h" +#endif + IMPL_SECTION_LIMITS(struct criterion_test, criterion_tests); IMPL_SECTION_LIMITS(struct criterion_suite, crit_suites); @@ -43,6 +48,9 @@ IMPL_SECTION_LIMITS(struct criterion_suite, crit_suites); TestSuite(); Test(,) {}; +__attribute__ ((always_inline)) +static inline void nothing() {} + int cmp_suite(void *a, void *b) { struct criterion_suite *s1 = a, *s2 = b; return strcmp(s1->name, s2->name); @@ -109,6 +117,7 @@ static void map_tests(struct criterion_test_set *set, continue; report(PRE_SUITE, s); + log(pre_suite, s); smart struct criterion_suite_stats *suite_stats = suite_stats_init(&s->suite); @@ -124,12 +133,10 @@ static void map_tests(struct criterion_test_set *set, } report(POST_SUITE, suite_stats); + log(post_suite, suite_stats); } } -__attribute__ ((always_inline)) -static inline void nothing() {} - static void run_test_child(struct criterion_test *test, struct criterion_suite *suite) { @@ -197,15 +204,27 @@ static void run_test(struct criterion_global_stats *stats, 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); - test_started = true; - break; - case ASSERT: report(ASSERT, ev->data); break; - case POST_TEST: report(POST_TEST, test_stats); - normal_finish = true; - break; - case POST_FINI: report(POST_FINI, test_stats); break; + case PRE_INIT: + report(PRE_INIT, test); break; + log(pre_init, test); + case PRE_TEST: + report(PRE_TEST, test); + log(pre_test, test); + test_started = true; + break; + case ASSERT: + report(ASSERT, ev->data); + log(assert, ev->data); + break; + case POST_TEST: + report(POST_TEST, test_stats); + log(post_test, test_stats); + normal_finish = true; + break; + case POST_FINI: + report(POST_FINI, test_stats); + log(post_fini, test_stats); + break; } sfree(ev); } @@ -225,21 +244,49 @@ static void run_test(struct criterion_global_stats *stats, test_stats->signal = status.status; if (test->data->signal == 0) { push_event(TEST_CRASH); + log(test_crash, test_stats); } else { double elapsed_time = 0; push_event(POST_TEST, .data = &elapsed_time); + log(post_test, test_stats); push_event(POST_FINI); + log(post_fini, test_stats); } } } +#ifdef HAVE_PCRE +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) { + const char *errmsg; + int ret = extmatch(criterion_options.pattern, test->data->identifier_, &errmsg); + if (ret == -10) { + printf("pattern error: %s\n", errmsg); + exit(1); + } else if (ret < 0) { + test->data->disabled = true; + } + } + } +} +#endif + 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(); +#ifdef HAVE_PCRE + if (criterion_options.pattern) + disable_unmatching(set); +#endif report(PRE_ALL, set); + log(pre_all, set); smart struct criterion_global_stats *stats = stats_init(); map_tests(set, stats, run_test); @@ -248,6 +295,7 @@ static int criterion_run_all_tests_impl(void) { return -1; report(POST_ALL, stats); + log(post_all, stats); return stats->tests_failed == 0; } From 9aa9be0a4189f76b95dae3f8d31be73f7197d15a Mon Sep 17 00:00:00 2001 From: Snaipe Date: Mon, 3 Aug 2015 14:25:53 +0200 Subject: [PATCH 54/78] Added tentative to retrieve the sections from the PE header --- src/posix-compat.c | 32 ++++++++++++++++++++++++++------ 1 file changed, 26 insertions(+), 6 deletions(-) diff --git a/src/posix-compat.c b/src/posix-compat.c index 21378aa..34516d6 100644 --- a/src/posix-compat.c +++ b/src/posix-compat.c @@ -211,14 +211,34 @@ bool is_current_process(s_proc_handle *proc) { #ifdef VANILLA_WIN32 void *get_win_section_start(const char *section) { - char symbol[64]; - sprintf(symbol, "g_%s_section_start", section); - return (void*) GetProcAddress(GetModuleHandle(NULL), symbol); + PIMAGE_DOS_HEADER dosHeader = (PIMAGE_DOS_HEADER) GetModuleHandle(NULL); + PIMAGE_NT_HEADERS ntHeader = ntHeader = (PIMAGE_NT_HEADERS) ((DWORD)(dosHeader) + (dosHeader->e_lfanew)); + + assert(dosHeader->e_magic == IMAGE_DOS_SIGNATURE); + assert(ntHeader->Signature == IMAGE_NT_SIGNATURE); + + PIMAGE_SECTION_HEADER pSecHeader = IMAGE_FIRST_SECTION(ntHeader); + for(int i = 0; i < ntHeader->FileHeader.NumberOfSections; i++, pSecHeader++) { + if (!strcmp(pSecHeader->Name, section)) { + return (void*) pSecHeader->VirtualAddress; + } + } + return NULL; } void *get_win_section_end(const char *section) { - char symbol[64]; - sprintf(symbol, "g_%s_section_end", section); - return (void*) GetProcAddress(GetModuleHandle(NULL), symbol); + PIMAGE_DOS_HEADER dosHeader = (PIMAGE_DOS_HEADER) GetModuleHandle(NULL); + PIMAGE_NT_HEADERS ntHeader = ntHeader = (PIMAGE_NT_HEADERS) ((DWORD)(dosHeader) + (dosHeader->e_lfanew)); + + assert(dosHeader->e_magic == IMAGE_DOS_SIGNATURE); + assert(ntHeader->Signature == IMAGE_NT_SIGNATURE); + + PIMAGE_SECTION_HEADER pSecHeader = IMAGE_FIRST_SECTION(ntHeader); + for(int i = 0; i < ntHeader->FileHeader.NumberOfSections; i++, pSecHeader++) { + if (!strcmp(pSecHeader->Name, section)) { + return (char*) pSecHeader->VirtualAddress + pSecHeader->SizeOfRawData); + } + } + return NULL; } #endif From 86762f8ff7295fc4a8bac1a29d74a3f1172f47bb Mon Sep 17 00:00:00 2001 From: Snaipe Date: Mon, 3 Aug 2015 15:15:48 +0200 Subject: [PATCH 55/78] Fixed windows code for section retrieving and changed section names to fit under 8 bytes. --- include/criterion/criterion.h | 4 ++-- include/criterion/hooks.h | 20 +++++++++++++++++++- src/posix-compat.c | 6 +++--- src/report.c | 16 ++++++++-------- src/report.h | 4 ++-- src/runner.c | 4 ++-- src/runner.h | 16 ++++++++-------- 7 files changed, 44 insertions(+), 26 deletions(-) diff --git a/include/criterion/criterion.h b/include/criterion/criterion.h index 48b3dcf..50c85b2 100644 --- a/include/criterion/criterion.h +++ b/include/criterion/criterion.h @@ -22,7 +22,7 @@ .line_ = __LINE__, \ __VA_ARGS__ \ }; \ - SECTION_("criterion_tests") \ + SECTION_("cr_tst") \ const struct criterion_test IDENTIFIER_(Category, Name, meta) = { \ .name = #Name, \ .category = #Category, \ @@ -38,7 +38,7 @@ .line_ = 0, \ __VA_ARGS__ \ }; \ - SECTION_("crit_suites") \ + SECTION_("cr_sts") \ const struct criterion_suite SUITE_IDENTIFIER_(Name, meta) = { \ .name = #Name, \ .data = &SUITE_IDENTIFIER_(Name, extra), \ diff --git a/include/criterion/hooks.h b/include/criterion/hooks.h index a8b7bfa..c597467 100644 --- a/include/criterion/hooks.h +++ b/include/criterion/hooks.h @@ -48,9 +48,27 @@ typedef void (*f_report_hook)(); # define HOOK_PROTOTYPE_ \ void HOOK_IDENTIFIER_(impl) +// Section abbreviations +# define HOOK_SECTION_PRE_ALL cr_pra +# define HOOK_SECTION_PRE_SUITE cr_prs +# define HOOK_SECTION_PRE_INIT cr_pri +# define HOOK_SECTION_PRE_TEST cr_prt +# define HOOK_SECTION_ASSERT cr_ast +# define HOOK_SECTION_TEST_CRASH cr_tsc +# define HOOK_SECTION_POST_TEST cr_pot +# define HOOK_SECTION_POST_FINI cr_pof +# define HOOK_SECTION_POST_SUITE cr_pos +# define HOOK_SECTION_POST_ALL cr_poa + +# define HOOK_SECTION(Kind) HOOK_SECTION_ ## Kind + +# define HOOK_SECTION_STRINGIFY__(Sec) #Sec +# define HOOK_SECTION_STRINGIFY_(Sec) HOOK_SECTION_STRINGIFY__(Sec) +# define HOOK_SECTION_STRINGIFY(Kind) HOOK_SECTION_STRINGIFY_(HOOK_SECTION(Kind)) + # define ReportHook(Kind) \ HOOK_PROTOTYPE_(); \ - SECTION_("crit_" #Kind) \ + SECTION_(HOOK_SECTION_STRINGIFY(Kind)) \ const f_report_hook HOOK_IDENTIFIER_(func) = HOOK_IDENTIFIER_(impl); \ HOOK_PROTOTYPE_ diff --git a/src/posix-compat.c b/src/posix-compat.c index 34516d6..8759d32 100644 --- a/src/posix-compat.c +++ b/src/posix-compat.c @@ -219,7 +219,7 @@ void *get_win_section_start(const char *section) { PIMAGE_SECTION_HEADER pSecHeader = IMAGE_FIRST_SECTION(ntHeader); for(int i = 0; i < ntHeader->FileHeader.NumberOfSections; i++, pSecHeader++) { - if (!strcmp(pSecHeader->Name, section)) { + if (!strncmp(pSecHeader->Name, section, 8)) { return (void*) pSecHeader->VirtualAddress; } } @@ -235,8 +235,8 @@ void *get_win_section_end(const char *section) { PIMAGE_SECTION_HEADER pSecHeader = IMAGE_FIRST_SECTION(ntHeader); for(int i = 0; i < ntHeader->FileHeader.NumberOfSections; i++, pSecHeader++) { - if (!strcmp(pSecHeader->Name, section)) { - return (char*) pSecHeader->VirtualAddress + pSecHeader->SizeOfRawData); + if (!strncmp(pSecHeader->Name, section, 8)) { + return (char*) pSecHeader->VirtualAddress + pSecHeader->SizeOfRawData; } } return NULL; diff --git a/src/report.c b/src/report.c index f57758b..a55994a 100644 --- a/src/report.c +++ b/src/report.c @@ -37,14 +37,14 @@ #include "extmatch.h" #endif -#define IMPL_CALL_REPORT_HOOKS(Kind) \ - IMPL_SECTION_LIMITS(f_report_hook, crit_ ## Kind); \ - void call_report_hooks_##Kind(void *data) { \ - for (f_report_hook *hook = GET_SECTION_START(crit_ ## Kind); \ - hook < (f_report_hook*) GET_SECTION_END(crit_ ## Kind); \ - ++hook) { \ - (*hook)(data); \ - } \ +#define IMPL_CALL_REPORT_HOOKS(Kind) \ + IMPL_SECTION_LIMITS(f_report_hook, HOOK_SECTION(Kind)); \ + void call_report_hooks_##Kind(void *data) { \ + for (f_report_hook *hook = GET_SECTION_START(HOOK_SECTION(Kind)); \ + hook < (f_report_hook*) GET_SECTION_END(HOOK_SECTION(Kind)); \ + ++hook) { \ + (*hook)(data); \ + } \ } #define IMPL_REPORT_HOOK(Type) \ diff --git a/src/report.h b/src/report.h index 6a740c5..aab2a10 100644 --- a/src/report.h +++ b/src/report.h @@ -28,8 +28,8 @@ # define report(Kind, Data) call_report_hooks_##Kind(Data) -# define DECL_CALL_REPORT_HOOKS(Kind) \ - DECL_SECTION_LIMITS(f_report_hook, crit_ ## Kind); \ +# define DECL_CALL_REPORT_HOOKS(Kind) \ + DECL_SECTION_LIMITS(f_report_hook, HOOK_SECTION(Kind)); \ void call_report_hooks_##Kind(void *data) DECL_CALL_REPORT_HOOKS(PRE_ALL); diff --git a/src/runner.c b/src/runner.c index b19ea48..0136952 100644 --- a/src/runner.c +++ b/src/runner.c @@ -36,8 +36,8 @@ #include "posix-compat.h" #include "abort.h" -IMPL_SECTION_LIMITS(struct criterion_test, criterion_tests); -IMPL_SECTION_LIMITS(struct criterion_suite, crit_suites); +IMPL_SECTION_LIMITS(struct criterion_test, cr_tst); +IMPL_SECTION_LIMITS(struct criterion_suite, cr_sts); // This is here to make the test suite & test sections non-empty TestSuite(); diff --git a/src/runner.h b/src/runner.h index f021ee4..e78fd96 100644 --- a/src/runner.h +++ b/src/runner.h @@ -27,19 +27,19 @@ # include "criterion/types.h" # include "posix-compat.h" -DECL_SECTION_LIMITS(struct criterion_test, criterion_tests); -DECL_SECTION_LIMITS(struct criterion_suite, crit_suites); +DECL_SECTION_LIMITS(struct criterion_test, cr_tst); +DECL_SECTION_LIMITS(struct criterion_suite, cr_sts); struct criterion_test_set *criterion_init(void); -# define FOREACH_TEST_SEC(Test) \ - for (struct criterion_test *Test = GET_SECTION_START(criterion_tests); \ - Test < (struct criterion_test*) GET_SECTION_END(criterion_tests); \ +# define FOREACH_TEST_SEC(Test) \ + for (struct criterion_test *Test = GET_SECTION_START(cr_tst); \ + Test < (struct criterion_test*) GET_SECTION_END(cr_tst); \ ++Test) -# define FOREACH_SUITE_SEC(Suite) \ - for (struct criterion_suite *Suite = GET_SECTION_START(crit_suites); \ - Suite < (struct criterion_suite*) GET_SECTION_END(crit_suites); \ +# define FOREACH_SUITE_SEC(Suite) \ + for (struct criterion_suite *Suite = GET_SECTION_START(cr_sts); \ + Suite < (struct criterion_suite*) GET_SECTION_END(cr_sts); \ ++Suite) #endif /* !CRITERION_RUNNER_H_ */ From 567e4731a7f3248172d2176a49e8e4427e64f9b7 Mon Sep 17 00:00:00 2001 From: Snaipe Date: Mon, 3 Aug 2015 15:37:12 +0200 Subject: [PATCH 56/78] Fixed section iteration crashing on padding entries & typos --- src/posix-compat.c | 9 +++++---- src/runner.c | 6 ++++++ 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/src/posix-compat.c b/src/posix-compat.c index 8759d32..1c21709 100644 --- a/src/posix-compat.c +++ b/src/posix-compat.c @@ -1,3 +1,4 @@ +#include #include "posix-compat.h" #include "process.h" @@ -219,8 +220,8 @@ void *get_win_section_start(const char *section) { PIMAGE_SECTION_HEADER pSecHeader = IMAGE_FIRST_SECTION(ntHeader); for(int i = 0; i < ntHeader->FileHeader.NumberOfSections; i++, pSecHeader++) { - if (!strncmp(pSecHeader->Name, section, 8)) { - return (void*) pSecHeader->VirtualAddress; + if (!strncmp((char*) pSecHeader->Name, section, 8)) { + return (char*) dosHeader + pSecHeader->VirtualAddress; } } return NULL; @@ -235,8 +236,8 @@ void *get_win_section_end(const char *section) { PIMAGE_SECTION_HEADER pSecHeader = IMAGE_FIRST_SECTION(ntHeader); for(int i = 0; i < ntHeader->FileHeader.NumberOfSections; i++, pSecHeader++) { - if (!strncmp(pSecHeader->Name, section, 8)) { - return (char*) pSecHeader->VirtualAddress + pSecHeader->SizeOfRawData; + if (!strncmp((char*) pSecHeader->Name, section, 8)) { + return (char*) dosHeader + (size_t) pSecHeader->VirtualAddress + pSecHeader->SizeOfRawData; } } return NULL; diff --git a/src/runner.c b/src/runner.c index 0136952..f3b6dec 100644 --- a/src/runner.c +++ b/src/runner.c @@ -67,6 +67,9 @@ struct criterion_test_set *criterion_init(void) { struct criterion_ordered_set *suites = new_ordered_set(cmp_suite, dtor_suite_set); FOREACH_SUITE_SEC(s) { + if (!s->name) + break; + struct criterion_suite_set css = { .suite = *s, }; @@ -75,6 +78,9 @@ struct criterion_test_set *criterion_init(void) { size_t nb_tests = 0; FOREACH_TEST_SEC(test) { + if (!test->category) + break; + if (!*test->category) continue; From 0b74a5a279783ab4387670084c89011734120b4b Mon Sep 17 00:00:00 2001 From: Snaipe Date: Tue, 4 Aug 2015 11:07:43 +0200 Subject: [PATCH 57/78] Switched context copy to shared memory since the library's memory space is not initialized on a newly created process --- src/posix-compat.c | 116 +++++++++++++++++++++++++++++++++------------ 1 file changed, 85 insertions(+), 31 deletions(-) diff --git a/src/posix-compat.c b/src/posix-compat.c index 1c21709..71641f1 100644 --- a/src/posix-compat.c +++ b/src/posix-compat.c @@ -56,19 +56,53 @@ struct pipe_handle { struct worker_context g_worker_context = {.test = NULL}; #ifdef VANILLA_WIN32 -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; +struct full_context { + struct worker_context ctx; + struct criterion_test test; + struct criterion_test_extra_data test_data; + struct criterion_suite suite; + struct criterion_test_extra_data suite_data; + struct pipe_handle pipe; + int resumed; +}; + +static TCHAR g_mapping_name[] = TEXT("WinCriterionWorker"); +#define MAPPING_SIZE sizeof (struct full_context) + +static struct full_context local_ctx; #endif int resume_child(void) { - if (g_worker_context.test) { - run_worker(&g_worker_context); - return 1; - } +#ifdef VANILLA_WIN32 + HANDLE sharedMem = OpenFileMapping( + FILE_MAP_ALL_ACCESS, + FALSE, + g_mapping_name); + + if (sharedMem == NULL) + return 0; + + struct full_context *ctx = (struct full_context *) MapViewOfFile(sharedMem, + FILE_MAP_ALL_ACCESS, + 0, + 0, + MAPPING_SIZE); + + if (ctx == NULL) + exit(-1); + + local_ctx = *ctx; + g_worker_context = local_ctx.worker_context; + ctx.resumed = 1; + + UmapViewOfFile(ctx); + CloseHandle(sharedMem); + + run_worker(&g_worker_context); + return 1; +#else return 0; +#endif } s_proc_handle *fork_process() { @@ -86,37 +120,57 @@ s_proc_handle *fork_process() { return (void *) -1; // Copy context over - f_worker_func child_func = g_worker_context.func; + HANDLE sharedMem = CreateFileMapping( + INVALID_HANDLE_VALUE, + NULL, + PAGE_READWRITE, + 0, + MAPPING_SIZE, + g_mapping_name) - 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; + if (sharedMem == NULL) + return (void *) -1; - g_worker_context = (struct worker_context) { - &child_test, - &child_suite, - child_func, - &child_pipe - }; + struct full_context *ctx = (struct full_context *) MapViewOfFile(sharedMem, + FILE_MAP_ALL_ACCESS, + 0, + 0, + MAPPING_SIZE); - 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; - WRITE_PROCESS_(info.hProcess, child_suite_data, sizeof (child_suite_data)); + if (ctx == NULL) { + CloseHandle(sharedMem); + return (void *) -1; } - 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)); + *ctx = (struc full_context) { + .test = *g_worker_context.test; + .test_data = *g_worker_context.test->data; + .suite = *g_worker_context.suite; + .pipe = *g_worker_context.pipe; + }; + + ctx.ctx = (struct worker_context) { + &ctx.test, + &ctx.suite, + g_worker_context.func, + &ctx.pipe + }; + + ctx.test.data = &ctx.test_data; + + if (g_worker_context.suite->data) { + ctx.suite_data = *g_worker_context.suite->data; + ctx.suite.data = &ctx.suite_data; + } ResumeThread(info.hThread); CloseHandle(info.hThread); + while (!ctx.resumed); // wait until the child has initialized itself + + UmapViewOfFile(ctx); + CloseHandle(sharedMem); + return unique_ptr(s_proc_handle, { info.hProcess }); #else pid_t pid = fork(); From b0200e8e41c55e833ec2f7d7ece67d1cdca16513 Mon Sep 17 00:00:00 2001 From: Snaipe Date: Tue, 4 Aug 2015 04:29:11 -0700 Subject: [PATCH 58/78] Fixed some typos --- src/posix-compat.c | 50 +++++++++++++++++++++++----------------------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/src/posix-compat.c b/src/posix-compat.c index 71641f1..d756c9a 100644 --- a/src/posix-compat.c +++ b/src/posix-compat.c @@ -57,11 +57,11 @@ struct worker_context g_worker_context = {.test = NULL}; #ifdef VANILLA_WIN32 struct full_context { - struct worker_context ctx; struct criterion_test test; struct criterion_test_extra_data test_data; struct criterion_suite suite; struct criterion_test_extra_data suite_data; + f_worker_func func; struct pipe_handle pipe; int resumed; }; @@ -92,10 +92,19 @@ int resume_child(void) { exit(-1); local_ctx = *ctx; - g_worker_context = local_ctx.worker_context; - ctx.resumed = 1; + g_worker_context = (struct worker_context) { + &local_ctx.test, + &local_ctx.suite, + local_ctx.func, + &local_ctx.pipe + }; - UmapViewOfFile(ctx); + local_ctx.test.data = &local_ctx.test_data; + local_ctx.suite.data = &local_ctx.suite_data; + + ctx->resumed = 1; + + UnmapViewOfFile(ctx); CloseHandle(sharedMem); run_worker(&g_worker_context); @@ -126,7 +135,7 @@ s_proc_handle *fork_process() { PAGE_READWRITE, 0, MAPPING_SIZE, - g_mapping_name) + g_mapping_name); if (sharedMem == NULL) return (void *) -1; @@ -142,33 +151,24 @@ s_proc_handle *fork_process() { return (void *) -1; } - *ctx = (struc full_context) { - .test = *g_worker_context.test; - .test_data = *g_worker_context.test->data; - .suite = *g_worker_context.suite; - .pipe = *g_worker_context.pipe; + *ctx = (struct full_context) { + .test = *g_worker_context.test, + .test_data = *g_worker_context.test->data, + .suite = *g_worker_context.suite, + .func = g_worker_context.func, + .pipe = *g_worker_context.pipe, + .resumed = 0, }; - ctx.ctx = (struct worker_context) { - &ctx.test, - &ctx.suite, - g_worker_context.func, - &ctx.pipe - }; - - ctx.test.data = &ctx.test_data; - - if (g_worker_context.suite->data) { - ctx.suite_data = *g_worker_context.suite->data; - ctx.suite.data = &ctx.suite_data; - } + if (g_worker_context.suite->data) + ctx->suite_data = *g_worker_context.suite->data; ResumeThread(info.hThread); CloseHandle(info.hThread); - while (!ctx.resumed); // wait until the child has initialized itself + while (!ctx->resumed); // wait until the child has initialized itself - UmapViewOfFile(ctx); + UnmapViewOfFile(ctx); CloseHandle(sharedMem); return unique_ptr(s_proc_handle, { info.hProcess }); From 5608711a0057363a21aac64eed2528734be2bcef Mon Sep 17 00:00:00 2001 From: Snaipe Date: Tue, 4 Aug 2015 15:02:04 +0200 Subject: [PATCH 59/78] Fixed output on windows --- src/log/logging.c | 6 +++++- src/log/normal.c | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/log/logging.c b/src/log/logging.c index 623b2a9..b527e71 100644 --- a/src/log/logging.c +++ b/src/log/logging.c @@ -29,7 +29,11 @@ #include "criterion/options.h" #include "i18n.h" -#define LOG_FORMAT "[%1$s%2$s%3$s] %4$s" +#ifdef ENABLE_NLS +# define LOG_FORMAT "[%1$s%2$s%3$s] %4$s" +#else +# define LOG_FORMAT "[%s%s%s] %s" +#endif const struct criterion_prefix_data g_criterion_logging_prefixes[] = { [CRITERION_LOGGING_PREFIX_DASHES] = { "----", CRIT_FG_BLUE }, diff --git a/src/log/normal.c b/src/log/normal.c index 004c448..ff83888 100644 --- a/src/log/normal.c +++ b/src/log/normal.c @@ -47,7 +47,7 @@ typedef const char *const msg_t; static msg_t msg_pre_all = "Criterion v%s\n"; static msg_t msg_desc = " %s\n"; -#if ENABLE_NLS +#ifdef ENABLE_NLS static msg_t msg_pre_init = "%1$s::%2$s\n"; static msg_t msg_post_test_timed = "%1$s::%2$s: (%3$3.2fs)\n"; static msg_t msg_post_test = "%1$s::%2$s\n"; From 051e97b96a046444b32794de3c03c29743de7c74 Mon Sep 17 00:00:00 2001 From: Snaipe Date: Tue, 4 Aug 2015 15:02:33 +0200 Subject: [PATCH 60/78] Added basic SEH-to-signal translator in posix compatibility layer --- src/posix-compat.c | 37 ++++++++++++++++++++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/src/posix-compat.c b/src/posix-compat.c index d756c9a..108fe71 100644 --- a/src/posix-compat.c +++ b/src/posix-compat.c @@ -107,6 +107,8 @@ int resume_child(void) { UnmapViewOfFile(ctx); CloseHandle(sharedMem); + SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX); + run_worker(&g_worker_context); return 1; #else @@ -188,7 +190,40 @@ void wait_process(s_proc_handle *handle, int *status) { DWORD exit_code; GetExitCodeProcess(handle->handle, &exit_code); CloseHandle(handle->handle); - *status = exit_code << 8; + + int sig = 0; + switch (exit_code) { + case STATUS_FLOAT_DENORMAL_OPERAND: + case STATUS_FLOAT_DIVIDE_BY_ZERO: + case STATUS_FLOAT_INEXACT_RESULT: + case STATUS_FLOAT_INVALID_OPERATION: + case STATUS_FLOAT_OVERFLOW: + case STATUS_FLOAT_STACK_CHECK: + case STATUS_FLOAT_UNDERFLOW: + case STATUS_INTEGER_DIVIDE_BY_ZERO: + case STATUS_INTEGER_OVERFLOW: sig = SIGFPE; break; + + case STATUS_ILLEGAL_INSTRUCTION: + case STATUS_PRIVILEGED_INSTRUCTION: + case STATUS_NONCONTINUABLE_EXCEPTION: sig = SIGILL; break; + + case STATUS_TIMEOUT: sig = SIGALRM; break; + + case STATUS_ACCESS_VIOLATION: + case STATUS_DATATYPE_MISALIGNMENT: + case STATUS_ARRAY_BOUNDS_EXCEEDED: + case STATUS_GUARD_PAGE_VIOLATION: + case STATUS_IN_PAGE_ERROR: + case STATUS_NO_MEMORY: + case STATUS_INVALID_DISPOSITION: + case STATUS_STACK_OVERFLOW: sig = SIGSEGV; break; + + case STATUS_CONTROL_C_EXIT: sig = SIGINT; break; + + default: break; + } + + *status = sig ? sig : exit_code << 8; #else waitpid(handle->pid, status, 0); #endif From 1feeca65ce23aaf6646c2d29820012ef23406144 Mon Sep 17 00:00:00 2001 From: Snaipe Date: Tue, 4 Aug 2015 15:18:39 +0200 Subject: [PATCH 61/78] Fixed signal handling on windows --- samples/signal.c | 5 +++-- src/posix-compat.c | 7 ++++++- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/samples/signal.c b/samples/signal.c index 1cda5d9..9dcc99d 100644 --- a/samples/signal.c +++ b/samples/signal.c @@ -8,8 +8,9 @@ Test(simple, caught, .signal = SIGSEGV) { *i = 42; } -Test(simple, wrong_signal, .signal = SIGSEGV) { - raise(SIGINT); +Test(simple, wrong_signal, .signal = SIGINT) { + int *i = NULL; + *i = 42; } Test(simple, uncaught) { diff --git a/src/posix-compat.c b/src/posix-compat.c index 108fe71..72afb91 100644 --- a/src/posix-compat.c +++ b/src/posix-compat.c @@ -28,6 +28,11 @@ # define WRITE_PROCESS_(Proc, What, Size) \ WriteProcessMemory(Proc, &What, &What, Size, NULL); +# include +# ifndef SIGALRM +# define SIGALRM 14 +# endif + #else # include # include @@ -191,7 +196,7 @@ void wait_process(s_proc_handle *handle, int *status) { GetExitCodeProcess(handle->handle, &exit_code); CloseHandle(handle->handle); - int sig = 0; + unsigned int sig = 0; switch (exit_code) { case STATUS_FLOAT_DENORMAL_OPERAND: case STATUS_FLOAT_DIVIDE_BY_ZERO: From 0d1210a24dbaa6559ce9421d87cce4cc1aec469b Mon Sep 17 00:00:00 2001 From: Snaipe Date: Tue, 4 Aug 2015 15:36:50 +0200 Subject: [PATCH 62/78] Fixed typo disabling pre_init logging --- src/runner.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/runner.c b/src/runner.c index db95f9f..6891515 100644 --- a/src/runner.c +++ b/src/runner.c @@ -211,8 +211,9 @@ static void run_test(struct criterion_global_stats *stats, stat_push_event(stats, suite_stats, test_stats, ev); switch (ev->kind) { case PRE_INIT: - report(PRE_INIT, test); break; + report(PRE_INIT, test); log(pre_init, test); + break; case PRE_TEST: report(PRE_TEST, test); log(pre_test, test); From 6518f277da169e608a2eb6e5c1d64766f3c05b79 Mon Sep 17 00:00:00 2001 From: Snaipe Date: Tue, 4 Aug 2015 15:48:48 +0200 Subject: [PATCH 63/78] Fixed after_failure command on travis build --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 8d5ebee..be127b7 100644 --- a/.travis.yml +++ b/.travis.yml @@ -18,7 +18,7 @@ script: after_success: - make coveralls after_failure: -- cat build/Testing/Temporary/LastTest.log +- cat Testing/Temporary/LastTest.log env: global: secure: bzZcWjdqoTgceC40kEBucx7NuWYJPk+rxgF3UJJDXi+ijQAFYPv70p5eVsGR6rfc+XgqXCxcUFQtuL4ZVt7QEfVk1ZOJITNeHbKIeKaEYS4nX8mFf+CBeEm9bJGZ04KiQJdJu5mzzAHvXbW7roGXDGWe1Bjnk5wwA+dNUCa7H04= From 0e59711ecacc66a07a09be6a72c3f99a97da2c6f Mon Sep 17 00:00:00 2001 From: Snaipe Date: Tue, 4 Aug 2015 15:50:13 +0200 Subject: [PATCH 64/78] Made all test scripts always succeed on assertion failure --- .travis.yml | 2 +- samples/CMakeLists.txt | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index be127b7..010eab6 100644 --- a/.travis.yml +++ b/.travis.yml @@ -14,7 +14,7 @@ before_install: - export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$HOME/lib - export CFLAGS="-g -O0" script: -- mkdir -p build && cd $_ && cmake -DCOVERALLS=ON -DCMAKE_BUILD_TYPE=Debug -DCMAKE_PREFIX_PATH=$HOME .. && make && make -C samples test +- mkdir -p build && cd $_ && cmake -DCOVERALLS=ON -DCMAKE_BUILD_TYPE=Debug -DCMAKE_PREFIX_PATH=$HOME .. && make && make test after_success: - make coveralls after_failure: diff --git a/samples/CMakeLists.txt b/samples/CMakeLists.txt index 116c8a9..206c049 100644 --- a/samples/CMakeLists.txt +++ b/samples/CMakeLists.txt @@ -38,4 +38,7 @@ endforeach() foreach(script ${SCRIPTS}) add_test(${script} sh ${CMAKE_CURRENT_LIST_DIR}/tests/${script}.sh) + set_property(TEST ${script} PROPERTY + ENVIRONMENT "CRITERION_ALWAYS_SUCCEED=1" + ) endforeach() From ac3044b86ef81ed73c6b8cb98967c9d036d2dead Mon Sep 17 00:00:00 2001 From: Snaipe Date: Tue, 4 Aug 2015 16:25:35 +0200 Subject: [PATCH 65/78] Added missing config.h to runner.c, fixed --pattern not working --- src/runner.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/runner.c b/src/runner.c index 6891515..a35a57c 100644 --- a/src/runner.c +++ b/src/runner.c @@ -36,6 +36,7 @@ #include "timer.h" #include "posix-compat.h" #include "abort.h" +#include "config.h" #ifdef HAVE_PCRE #include "extmatch.h" From 8761c094f3516fcbe11779c8568433b149643846 Mon Sep 17 00:00:00 2001 From: Snaipe Date: Tue, 4 Aug 2015 16:34:10 +0200 Subject: [PATCH 66/78] Fixed libcsptr.dll not being found on appveyor CI --- appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index 935ee58..7cfbc0b 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -4,7 +4,7 @@ os: Windows Server 2012 init: - git config --global core.autocrlf input - - 'SET PATH=%PATH%;C:\MinGW\msys\1.0\bin;C:\MinGW\bin' + - 'SET PATH=%PATH%;C:\MinGW\msys\1.0\bin;C:\MinGW\bin;%APPVEYOR_BUILD_FOLDER%\lib' environment: COVERALLS_TOKEN: From 6ba2497b5432eb8c7433c247970bd473ccef81dc Mon Sep 17 00:00:00 2001 From: Snaipe Date: Tue, 4 Aug 2015 17:07:29 +0200 Subject: [PATCH 67/78] Added runtime destination for windows cmake install rule --- CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index c676d20..7fe8c7f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -122,6 +122,7 @@ endif() install(FILES ${INTERFACE_FILES} DESTINATION include/criterion) install(TARGETS criterion + RUNTIME DESTINATION bin LIBRARY DESTINATION lib ARCHIVE DESTINATION lib ) From b21519bd92ab2e453b9c06c0ae649cd605c6a8c4 Mon Sep 17 00:00:00 2001 From: Snaipe Date: Tue, 4 Aug 2015 17:14:29 +0200 Subject: [PATCH 68/78] Fixed appveyor library path --- appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index 7cfbc0b..8f59b2a 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -4,7 +4,7 @@ os: Windows Server 2012 init: - git config --global core.autocrlf input - - 'SET PATH=%PATH%;C:\MinGW\msys\1.0\bin;C:\MinGW\bin;%APPVEYOR_BUILD_FOLDER%\lib' + - 'SET PATH=%PATH%;C:\MinGW\msys\1.0\bin;C:\MinGW\bin;%APPVEYOR_BUILD_FOLDER%\bin' environment: COVERALLS_TOKEN: From 71a9fdf67c8b9b74837d308dd0fb82b4ae783ac1 Mon Sep 17 00:00:00 2001 From: Snaipe Date: Tue, 4 Aug 2015 17:53:48 +0200 Subject: [PATCH 69/78] Added more pattern tests --- samples/tests/pattern.sh | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/samples/tests/pattern.sh b/samples/tests/pattern.sh index c44e812..3d2a505 100755 --- a/samples/tests/pattern.sh +++ b/samples/tests/pattern.sh @@ -1,2 +1,7 @@ #!/bin/sh ./simple --pattern '*/passing' +./simple --pattern '!(*/passing)' +./simple --pattern '[pf]a@(ss|il)ing' +./simple --pattern '@(+(nest)ed))' +./simple --pattern '?(*(a|b))' +./simple --pattern '?(malformed' From d07ad6a1491f5d8b137e414f01ce573b4bb14416 Mon Sep 17 00:00:00 2001 From: Snaipe Date: Tue, 4 Aug 2015 18:20:06 +0200 Subject: [PATCH 70/78] Added more tests and fixed some border-case errors on the extglob translator --- samples/tests/pattern.sh | 7 +++++-- src/extmatch.c | 12 +++++++++--- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/samples/tests/pattern.sh b/samples/tests/pattern.sh index 3d2a505..09996f1 100755 --- a/samples/tests/pattern.sh +++ b/samples/tests/pattern.sh @@ -1,7 +1,10 @@ -#!/bin/sh +#!/bin/sh -e ./simple --pattern '*/passing' ./simple --pattern '!(*/passing)' ./simple --pattern '[pf]a@(ss|il)ing' ./simple --pattern '@(+(nest)ed))' ./simple --pattern '?(*(a|b))' -./simple --pattern '?(malformed' +! ./simple --pattern '?(malformed' +./simple --pattern '[!azerty]assing' +./simple --pattern '|pipe' +./simple --pattern '\!(escaped' diff --git a/src/extmatch.c b/src/extmatch.c index f03154d..205a148 100644 --- a/src/extmatch.c +++ b/src/extmatch.c @@ -13,7 +13,7 @@ struct context { char old, cur; int eos; const char **errmsg; - jmp_buf jmp; + jmp_buf *jmp; }; void transform_impl(struct context *ctx); @@ -25,6 +25,8 @@ static inline void transform_rec(struct context *ctx) { .src = ctx->src, .old = ctx->old, .eos = ctx->eos, + .errmsg = ctx->errmsg, + .jmp = ctx->jmp, }; transform_impl(&new_ctx); ctx->dst = new_ctx.dst; @@ -154,6 +156,8 @@ void transform_impl(struct context *ctx) { ['('] = escape_char, [')'] = escape_char, ['|'] = escape_pipe, + + [255] = NULL, }; for (char c = read_char(ctx); !ctx->eos; c = read_char(ctx)) { f_handler handler = handlers[(unsigned char) c]; @@ -171,17 +175,19 @@ void transform_impl(struct context *ctx) { } if (ctx->depth > 0) { *ctx->errmsg = "mismatching parenthesis"; - longjmp(ctx->jmp, -1); // abort operation + longjmp(*ctx->jmp, -1); // abort operation } } static int transform(const char *pattern, char *result, const char **errmsg) { + jmp_buf jmp; struct context ctx = { .src = pattern, .dst = result, .errmsg = errmsg, + .jmp = &jmp, }; - if (!setjmp(ctx.jmp)) { + if (!setjmp(*ctx.jmp)) { copy_char(&ctx, '^'); transform_impl(&ctx); copy_char(&ctx, '$'); From 4a7b1f75cd7e4990695ae65735674e25f88890a7 Mon Sep 17 00:00:00 2001 From: Snaipe Date: Tue, 4 Aug 2015 18:34:51 +0200 Subject: [PATCH 71/78] Added build folder to appveyor path --- appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index 8f59b2a..73c6439 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -4,7 +4,7 @@ os: Windows Server 2012 init: - git config --global core.autocrlf input - - 'SET PATH=%PATH%;C:\MinGW\msys\1.0\bin;C:\MinGW\bin;%APPVEYOR_BUILD_FOLDER%\bin' + - 'SET PATH=%PATH%;C:\MinGW\msys\1.0\bin;C:\MinGW\bin;%APPVEYOR_BUILD_FOLDER%\bin;%APPVEYOR_BUILD_FOLDER%\build' environment: COVERALLS_TOKEN: From fdca157049342d1eb57ef7cf87620b175766ec3c Mon Sep 17 00:00:00 2001 From: Snaipe Date: Tue, 4 Aug 2015 18:55:59 +0200 Subject: [PATCH 72/78] Added coverage reports on appveyor --- appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index 73c6439..30ba460 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -25,7 +25,7 @@ install: - 'set LOCAL_INSTALL=%APPVEYOR_BUILD_FOLDER%' - 'bash -lc "cd $APPVEYOR_BUILD_FOLDER; exec 0 Date: Tue, 4 Aug 2015 11:47:12 -0700 Subject: [PATCH 73/78] Fixed coveralls cmake module to handle windows paths --- .cmake/Modules/CoverallsGenerateGcov.cmake | 1 + 1 file changed, 1 insertion(+) diff --git a/.cmake/Modules/CoverallsGenerateGcov.cmake b/.cmake/Modules/CoverallsGenerateGcov.cmake index fced087..429b695 100644 --- a/.cmake/Modules/CoverallsGenerateGcov.cmake +++ b/.cmake/Modules/CoverallsGenerateGcov.cmake @@ -166,6 +166,7 @@ macro(get_source_path_from_gcov_filename _SRC_FILENAME _GCOV_FILENAME) # #path#to#project#root#subdir#the_file.c.gcov -> /path/to/project/root/subdir/the_file.c string(REGEX REPLACE "\\.gcov$" "" SRC_FILENAME_TMP ${_GCOV_FILENAME_WEXT}) string(REGEX REPLACE "\#" "/" SRC_FILENAME_TMP ${SRC_FILENAME_TMP}) + string(REGEX REPLACE "~" ":" SRC_FILENAME_TMP ${SRC_FILENAME_TMP}) set(${_SRC_FILENAME} "${SRC_FILENAME_TMP}") endmacro() From 689d14428ebcb31d6814e75e2ec99918214a7ca4 Mon Sep 17 00:00:00 2001 From: Snaipe Date: Wed, 5 Aug 2015 05:48:15 +0200 Subject: [PATCH 74/78] Fixed coveralls token environment variable naming --- appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index 30ba460..614a37a 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -7,7 +7,7 @@ init: - 'SET PATH=%PATH%;C:\MinGW\msys\1.0\bin;C:\MinGW\bin;%APPVEYOR_BUILD_FOLDER%\bin;%APPVEYOR_BUILD_FOLDER%\build' environment: - COVERALLS_TOKEN: + COVERALLS_REPO_TOKEN: secure: 5nuCg+faxFPeppoNNcSwVobswAVFUf8ut83vw8CX/4W2y0kZkGmwEfCUxSQWiQDU clone_depth: 5 From 2a2a93e639e34485d69dfe66be1fba5b170cee3c Mon Sep 17 00:00:00 2001 From: Snaipe Date: Wed, 5 Aug 2015 05:51:48 +0200 Subject: [PATCH 75/78] Fixed readme versions & added windows support back --- README.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index f60bc3c..4182cf2 100644 --- a/README.md +++ b/README.md @@ -31,13 +31,14 @@ 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, and Mac OS X (Windows is currenly not completely supported). +* [x] Runs on Linux, FreeBSD, Mac OS X, and Windows (Compiling with MinGW GCC). ## Downloads -* [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) -* [FreeBSD (x86_64)](https://github.com/Snaipe/Criterion/releases/download/v1.2.0/criterion-1.2.0-freebsd-x86_64.tar.bz2) +* [Linux (x86_64)](https://github.com/Snaipe/Criterion/releases/download/v1.2.2/criterion-1.2.2-linux-x86_64.tar.bz2) +* [OS X (x86_64)](https://github.com/Snaipe/Criterion/releases/download/v1.2.2/criterion-1.2.2-osx-x86_64.tar.bz2) +* [FreeBSD (x86_64)](https://github.com/Snaipe/Criterion/releases/download/v1.2.2/criterion-1.2.2-freebsd-x86_64.tar.bz2) +* [Windows (x86_64)](https://github.com/Snaipe/Criterion/releases/download/v1.2.2/criterion-1.2.2-windows-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) @@ -98,8 +99,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, and FreeBSD 10.0. - Windows is currently not supported, but it being worked on. + most \*nix systems; Mac OS X Yosemite 10.10, FreeBSD 10.0, Windows 7 and 2K. ## Credits From e115417f667689c57ca241af6c4622ff2968d629 Mon Sep 17 00:00:00 2001 From: Snaipe Date: Wed, 5 Aug 2015 05:54:16 +0200 Subject: [PATCH 76/78] Updated documentation on windows support --- doc/intro.rst | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/doc/intro.rst b/doc/intro.rst index 3341d0f..e2a1125 100644 --- a/doc/intro.rst +++ b/doc/intro.rst @@ -27,6 +27,5 @@ Features reported and tested. * Progress and statistics can be followed in real time with report hooks. * TAP output format can be enabled with an option. -* Runs on Linux, FreeBSD, Mac OS X, and Windows (compiles only with Cygwin - for the moment). +* Runs on Linux, FreeBSD, Mac OS X, and Windows (Compiling with MinGW GCC). * xUnit framework structure From dafe456c3163a3051a169c46392c73bf7458990a Mon Sep 17 00:00:00 2001 From: Snaipe Date: Wed, 5 Aug 2015 06:18:26 +0200 Subject: [PATCH 77/78] Updated documentation for signals on windows --- doc/starter.rst | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/doc/starter.rst b/doc/starter.rst index a85bfed..106c7d1 100644 --- a/doc/starter.rst +++ b/doc/starter.rst @@ -147,7 +147,34 @@ is received: *ptr = 42; } -This feature will of course not work on Windows. +This feature will also work (to some extent) on Windows for the +following signals on some exceptions: + +======== ===================================================================== +Signal Triggered by +======== ===================================================================== +SIGSEGV STATUS_ACCESS_VIOLATION, STATUS_DATATYPE_MISALIGNMENT, + STATUS_ARRAY_BOUNDS_EXCEEDED, STATUS_GUARD_PAGE_VIOLATION, + STATUS_IN_PAGE_ERROR, STATUS_NO_MEMORY, STATUS_INVALID_DISPOSITION, + STATUS_STACK_OVERFLOW +-------- --------------------------------------------------------------------- +SIGILL STATUS_ILLEGAL_INSTRUCTION, STATUS_PRIVILEGED_INSTRUCTION, + STATUS_NONCONTINUABLE_EXCEPTION +-------- --------------------------------------------------------------------- +SIGINT STATUS_CONTROL_C_EXIT +-------- --------------------------------------------------------------------- +SIGFPE STATUS_FLOAT_DENORMAL_OPERAND, STATUS_FLOAT_DIVIDE_BY_ZERO, + STATUS_FLOAT_INEXACT_RESULT, STATUS_FLOAT_INVALID_OPERATION, + STATUS_FLOAT_OVERFLOW, STATUS_FLOAT_STACK_CHECK, + STATUS_FLOAT_UNDERFLOW, STATUS_INTEGER_DIVIDE_BY_ZERO, + STATUS_INTEGER_OVERFLOW +-------- --------------------------------------------------------------------- +SIGALRM STATUS_TIMEOUT +======== ===================================================================== + +See the `windows exception reference`_ for more details on each exception. + +.. _windows exception reference: https://msdn.microsoft.com/en-us/library/windows/desktop/ms679356(v=vs.85).aspx Configuration reference ~~~~~~~~~~~~~~~~~~~~~~~ From 7ba60586bf4fe00392638a3d90103bd066c17e5d Mon Sep 17 00:00:00 2001 From: Snaipe Date: Wed, 5 Aug 2015 06:26:12 +0200 Subject: [PATCH 78/78] Updated version numbers and setup steps in documentation --- .bumpversion.cfg | 2 ++ README.md | 8 ++++---- doc/setup.rst | 9 +++++---- 3 files changed, 11 insertions(+), 8 deletions(-) diff --git a/.bumpversion.cfg b/.bumpversion.cfg index 6ea2abb..e8f1054 100644 --- a/.bumpversion.cfg +++ b/.bumpversion.cfg @@ -8,3 +8,5 @@ commit = True [bumpversion:file:appveyor.yml] +[bumpversion:file:README.md] + diff --git a/README.md b/README.md index 4182cf2..d58d453 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.2.2/criterion-1.2.2-linux-x86_64.tar.bz2) -* [OS X (x86_64)](https://github.com/Snaipe/Criterion/releases/download/v1.2.2/criterion-1.2.2-osx-x86_64.tar.bz2) -* [FreeBSD (x86_64)](https://github.com/Snaipe/Criterion/releases/download/v1.2.2/criterion-1.2.2-freebsd-x86_64.tar.bz2) -* [Windows (x86_64)](https://github.com/Snaipe/Criterion/releases/download/v1.2.2/criterion-1.2.2-windows-x86_64.tar.bz2) +* [Linux (x86_64)](https://github.com/Snaipe/Criterion/releases/download/v1.2.3/criterion-1.2.3-linux-x86_64.tar.bz2) +* [OS X (x86_64)](https://github.com/Snaipe/Criterion/releases/download/v1.2.3/criterion-1.2.3-osx-x86_64.tar.bz2) +* [FreeBSD (x86_64)](https://github.com/Snaipe/Criterion/releases/download/v1.2.3/criterion-1.2.3-freebsd-x86_64.tar.bz2) +* [Windows (x86_64)](https://github.com/Snaipe/Criterion/releases/download/v1.2.3/criterion-1.2.3-windows-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/doc/setup.rst b/doc/setup.rst index 0182ec0..507fc81 100644 --- a/doc/setup.rst +++ b/doc/setup.rst @@ -6,7 +6,7 @@ Prerequisites Currently, this library only works under \*nix systems. -To compile the static library and its dependencies, GCC 4.9+ is needed. +To compile the static library and its dependencies, GCC 4.6+ is needed. To use the static library, any GNU-C compatible compiler will suffice (GCC, Clang/LLVM, ICC, MinGW-GCC, ...). @@ -16,9 +16,10 @@ Installation .. code-block:: bash - $ git clone https://github.com/Snaipe/Criterion.git - $ cd Criterion - $ ./autogen.sh && ./configure && make && sudo make install + $ git clone https://github.com/Snaipe/Criterion.git && cd Criterion + $ LOCAL_INSTALL=/usr .ci/install-libcsptr.sh + $ mkdir build && cd $_ && cmake -DCMAKE_INSTALL_PATH=/usr .. + $ make && sudo make install Usage -----