The macro TEST only allows defining a test that consists of a single expression. Add the new macro, TEST_RUN, which provides a way to define unit tests that are made up of one or more statements. A test started with it implicitly ends when the next test is started or test_done() is called. TEST_RUN allows defining self-contained tests en bloc, a bit like test_expect_success does for regular tests. Unlike TEST it does not require defining wrapper functions for test statements. No public method is provided for ending a test explicitly, yet; let's see if we'll ever need one. Signed-off-by: René Scharfe <l.s.r@xxxxxx> --- t/helper/test-example-tap.c | 33 +++++++++++++++++++++++++++++ t/t0080/expect | 35 ++++++++++++++++++++++++++++++- t/unit-tests/test-lib.c | 42 +++++++++++++++++++++++++++++++++++-- t/unit-tests/test-lib.h | 8 +++++++ 4 files changed, 115 insertions(+), 3 deletions(-) diff --git a/t/helper/test-example-tap.c b/t/helper/test-example-tap.c index d072ad559f..7b02177a9f 100644 --- a/t/helper/test-example-tap.c +++ b/t/helper/test-example-tap.c @@ -92,5 +92,38 @@ int cmd__example_tap(int argc, const char **argv) test_res = TEST(t_empty(), "test with no checks"); TEST(check_int(test_res, ==, 0), "test with no checks returns 0"); + if (TEST_RUN("TEST_RUN passing test")) + check_int(1, ==, 1); + if (TEST_RUN("TEST_RUN failing test")) + check_int(1, ==, 2); + if (TEST_RUN("TEST_RUN passing TEST_TODO()")) + TEST_TODO(check(0)); + if (TEST_RUN("TEST_RUN failing TEST_TODO()")) + TEST_TODO(check(1)); + if (TEST_RUN("TEST_RUN test_skip()")) { + check(0); + test_skip("missing prerequisite"); + check(1); + } + if (TEST_RUN("TEST_RUN test_skip() inside TEST_TODO()")) + TEST_TODO((test_skip("missing prerequisite"), 1)); + if (TEST_RUN("TEST_RUN TEST_TODO() after failing check")) { + check(0); + TEST_TODO(check(0)); + } + if (TEST_RUN("TEST_RUN failing check after TEST_TODO()")) { + check(1); + TEST_TODO(check(0)); + check(0); + } + if (TEST_RUN("TEST_RUN messages from failing string and char comparison")) { + check_str("\thello\\", "there\"\n"); + check_str("NULL", NULL); + check_char('a', ==, '\n'); + check_char('\\', ==, '\''); + } + if (TEST_RUN("TEST_RUN test with no checks")) + ; /* nothing */ + return test_done(); } diff --git a/t/t0080/expect b/t/t0080/expect index 0cfa0dc6d8..92526e1b06 100644 --- a/t/t0080/expect +++ b/t/t0080/expect @@ -40,4 +40,37 @@ not ok 17 - messages from failing string and char comparison # BUG: test has no checks at t/helper/test-example-tap.c:92 not ok 18 - test with no checks ok 19 - test with no checks returns 0 -1..19 +ok 20 - TEST_RUN passing test +# check "1 == 2" failed at t/helper/test-example-tap.c:98 +# left: 1 +# right: 2 +not ok 21 - TEST_RUN failing test +not ok 22 - TEST_RUN passing TEST_TODO() # TODO +# todo check 'check(1)' succeeded at t/helper/test-example-tap.c:102 +not ok 23 - TEST_RUN failing TEST_TODO() +# check "0" failed at t/helper/test-example-tap.c:104 +# skipping test - missing prerequisite +# skipping check '1' at t/helper/test-example-tap.c:106 +ok 24 - TEST_RUN test_skip() # SKIP +# skipping test - missing prerequisite +ok 25 - TEST_RUN test_skip() inside TEST_TODO() # SKIP +# check "0" failed at t/helper/test-example-tap.c:111 +not ok 26 - TEST_RUN TEST_TODO() after failing check +# check "0" failed at t/helper/test-example-tap.c:117 +not ok 27 - TEST_RUN failing check after TEST_TODO() +# check "!strcmp("\thello\\", "there\"\n")" failed at t/helper/test-example-tap.c:120 +# left: "\011hello\\" +# right: "there\"\012" +# check "!strcmp("NULL", NULL)" failed at t/helper/test-example-tap.c:121 +# left: "NULL" +# right: NULL +# check "'a' == '\n'" failed at t/helper/test-example-tap.c:122 +# left: 'a' +# right: '\012' +# check "'\\' == '\''" failed at t/helper/test-example-tap.c:123 +# left: '\\' +# right: '\'' +not ok 28 - TEST_RUN messages from failing string and char comparison +# BUG: test has no checks at t/helper/test-example-tap.c:125 +not ok 29 - TEST_RUN test with no checks +1..29 diff --git a/t/unit-tests/test-lib.c b/t/unit-tests/test-lib.c index 3c513ce59a..fc50755fae 100644 --- a/t/unit-tests/test-lib.c +++ b/t/unit-tests/test-lib.c @@ -16,6 +16,8 @@ static struct { unsigned running :1; unsigned skip_all :1; unsigned todo :1; + char *desc; + char *location; } ctx = { .lazy_plan = 1, .result = RESULT_NONE, @@ -123,9 +125,45 @@ void test_plan(int count) ctx.lazy_plan = 0; } -int test_done(void) +static void test__run_maybe_end(void) { + if (ctx.running) { + assert(ctx.location); + assert(ctx.desc); + test__run_end(0, ctx.location, "%s", ctx.desc); + FREE_AND_NULL(ctx.location); + FREE_AND_NULL(ctx.desc); + } assert(!ctx.running); + assert(!ctx.location); + assert(!ctx.desc); +} + +int test__run(const char *location, const char *format, ...) +{ + va_list ap; + char *desc; + + test__run_maybe_end(); + + va_start(ap, format); + desc = xstrvfmt(format, ap); + va_end(ap); + + if (test__run_begin()) { + test__run_end(1, location, "%s", desc); + free(desc); + return 0; + } else { + ctx.location = xstrdup(location); + ctx.desc = desc; + return 1; + } +} + +int test_done(void) +{ + test__run_maybe_end(); if (ctx.lazy_plan) test_plan(ctx.count); @@ -169,7 +207,7 @@ void test_skip_all(const char *format, ...) int test__run_begin(void) { - assert(!ctx.running); + test__run_maybe_end(); ctx.count++; ctx.result = RESULT_NONE; diff --git a/t/unit-tests/test-lib.h b/t/unit-tests/test-lib.h index 2de6d715d5..6df40e3b12 100644 --- a/t/unit-tests/test-lib.h +++ b/t/unit-tests/test-lib.h @@ -21,6 +21,13 @@ */ void test_plan(int count); +/* + * Start a test, returns 1 if the test was actually started or 0 if it + * was skipped. The test ends when the next test starts or test_done() + * is called. + */ +#define TEST_RUN(...) test__run(TEST_LOCATION(), __VA_ARGS__) + /* * test_done() must be called at the end of main(). It will print the * plan if plan() was not called at the beginning of the test program @@ -156,6 +163,7 @@ extern union test__tmp test__tmp[2]; int test__run_begin(void); __attribute__((format (printf, 3, 4))) int test__run_end(int, const char *, const char *, ...); +int test__run(const char *location, const char *format, ...); void test__todo_begin(void); int test__todo_end(const char *, const char *, int); -- 2.45.2