[Issue #12] Merge branch 'features/i18n' into bleeding

This commit is contained in:
Snaipe 2015-04-06 19:28:25 +02:00
commit ef2ea42c1a
15 changed files with 329 additions and 67 deletions

1
.gitignore vendored
View file

@ -7,6 +7,7 @@
!*.h
!*.rst
!samples/tests/*.sh
!*.po
!LICENSE
!HEADER

View file

@ -4,7 +4,7 @@ compiler:
before_install:
- sudo add-apt-repository ppa:ubuntu-toolchain-r/test -y
- sudo apt-get -qq update
- sudo apt-get -qq install -y check gcc-4.9
- sudo apt-get -qq install -y check gcc-4.9 gettext autopoint
- sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-4.9 90
- sudo pip install cpp-coveralls
script:

View file

@ -1,5 +1,6 @@
ACLOCAL_AMFLAGS = -I m4
SUBDIRS = dependencies/csptr samples
AM_CPPFLAGS = -DLOCALEDIR='"$(localedir)"'
SUBDIRS = po dependencies/csptr samples
lib_LTLIBRARIES = libcriterion.la
@ -19,7 +20,7 @@ libcriterion_la_LDFLAGS = $(COVERAGE_LDFLAGS)
# dirty but unless someone has a better alternative...
libcriterion_la_LIBADD = dependencies/csptr/src/libcsptr_la-*.lo
EXTRA_DIST = LICENSE
EXTRA_DIST = config.rpath LICENSE
subdirincludedir = $(includedir)/criterion/
subdirinclude_HEADERS = \
@ -51,6 +52,8 @@ libcriterion_la_SOURCES = \
src/options.c \
src/timer.c \
src/timer.h \
src/i18n.c \
src/i18n.h \
src/ordered-set.c \
src/posix-compat.c \
src/main.c

View file

@ -1,3 +1,4 @@
#!/bin/sh
git submodule update --init --recursive
autopoint
autoreconf -i

View file

@ -22,6 +22,9 @@ AC_SUBST([LIBTOOL_DEPS])
AC_FUNC_FNMATCH
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])],
@ -33,7 +36,7 @@ AC_ARG_ENABLE([gcov],
[])
AC_CONFIG_HEADERS([src/config.h])
AC_CONFIG_FILES([Makefile samples/Makefile])
AC_CONFIG_FILES([Makefile samples/Makefile po/Makefile.in])
AC_CONFIG_SUBDIRS([dependencies/csptr])

View file

@ -25,6 +25,7 @@
# define CRITERION_LOGGING_H_
# include <stdbool.h>
# include <stdarg.h>
# include "common.h"
# include "ordered-set.h"
# include "stats.h"
@ -34,12 +35,61 @@ enum criterion_logging_level {
CRITERION_IMPORTANT,
};
enum criterion_logging_prefix {
CRITERION_LOGGING_PREFIX_DASHES,
CRITERION_LOGGING_PREFIX_EQUALS,
CRITERION_LOGGING_PREFIX_RUN,
CRITERION_LOGGING_PREFIX_SKIP,
CRITERION_LOGGING_PREFIX_PASS,
CRITERION_LOGGING_PREFIX_FAIL,
};
struct criterion_prefix_data {
const char *prefix;
const char *color;
};
# ifdef CRITERION_LOGGING_COLORS
# define CRIT_COLOR_NORMALIZE(Str) (criterion_options.use_ascii ? "" : Str)
# define CRIT_FG_BOLD "\e[0;1m"
# define CRIT_FG_RED "\e[0;31m"
# define CRIT_FG_GREEN "\e[0;32m"
# define CRIT_FG_GOLD "\e[0;33m"
# define CRIT_FG_BLUE "\e[0;34m"
# define CRIT_RESET "\e[0m"
# define FG_BOLD CRIT_COLOR_NORMALIZE(CRIT_FG_BOLD)
# define FG_RED CRIT_COLOR_NORMALIZE(CRIT_FG_RED)
# define FG_GREEN CRIT_COLOR_NORMALIZE(CRIT_FG_GREEN)
# define FG_GOLD CRIT_COLOR_NORMALIZE(CRIT_FG_GOLD)
# define FG_BLUE CRIT_COLOR_NORMALIZE(CRIT_FG_BLUE)
# define RESET CRIT_COLOR_NORMALIZE(CRIT_RESET)
# endif
extern const struct criterion_prefix_data g_criterion_logging_prefixes[];
# define CRITERION_PREFIX_DASHES (&g_criterion_logging_prefixes[CRITERION_LOGGING_PREFIX_DASHES])
# define CRITERION_PREFIX_EQUALS (&g_criterion_logging_prefixes[CRITERION_LOGGING_PREFIX_EQUALS])
# define CRITERION_PREFIX_RUN (&g_criterion_logging_prefixes[CRITERION_LOGGING_PREFIX_RUN ])
# define CRITERION_PREFIX_SKIP (&g_criterion_logging_prefixes[CRITERION_LOGGING_PREFIX_SKIP ])
# define CRITERION_PREFIX_PASS (&g_criterion_logging_prefixes[CRITERION_LOGGING_PREFIX_PASS ])
# define CRITERION_PREFIX_FAIL (&g_criterion_logging_prefixes[CRITERION_LOGGING_PREFIX_EQUALS])
void criterion_vlog(enum criterion_logging_level level, const char *msg, va_list args);
FORMAT(printf, 3, 4)
void criterion_plog(enum criterion_logging_level level, const struct criterion_prefix_data *prefix, const char *msg, ...);
FORMAT(printf, 2, 3)
void criterion_log(enum criterion_logging_level level, const char *msg, ...);
# define criterion_info(...) criterion_log(CRITERION_INFO, __VA_ARGS__)
# define criterion_important(...) criterion_log(CRITERION_IMPORTANT, __VA_ARGS__)
# define criterion_pinfo(...) criterion_plog(CRITERION_INFO, __VA_ARGS__)
# define criterion_pimportant(...) criterion_plog(CRITERION_IMPORTANT, __VA_ARGS__)
struct criterion_output_provider {
void (*log_pre_all )(struct criterion_test_set *set);
void (*log_pre_suite )(struct criterion_suite_set *set);

1
po/LINGUAS Normal file
View file

@ -0,0 +1 @@
fr

78
po/Makevars Normal file
View file

@ -0,0 +1,78 @@
# Makefile variables for PO directory in any package using GNU gettext.
# Usually the message domain is the same as the package name.
DOMAIN = $(PACKAGE)
# These two variables depend on the location of this directory.
subdir = po
top_builddir = ..
# These options get passed to xgettext.
XGETTEXT_OPTIONS = --keyword=_ --keyword=N_
# This is the copyright holder that gets inserted into the header of the
# $(DOMAIN).pot file. Set this to the copyright holder of the surrounding
# package. (Note that the msgstr strings, extracted from the package's
# sources, belong to the copyright holder of the package.) Translators are
# expected to transfer the copyright for their translations to this person
# or entity, or to disclaim their copyright. The empty string stands for
# the public domain; in this case the translators are expected to disclaim
# their copyright.
COPYRIGHT_HOLDER = Franklin "Snaipe" Mathieu
# This tells whether or not to prepend "GNU " prefix to the package
# name that gets inserted into the header of the $(DOMAIN).pot file.
# Possible values are "yes", "no", or empty. If it is empty, try to
# detect it automatically by scanning the files in $(top_srcdir) for
# "GNU packagename" string.
PACKAGE_GNU = no
# This is the email address or URL to which the translators shall report
# bugs in the untranslated strings:
# - Strings which are not entire sentences, see the maintainer guidelines
# in the GNU gettext documentation, section 'Preparing Strings'.
# - Strings which use unclear terms or require additional context to be
# understood.
# - Strings which make invalid assumptions about notation of date, time or
# money.
# - Pluralisation problems.
# - Incorrect English spelling.
# - Incorrect formatting.
# It can be your email address, or a mailing list address where translators
# can write to without being subscribed, or the URL of a web page through
# which the translators can contact you.
MSGID_BUGS_ADDRESS =
# This is the list of locale categories, beyond LC_MESSAGES, for which the
# message catalogs shall be used. It is usually empty.
EXTRA_LOCALE_CATEGORIES =
# This tells whether the $(DOMAIN).pot file contains messages with an 'msgctxt'
# context. Possible values are "yes" and "no". Set this to yes if the
# package uses functions taking also a message context, like pgettext(), or
# if in $(XGETTEXT_OPTIONS) you define keywords with a context argument.
USE_MSGCTXT = no
# These options get passed to msgmerge.
# Useful options are in particular:
# --previous to keep previous msgids of translated messages,
# --quiet to reduce the verbosity.
MSGMERGE_OPTIONS =
# These options get passed to msginit.
# If you want to disable line wrapping when writing PO files, add
# --no-wrap to MSGMERGE_OPTIONS, XGETTEXT_OPTIONS, and
# MSGINIT_OPTIONS.
MSGINIT_OPTIONS =
# This tells whether or not to regenerate a PO file when $(DOMAIN).pot
# has changed. Possible values are "yes" and "no". Set this to no if
# the POT file is checked in the repository and the version control
# program ignores timestamps.
PO_DEPENDS_ON_POT = yes
# This tells whether or not to forcibly update $(DOMAIN).pot and
# regenerate PO files on "make dist". Possible values are "yes" and
# "no". Set this to no if the POT file and PO files are maintained
# externally.
DIST_DEPENDS_ON_UPDATE_PO = yes

2
po/POTFILES.in Normal file
View file

@ -0,0 +1,2 @@
# List of source files which contain translatable strings.
src/log/normal.c

68
po/fr.po Normal file
View file

@ -0,0 +1,68 @@
# French translations for criterion package
# Traductions françaises du paquet criterion.
# Copyright (C) 2015 Franklin "Snaipe" Mathieu
# This file is distributed under the same license as the criterion package.
# <franklinmathieu@gmail.com>, 2015.
#
msgid ""
msgstr ""
"Project-Id-Version: criterion 1.0.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-04-03 17:57+0200\n"
"PO-Revision-Date: 2015-04-03 17:58+0200\n"
"Last-Translator: <franklinmathieu@gmail.com>\n"
"Language-Team: French\n"
"Language: fr\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
#: src/log/normal.c:38
#, c-format
msgid "Criterion v%s\n"
msgstr "Criterion v%s\n"
#: src/log/normal.c:42
#, c-format
msgid "%1$s::%2$s\n"
msgstr "%1$s::%2$s\n"
#: src/log/normal.c:68
#, c-format
msgid "%1$s::%2$s: Test is disabled\n"
msgstr "%1$s::%2$s: Le test est désactivé\n"
#: src/log/normal.c:69
#, c-format
msgid "%1$s::%2$s: Suite is disabled\n"
msgstr "%1$s::%2$s: La suite est désactivée\n"
#: src/log/normal.c:80
#, c-format
msgid ""
"%1$sSynthesis: Tested: %2$s%3$lu%4$s | Passing: %5$s%6$lu%7$s | Failing: %8$s"
"%9$lu%10$s | Crashing: %11$s%12$lu%13$s %14$s\n"
msgstr ""
"%1$sSynthèse: Testés: %2$s%3$lu%4$s | Validés: %5$s%6$lu%7$s | Échoués: %8$s"
"%9$lu%10$s | Plantages: %11$s%12$lu%13$s %14$s\n"
#: src/log/normal.c:99
#, c-format
msgid "%1$s%2$s%3$s:%4$s%5$d%6$s: Assertion failed: %7$s\n"
msgstr "%1$s%2$s%3$s:%4$s%5$d%6$s: Échec d'assertion: %7$s\n"
#: src/log/normal.c:105
#, c-format
msgid " %s\n"
msgstr " %s\n"
#: src/log/normal.c:112
#, c-format
msgid "%1$s%2$s%3$s:%4$s%5$u%6$s: Unexpected signal caught below this line!\n"
msgstr "%1$s%2$s%3$s:%4$s%5$u%6$s: Un signal inattendu a été reçu après cette ligne!\n"
#: src/log/normal.c:116
#, c-format
msgid "%1$s::%2$s: CRASH!\n"
msgstr "%1$s::%2$s: PLANTAGE!\n"

8
src/i18n.c Normal file
View file

@ -0,0 +1,8 @@
#include "i18n.h"
#ifdef I18N
__attribute__ ((constructor))
void init_i18n(void) {
bindtextdomain (PACKAGE, LOCALEDIR);
}
#endif

15
src/i18n.h Normal file
View file

@ -0,0 +1,15 @@
#ifndef I18N_H_
# define I18N_H_
# include "config.h"
# ifndef I18N
# define _(String) String
# define _s(String, Plural, Quantity) ((Quantity) == 1 ? String : Plural)
# else
# include <libintl.h>
# define _(String) dgettext(PACKAGE, String)
# define _s(String, Plural, Quantity) dngettext(PACKAGE, String, Plural, (Quantity))
# endif
#endif /* !I18N_H_ */

View file

@ -21,18 +21,54 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#define CRITERION_LOGGING_COLORS
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include "criterion/logging.h"
#include "criterion/options.h"
#include "i18n.h"
void criterion_log(enum criterion_logging_level level, const char *msg, ...) {
#define LOG_FORMAT "[%1$s%2$s%3$s] %4$s"
const struct criterion_prefix_data g_criterion_logging_prefixes[] = {
[CRITERION_LOGGING_PREFIX_DASHES] = { "----", CRIT_FG_BLUE },
[CRITERION_LOGGING_PREFIX_EQUALS] = { "====", CRIT_FG_BLUE },
[CRITERION_LOGGING_PREFIX_RUN] = { "RUN ", CRIT_FG_BLUE },
[CRITERION_LOGGING_PREFIX_SKIP] = { "SKIP", CRIT_FG_GOLD },
[CRITERION_LOGGING_PREFIX_PASS] = { "PASS", CRIT_FG_GREEN },
[CRITERION_LOGGING_PREFIX_FAIL] = { "FAIL", CRIT_FG_RED },
{ NULL }
};
void criterion_plog(enum criterion_logging_level level, const struct criterion_prefix_data *prefix, const char *msg, ...) {
va_list args;
if (level < criterion_options.logging_threshold)
return;
char formatted_msg[1024];
va_start(args, msg);
vfprintf(stderr, msg, args);
vsnprintf(formatted_msg, sizeof formatted_msg, msg, args);
va_end(args);
fprintf(stderr, _(LOG_FORMAT),
CRIT_COLOR_NORMALIZE(prefix->color),
prefix->prefix,
RESET,
formatted_msg);
}
void criterion_log(enum criterion_logging_level level, const char *msg, ...) {
va_list args;
va_start(args, msg);
criterion_vlog(level, msg, args);
va_end(args);
}
void criterion_vlog(enum criterion_logging_level level, const char *msg, va_list args) {
if (level < criterion_options.logging_threshold)
return;
vfprintf(stderr, msg, args);
}

View file

@ -22,6 +22,7 @@
* THE SOFTWARE.
*/
#define _GNU_SOURCE
#define CRITERION_LOGGING_COLORS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@ -31,34 +32,27 @@
#include "criterion/ordered-set.h"
#include "timer.h"
#include "config.h"
#define NORMALIZE(Str) (criterion_options.use_ascii ? "" : Str)
#define FG_BOLD NORMALIZE("\e[0;1m")
#define FG_RED NORMALIZE("\e[0;31m")
#define FG_GREEN NORMALIZE("\e[0;32m")
#define FG_GOLD NORMALIZE("\e[0;33m")
#define FG_BLUE NORMALIZE("\e[0;34m")
#define RESET NORMALIZE("\e[0m")
#include "i18n.h"
void normal_log_pre_all(UNUSED struct criterion_test_set *set) {
criterion_info("[%s====%s] Criterion v%s\n", FG_BLUE, RESET, VERSION);
criterion_pinfo(CRITERION_PREFIX_DASHES, _("Criterion v%s\n"), VERSION);
}
void normal_log_pre_init(struct criterion_test *test) {
criterion_info("[%sRUN%s ] %s::%s\n", FG_BLUE, RESET, test->category, test->name);
criterion_pinfo(CRITERION_PREFIX_RUN, _("%1$s::%2$s\n"), test->category, test->name);
if (test->data->description)
criterion_info("[%s----%s] %s\n", FG_BLUE, RESET, test->data->description);
criterion_pinfo(CRITERION_PREFIX_RUN, _(" %s\n"), test->data->description);
}
void normal_log_post_test(struct criterion_test_stats *stats) {
const char *format = can_measure_time() ? "%s::%s: (%3.2fs)\n" : "%s::%s\n";
const enum criterion_logging_level level = stats->failed ? CRITERION_IMPORTANT
: CRITERION_INFO;
const char *color = stats->failed ? FG_RED : FG_GREEN;
const char *format = can_measure_time() ? "%1$s::%2$s: (%3$3.2fs)\n" : "%1$s::%2$s\n";
criterion_log(level, "[%s%s%s] ", color, stats->failed ? "FAIL" : "PASS", RESET);
criterion_log(level, format,
const enum criterion_logging_level level
= stats->failed ? CRITERION_IMPORTANT : CRITERION_INFO;
const struct criterion_prefix_data *prefix
= stats->failed ? CRITERION_PREFIX_FAIL : CRITERION_PREFIX_PASS;
criterion_plog(level, prefix, _(format),
stats->test->category,
stats->test->name,
stats->elapsed_time);
@ -72,28 +66,32 @@ static inline bool is_disabled(struct criterion_test *t, struct criterion_suite
void normal_log_post_suite(struct criterion_suite_stats *stats) {
for (struct criterion_test_stats *ts = stats->tests; ts; ts = ts->next) {
if (is_disabled(ts->test, stats->suite)) {
criterion_info("[%sSKIP%s] %s::%s: %s is disabled\n",
FG_GOLD,
RESET,
const char *format = ts->test->data->disabled
? _("%1$s::%2$s: Test is disabled\n")
: _("%1$s::%2$s: Suite is disabled\n");
criterion_pinfo(CRITERION_PREFIX_SKIP, format,
ts->test->category,
ts->test->name,
ts->test->data->disabled ? "test" : "suite");
ts->test->name);
if (ts->test->data->description)
criterion_info("[%s----%s] %s\n", FG_BLUE, RESET, ts->test->data->description);
criterion_pinfo(CRITERION_PREFIX_DASHES, " %s\n", ts->test->data->description);
}
}
}
void normal_log_post_all(struct criterion_global_stats *stats) {
criterion_important("[%s====%s] ", FG_BLUE, RESET);
criterion_important("%sSynthesis: " SIZE_T_FORMAT " test%s run. " SIZE_T_FORMAT " passed, " SIZE_T_FORMAT " failed (with " SIZE_T_FORMAT " crash%s)%s\n",
criterion_pimportant(CRITERION_PREFIX_EQUALS,
_("%1$sSynthesis: Tested: %2$s%3$lu%4$s "
"| Passing: %5$s%6$lu%7$s "
"| Failing: %8$s%9$lu%10$s "
"| Crashing: %11$s%12$lu%13$s "
"%14$s\n"),
FG_BOLD,
stats->nb_tests,
stats->nb_tests == 1 ? " was" : "s were",
stats->tests_passed,
stats->tests_failed,
stats->tests_crashed,
stats->tests_crashed == 1 ? "" : "es",
FG_BLUE, stats->nb_tests, FG_BOLD,
FG_GREEN, stats->tests_passed, FG_BOLD,
FG_RED, stats->tests_failed, FG_BOLD,
FG_RED, stats->tests_crashed, FG_BOLD,
RESET);
}
@ -102,48 +100,36 @@ void normal_log_assert(struct criterion_assert_stats *stats) {
char *dup = strdup(*stats->message ? stats->message : stats->condition), *saveptr = NULL;
char *line = strtok_r(dup, "\n", &saveptr);
criterion_important("[%s----%s] ", FG_BLUE, RESET);
criterion_important("%s%s%s:%s%d%s: Assertion failed: %s\n",
FG_BOLD,
stats->file,
RESET,
FG_RED,
stats->line,
RESET,
criterion_pimportant(CRITERION_PREFIX_DASHES,
_("%1$s%2$s%3$s:%4$s%5$d%6$s: Assertion failed: %7$s\n"),
FG_BOLD, stats->file, RESET,
FG_RED, stats->line, RESET,
line);
while ((line = strtok_r(NULL, "\n", &saveptr)))
criterion_important("[%s----%s] %s\n", FG_BLUE, RESET, line);
criterion_pimportant(CRITERION_PREFIX_DASHES, _(" %s\n"), line);
free(dup);
}
}
void normal_log_test_crash(struct criterion_test_stats *stats) {
criterion_important("[%s----%s] ", FG_BLUE, RESET);
criterion_important("%s%s%s:%s%u%s: Unexpected signal caught below this line!\n",
FG_BOLD,
stats->file,
RESET,
FG_RED,
stats->progress,
RESET);
criterion_important("[%sFAIL%s] %s::%s: CRASH!\n",
FG_RED,
RESET,
criterion_pimportant(CRITERION_PREFIX_DASHES,
_("%1$s%2$s%3$s:%4$s%5$u%6$s: "
"Unexpected signal caught below this line!\n"),
FG_BOLD, stats->file, RESET,
FG_RED, stats->progress, RESET);
criterion_pimportant(CRITERION_PREFIX_FAIL, _("%1$s::%2$s: CRASH!\n"),
stats->test->category,
stats->test->name);
}
void normal_log_pre_suite(struct criterion_suite_set *set) {
criterion_info("[%s====%s] ", FG_BLUE, RESET);
criterion_info("Running %s" SIZE_T_FORMAT "%s test%s from %s%s%s:\n",
FG_BLUE,
set->tests->size,
RESET,
set->tests->size == 1 ? "" : "s",
FG_GOLD,
set->suite.name,
RESET);
criterion_pinfo(CRITERION_PREFIX_EQUALS,
_s("Running %1$s%2$lu%3$s test from %4$s%5$s%6$s:\n",
"Running %1$s%2$lu%3$s tests from %4$s%5$s%6$s:\n",
set->tests->size),
FG_BLUE, set->tests->size, RESET,
FG_GOLD, set->suite.name, RESET);
}
struct criterion_output_provider normal_logging = {

View file

@ -26,11 +26,16 @@
#include <criterion/options.h>
#include <criterion/ordered-set.h>
#include <stdio.h>
#include <locale.h>
#include <getopt.h>
#include <csptr/smart_ptr.h>
#include "runner.h"
#include "config.h"
#ifdef I18N
# include <libintl.h>
#endif
# define VERSION_MSG "Tests compiled with Criterion v" VERSION "\n"
#ifdef HAVE_FNMATCH
@ -130,6 +135,11 @@ int main(int argc, char *argv[]) {
bool use_ascii = !strcmp("1", getenv("CRITERION_USE_ASCII") ?: "0")
|| !strcmp("dumb", getenv("TERM") ?: "dumb");
setlocale(LC_ALL, "");
#ifdef I18N
textdomain (PACKAGE "-test");
#endif
criterion_options = (struct criterion_options) {
.always_succeed = !strcmp("1", getenv("CRITERION_ALWAYS_SUCCEED") ?: "0"),
.no_early_exit = !strcmp("1", getenv("CRITERION_NO_EARLY_EXIT") ?: "0"),