unit-tests: add if_test
The macro TEST only allows defining a test that consists of a single expression. Add a new macro, if_test, which provides a way to define unit tests that are made up of one or more statements. if_test allows defining self-contained tests en bloc, a bit like test_expect_success does for regular tests. It acts like a conditional; the test body is executed if test_skip_all() had not been called before. Signed-off-by: René Scharfe <l.s.r@web.de> Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:

committed by
Junio C Hamano

parent
1f452d6c68
commit
96c6304c18
@ -169,6 +169,11 @@ ForEachMacros:
|
|||||||
- 'strmap_for_each_entry'
|
- 'strmap_for_each_entry'
|
||||||
- 'strset_for_each_entry'
|
- 'strset_for_each_entry'
|
||||||
|
|
||||||
|
# A list of macros that should be interpreted as conditionals instead of as
|
||||||
|
# function calls.
|
||||||
|
IfMacros:
|
||||||
|
- 'if_test'
|
||||||
|
|
||||||
# The maximum number of consecutive empty lines to keep.
|
# The maximum number of consecutive empty lines to keep.
|
||||||
MaxEmptyLinesToKeep: 1
|
MaxEmptyLinesToKeep: 1
|
||||||
|
|
||||||
|
@ -94,5 +94,38 @@ int cmd__example_tap(int argc, const char **argv)
|
|||||||
test_res = TEST(t_empty(), "test with no checks");
|
test_res = TEST(t_empty(), "test with no checks");
|
||||||
TEST(check_int(test_res, ==, 0), "test with no checks returns 0");
|
TEST(check_int(test_res, ==, 0), "test with no checks returns 0");
|
||||||
|
|
||||||
|
if_test ("if_test passing test")
|
||||||
|
check_int(1, ==, 1);
|
||||||
|
if_test ("if_test failing test")
|
||||||
|
check_int(1, ==, 2);
|
||||||
|
if_test ("if_test passing TEST_TODO()")
|
||||||
|
TEST_TODO(check(0));
|
||||||
|
if_test ("if_test failing TEST_TODO()")
|
||||||
|
TEST_TODO(check(1));
|
||||||
|
if_test ("if_test test_skip()") {
|
||||||
|
check(0);
|
||||||
|
test_skip("missing prerequisite");
|
||||||
|
check(1);
|
||||||
|
}
|
||||||
|
if_test ("if_test test_skip() inside TEST_TODO()")
|
||||||
|
TEST_TODO((test_skip("missing prerequisite"), 1));
|
||||||
|
if_test ("if_test TEST_TODO() after failing check") {
|
||||||
|
check(0);
|
||||||
|
TEST_TODO(check(0));
|
||||||
|
}
|
||||||
|
if_test ("if_test failing check after TEST_TODO()") {
|
||||||
|
check(1);
|
||||||
|
TEST_TODO(check(0));
|
||||||
|
check(0);
|
||||||
|
}
|
||||||
|
if_test ("if_test messages from failing string and char comparison") {
|
||||||
|
check_str("\thello\\", "there\"\n");
|
||||||
|
check_str("NULL", NULL);
|
||||||
|
check_char('a', ==, '\n');
|
||||||
|
check_char('\\', ==, '\'');
|
||||||
|
}
|
||||||
|
if_test ("if_test test with no checks")
|
||||||
|
; /* nothing */
|
||||||
|
|
||||||
return test_done();
|
return test_done();
|
||||||
}
|
}
|
||||||
|
@ -50,7 +50,40 @@ test_expect_success 'TAP output from unit tests' - <<\EOT
|
|||||||
# BUG: test has no checks at t/helper/test-example-tap.c:94
|
# BUG: test has no checks at t/helper/test-example-tap.c:94
|
||||||
not ok 18 - test with no checks
|
not ok 18 - test with no checks
|
||||||
ok 19 - test with no checks returns 0
|
ok 19 - test with no checks returns 0
|
||||||
1..19
|
ok 20 - if_test passing test
|
||||||
|
# check "1 == 2" failed at t/helper/test-example-tap.c:100
|
||||||
|
# left: 1
|
||||||
|
# right: 2
|
||||||
|
not ok 21 - if_test failing test
|
||||||
|
not ok 22 - if_test passing TEST_TODO() # TODO
|
||||||
|
# todo check 'check(1)' succeeded at t/helper/test-example-tap.c:104
|
||||||
|
not ok 23 - if_test failing TEST_TODO()
|
||||||
|
# check "0" failed at t/helper/test-example-tap.c:106
|
||||||
|
# skipping test - missing prerequisite
|
||||||
|
# skipping check '1' at t/helper/test-example-tap.c:108
|
||||||
|
ok 24 - if_test test_skip() # SKIP
|
||||||
|
# skipping test - missing prerequisite
|
||||||
|
ok 25 - if_test test_skip() inside TEST_TODO() # SKIP
|
||||||
|
# check "0" failed at t/helper/test-example-tap.c:113
|
||||||
|
not ok 26 - if_test TEST_TODO() after failing check
|
||||||
|
# check "0" failed at t/helper/test-example-tap.c:119
|
||||||
|
not ok 27 - if_test failing check after TEST_TODO()
|
||||||
|
# check "!strcmp("\thello\\\\", "there\"\n")" failed at t/helper/test-example-tap.c:122
|
||||||
|
# left: "\011hello\\\\"
|
||||||
|
# right: "there\"\012"
|
||||||
|
# check "!strcmp("NULL", NULL)" failed at t/helper/test-example-tap.c:123
|
||||||
|
# left: "NULL"
|
||||||
|
# right: NULL
|
||||||
|
# check "'a' == '\n'" failed at t/helper/test-example-tap.c:124
|
||||||
|
# left: 'a'
|
||||||
|
# right: '\012'
|
||||||
|
# check "'\\\\' == '\\''" failed at t/helper/test-example-tap.c:125
|
||||||
|
# left: '\\\\'
|
||||||
|
# right: '\\''
|
||||||
|
not ok 28 - if_test messages from failing string and char comparison
|
||||||
|
# BUG: test has no checks at t/helper/test-example-tap.c:127
|
||||||
|
not ok 29 - if_test test with no checks
|
||||||
|
1..29
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
! test-tool example-tap >actual &&
|
! test-tool example-tap >actual &&
|
||||||
|
@ -16,6 +16,8 @@ static struct {
|
|||||||
unsigned running :1;
|
unsigned running :1;
|
||||||
unsigned skip_all :1;
|
unsigned skip_all :1;
|
||||||
unsigned todo :1;
|
unsigned todo :1;
|
||||||
|
char location[100];
|
||||||
|
char description[100];
|
||||||
} ctx = {
|
} ctx = {
|
||||||
.lazy_plan = 1,
|
.lazy_plan = 1,
|
||||||
.result = RESULT_NONE,
|
.result = RESULT_NONE,
|
||||||
@ -125,6 +127,8 @@ void test_plan(int count)
|
|||||||
|
|
||||||
int test_done(void)
|
int test_done(void)
|
||||||
{
|
{
|
||||||
|
if (ctx.running && ctx.location[0] && ctx.description[0])
|
||||||
|
test__run_end(1, ctx.location, "%s", ctx.description);
|
||||||
assert(!ctx.running);
|
assert(!ctx.running);
|
||||||
|
|
||||||
if (ctx.lazy_plan)
|
if (ctx.lazy_plan)
|
||||||
@ -167,13 +171,38 @@ void test_skip_all(const char *format, ...)
|
|||||||
va_end(ap);
|
va_end(ap);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void test__run_describe(const char *location, const char *format, ...)
|
||||||
|
{
|
||||||
|
va_list ap;
|
||||||
|
int len;
|
||||||
|
|
||||||
|
assert(ctx.running);
|
||||||
|
assert(!ctx.location[0]);
|
||||||
|
assert(!ctx.description[0]);
|
||||||
|
|
||||||
|
xsnprintf(ctx.location, sizeof(ctx.location), "%s",
|
||||||
|
make_relative(location));
|
||||||
|
|
||||||
|
va_start(ap, format);
|
||||||
|
len = vsnprintf(ctx.description, sizeof(ctx.description), format, ap);
|
||||||
|
va_end(ap);
|
||||||
|
if (len < 0)
|
||||||
|
die("unable to format message: %s", format);
|
||||||
|
if (len >= sizeof(ctx.description))
|
||||||
|
BUG("ctx.description too small to format %s", format);
|
||||||
|
}
|
||||||
|
|
||||||
int test__run_begin(void)
|
int test__run_begin(void)
|
||||||
{
|
{
|
||||||
|
if (ctx.running && ctx.location[0] && ctx.description[0])
|
||||||
|
test__run_end(1, ctx.location, "%s", ctx.description);
|
||||||
assert(!ctx.running);
|
assert(!ctx.running);
|
||||||
|
|
||||||
ctx.count++;
|
ctx.count++;
|
||||||
ctx.result = RESULT_NONE;
|
ctx.result = RESULT_NONE;
|
||||||
ctx.running = 1;
|
ctx.running = 1;
|
||||||
|
ctx.location[0] = '\0';
|
||||||
|
ctx.description[0] = '\0';
|
||||||
|
|
||||||
return ctx.skip_all;
|
return ctx.skip_all;
|
||||||
}
|
}
|
||||||
|
@ -14,6 +14,23 @@
|
|||||||
test__run_end(test__run_begin() ? 0 : (t, 1), \
|
test__run_end(test__run_begin() ? 0 : (t, 1), \
|
||||||
TEST_LOCATION(), __VA_ARGS__)
|
TEST_LOCATION(), __VA_ARGS__)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Run a test unless test_skip_all() has been called. Acts like a
|
||||||
|
* conditional; the test body is expected as a statement or block after
|
||||||
|
* the closing parenthesis. The description for each test should be
|
||||||
|
* unique. E.g.:
|
||||||
|
*
|
||||||
|
* if_test ("something else %d %d", arg1, arg2) {
|
||||||
|
* prepare();
|
||||||
|
* test_something_else(arg1, arg2);
|
||||||
|
* cleanup();
|
||||||
|
* }
|
||||||
|
*/
|
||||||
|
#define if_test(...) \
|
||||||
|
if (test__run_begin() ? \
|
||||||
|
(test__run_end(0, TEST_LOCATION(), __VA_ARGS__), 0) : \
|
||||||
|
(test__run_describe(TEST_LOCATION(), __VA_ARGS__), 1))
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Print a test plan, should be called before any tests. If the number
|
* Print a test plan, should be called before any tests. If the number
|
||||||
* of tests is not known in advance test_done() will automatically
|
* of tests is not known in advance test_done() will automatically
|
||||||
@ -153,6 +170,9 @@ union test__tmp {
|
|||||||
|
|
||||||
extern union test__tmp test__tmp[2];
|
extern union test__tmp test__tmp[2];
|
||||||
|
|
||||||
|
__attribute__((format (printf, 2, 3)))
|
||||||
|
void test__run_describe(const char *, const char *, ...);
|
||||||
|
|
||||||
int test__run_begin(void);
|
int test__run_begin(void);
|
||||||
__attribute__((format (printf, 3, 4)))
|
__attribute__((format (printf, 3, 4)))
|
||||||
int test__run_end(int, const char *, const char *, ...);
|
int test__run_end(int, const char *, const char *, ...);
|
||||||
|
Reference in New Issue
Block a user