From 7794891d773120aeab0bedccec82cbcb599b7a40 Mon Sep 17 00:00:00 2001 From: Vladimir Davydov <vdavydov@tarantool.org> Date: Thu, 24 Aug 2023 15:13:32 +0300 Subject: [PATCH] test: allow to omit message in ok/is/isnt unit test helpers It's really annoying to add a message after each check in a unit test. Let's make this optional. If the message is omitted, "line %d" will be used instead. Also, let's print the expression on failure because it may be useful if exact sources are unavailable. NO_DOC=refactoring NO_CHANGELOG=refactoring (cherry picked from commit 62ae8bf3a5ba63a393a1e9e540d5fcca1d702670) --- test/unit/unit.c | 15 ++++++++---- test/unit/unit.h | 64 +++++++++++++++++++++--------------------------- 2 files changed, 38 insertions(+), 41 deletions(-) diff --git a/test/unit/unit.c b/test/unit/unit.c index 38326793d9..d1784bb8eb 100644 --- a/test/unit/unit.c +++ b/test/unit/unit.c @@ -60,19 +60,24 @@ check_plan(void) return r; } -int -_ok(int condition, const char *fmt, ...) +void +_ok(int condition, const char *expr, const char *file, int line, + const char *fmt, ...) { va_list ap; _space(stdout); printf("%s %d - ", condition ? "ok" : "not ok", ++tests_done[level]); - if (!condition) - tests_failed[level]++; va_start(ap, fmt); vprintf(fmt, ap); printf("\n"); va_end(ap); - return condition; + if (!condition) { + tests_failed[level]++; + _space(stderr); + fprintf(stderr, "# Failed test `%s'\n", expr); + _space(stderr); + fprintf(stderr, "# in %s at line %d\n", file, line); + } } diff --git a/test/unit/unit.h b/test/unit/unit.h index 77d0847b56..bb0e53136d 100644 --- a/test/unit/unit.h +++ b/test/unit/unit.h @@ -70,7 +70,9 @@ extern "C" { */ /* private function, use ok(...) instead */ -int _ok(int condition, const char *fmt, ...); +void +_ok(int condition, const char *expr, const char *file, int line, + const char *fmt, ...); /* private function, use note(...) or diag(...) instead */ void _space(FILE *stream); @@ -90,41 +92,31 @@ _plan(int count, bool tap); */ int check_plan(void); -#define ok(condition, fmt, args...) { \ - int res = _ok(condition, fmt, ##args); \ - if (!res) { \ - _space(stderr); \ - fprintf(stderr, "# Failed test '"); \ - fprintf(stderr, fmt, ##args); \ - fprintf(stderr, "'\n"); \ - _space(stderr); \ - fprintf(stderr, "# in %s at line %d\n", __FILE__, __LINE__); \ - } \ -} - -#define is(a, b, fmt, args...) { \ - int res = _ok((a) == (b), fmt, ##args); \ - if (!res) { \ - _space(stderr); \ - fprintf(stderr, "# Failed test '"); \ - fprintf(stderr, fmt, ##args); \ - fprintf(stderr, "'\n"); \ - _space(stderr); \ - fprintf(stderr, "# in %s at line %d\n", __FILE__, __LINE__); \ - } \ -} - -#define isnt(a, b, fmt, args...) { \ - int res = _ok((a) != (b), fmt, ##args); \ - if (!res) { \ - _space(stderr); \ - fprintf(stderr, "# Failed test '"); \ - fprintf(stderr, fmt, ##args); \ - fprintf(stderr, "'\n"); \ - _space(stderr); \ - fprintf(stderr, "# in %s at line %d\n", __FILE__, __LINE__); \ - } \ -} +/* + * The ok macro is defined so that it can be called without a message: + * + * ok(true); + * ok(true, "message"); + * ok(true, "message %d", i); + * + * It supports up to 7 format arguments. + */ +#define _select_10th(f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, ...) f10 +#define _ok0(cond, expr, ...) \ + _select_10th(, ##__VA_ARGS__, \ + _ok(cond, expr, __FILE__, __LINE__, __VA_ARGS__), \ + _ok(cond, expr, __FILE__, __LINE__, __VA_ARGS__), \ + _ok(cond, expr, __FILE__, __LINE__, __VA_ARGS__), \ + _ok(cond, expr, __FILE__, __LINE__, __VA_ARGS__), \ + _ok(cond, expr, __FILE__, __LINE__, __VA_ARGS__), \ + _ok(cond, expr, __FILE__, __LINE__, __VA_ARGS__), \ + _ok(cond, expr, __FILE__, __LINE__, __VA_ARGS__), \ + _ok(cond, expr, __FILE__, __LINE__, __VA_ARGS__), \ + _ok(cond, expr, __FILE__, __LINE__, "line %d", __LINE__)) + +#define ok(cond, ...) _ok0(cond, #cond, ##__VA_ARGS__) +#define is(a, b, ...) _ok0((a) == (b), #a " == " #b, ##__VA_ARGS__) +#define isnt(a, b, ...) _ok0((a) != (b), #a " != " #b, ##__VA_ARGS__) #if UNIT_TAP_COMPATIBLE -- GitLab