aboutsummaryrefslogtreecommitdiffstats
path: root/t/unit-tests
diff options
context:
space:
mode:
Diffstat (limited to 't/unit-tests')
-rw-r--r--t/unit-tests/t-ctype.c4
-rw-r--r--t/unit-tests/t-reftable-basics.c228
-rw-r--r--t/unit-tests/t-strvec.c416
-rw-r--r--t/unit-tests/test-lib.c36
-rw-r--r--t/unit-tests/test-lib.h20
5 files changed, 348 insertions, 356 deletions
diff --git a/t/unit-tests/t-ctype.c b/t/unit-tests/t-ctype.c
index d6ac1fe678..e28a7f50f9 100644
--- a/t/unit-tests/t-ctype.c
+++ b/t/unit-tests/t-ctype.c
@@ -4,15 +4,13 @@
size_t len = ARRAY_SIZE(string) - 1 + \
BUILD_ASSERT_OR_ZERO(ARRAY_SIZE(string) > 0) + \
BUILD_ASSERT_OR_ZERO(sizeof(string[0]) == sizeof(char)); \
- int skip = test__run_begin(); \
- if (!skip) { \
+ if_test (#class " works") { \
for (int i = 0; i < 256; i++) { \
if (!check_int(class(i), ==, !!memchr(string, i, len)))\
test_msg(" i: 0x%02x", i); \
} \
check(!class(EOF)); \
} \
- test__run_end(!skip, TEST_LOCATION(), #class " works"); \
} while (0)
#define DIGIT "0123456789"
diff --git a/t/unit-tests/t-reftable-basics.c b/t/unit-tests/t-reftable-basics.c
index 4e80bdf16d..1dd60ab5f0 100644
--- a/t/unit-tests/t-reftable-basics.c
+++ b/t/unit-tests/t-reftable-basics.c
@@ -20,141 +20,125 @@ static int integer_needle_lesseq(size_t i, void *_args)
return args->needle <= args->haystack[i];
}
-static void test_binsearch(void)
+int cmd_main(int argc, const char *argv[])
{
- int haystack[] = { 2, 4, 6, 8, 10 };
- struct {
- int needle;
- size_t expected_idx;
- } testcases[] = {
- {-9000, 0},
- {-1, 0},
- {0, 0},
- {2, 0},
- {3, 1},
- {4, 1},
- {7, 3},
- {9, 4},
- {10, 4},
- {11, 5},
- {9000, 5},
- };
-
- for (size_t i = 0; i < ARRAY_SIZE(testcases); i++) {
- struct integer_needle_lesseq_args args = {
- .haystack = haystack,
- .needle = testcases[i].needle,
+ if_test ("binary search with binsearch works") {
+ int haystack[] = { 2, 4, 6, 8, 10 };
+ struct {
+ int needle;
+ size_t expected_idx;
+ } testcases[] = {
+ {-9000, 0},
+ {-1, 0},
+ {0, 0},
+ {2, 0},
+ {3, 1},
+ {4, 1},
+ {7, 3},
+ {9, 4},
+ {10, 4},
+ {11, 5},
+ {9000, 5},
};
- size_t idx;
- idx = binsearch(ARRAY_SIZE(haystack), &integer_needle_lesseq, &args);
- check_int(idx, ==, testcases[i].expected_idx);
+ for (size_t i = 0; i < ARRAY_SIZE(testcases); i++) {
+ struct integer_needle_lesseq_args args = {
+ .haystack = haystack,
+ .needle = testcases[i].needle,
+ };
+ size_t idx;
+
+ idx = binsearch(ARRAY_SIZE(haystack),
+ &integer_needle_lesseq, &args);
+ check_int(idx, ==, testcases[i].expected_idx);
+ }
}
-}
-static void test_names_length(void)
-{
- const char *a[] = { "a", "b", NULL };
- check_int(names_length(a), ==, 2);
-}
-
-static void test_names_equal(void)
-{
- const char *a[] = { "a", "b", "c", NULL };
- const char *b[] = { "a", "b", "d", NULL };
- const char *c[] = { "a", "b", NULL };
+ if_test ("names_length retuns size of a NULL-terminated string array") {
+ const char *a[] = { "a", "b", NULL };
+ check_int(names_length(a), ==, 2);
+ }
- check(names_equal(a, a));
- check(!names_equal(a, b));
- check(!names_equal(a, c));
-}
+ if_test ("names_equal compares NULL-terminated string arrays") {
+ const char *a[] = { "a", "b", "c", NULL };
+ const char *b[] = { "a", "b", "d", NULL };
+ const char *c[] = { "a", "b", NULL };
-static void test_parse_names_normal(void)
-{
- char in1[] = "line\n";
- char in2[] = "a\nb\nc";
- char **out = NULL;
- parse_names(in1, strlen(in1), &out);
- check_str(out[0], "line");
- check(!out[1]);
- free_names(out);
-
- parse_names(in2, strlen(in2), &out);
- check_str(out[0], "a");
- check_str(out[1], "b");
- check_str(out[2], "c");
- check(!out[3]);
- free_names(out);
-}
+ check(names_equal(a, a));
+ check(!names_equal(a, b));
+ check(!names_equal(a, c));
+ }
-static void test_parse_names_drop_empty(void)
-{
- char in[] = "a\n\nb\n";
- char **out = NULL;
- parse_names(in, strlen(in), &out);
- check_str(out[0], "a");
- /* simply '\n' should be dropped as empty string */
- check_str(out[1], "b");
- check(!out[2]);
- free_names(out);
-}
+ if_test ("parse_names works for basic input") {
+ char in1[] = "line\n";
+ char in2[] = "a\nb\nc";
+ char **out = NULL;
+ parse_names(in1, strlen(in1), &out);
+ check_str(out[0], "line");
+ check(!out[1]);
+ free_names(out);
+
+ parse_names(in2, strlen(in2), &out);
+ check_str(out[0], "a");
+ check_str(out[1], "b");
+ check_str(out[2], "c");
+ check(!out[3]);
+ free_names(out);
+ }
-static void test_common_prefix(void)
-{
- struct strbuf a = STRBUF_INIT;
- struct strbuf b = STRBUF_INIT;
- struct {
- const char *a, *b;
- int want;
- } cases[] = {
- {"abcdef", "abc", 3},
- { "abc", "ab", 2 },
- { "", "abc", 0 },
- { "abc", "abd", 2 },
- { "abc", "pqr", 0 },
- };
-
- for (size_t i = 0; i < ARRAY_SIZE(cases); i++) {
- strbuf_addstr(&a, cases[i].a);
- strbuf_addstr(&b, cases[i].b);
- check_int(common_prefix_size(&a, &b), ==, cases[i].want);
- strbuf_reset(&a);
- strbuf_reset(&b);
+ if_test ("parse_names drops empty string") {
+ char in[] = "a\n\nb\n";
+ char **out = NULL;
+ parse_names(in, strlen(in), &out);
+ check_str(out[0], "a");
+ /* simply '\n' should be dropped as empty string */
+ check_str(out[1], "b");
+ check(!out[2]);
+ free_names(out);
}
- strbuf_release(&a);
- strbuf_release(&b);
-}
-static void test_u24_roundtrip(void)
-{
- uint32_t in = 0x112233;
- uint8_t dest[3];
- uint32_t out;
- put_be24(dest, in);
- out = get_be24(dest);
- check_int(in, ==, out);
-}
+ if_test ("common_prefix_size works") {
+ struct strbuf a = STRBUF_INIT;
+ struct strbuf b = STRBUF_INIT;
+ struct {
+ const char *a, *b;
+ int want;
+ } cases[] = {
+ {"abcdef", "abc", 3},
+ { "abc", "ab", 2 },
+ { "", "abc", 0 },
+ { "abc", "abd", 2 },
+ { "abc", "pqr", 0 },
+ };
-static void test_u16_roundtrip(void)
-{
- uint32_t in = 0xfef1;
- uint8_t dest[3];
- uint32_t out;
- put_be16(dest, in);
- out = get_be16(dest);
- check_int(in, ==, out);
-}
+ for (size_t i = 0; i < ARRAY_SIZE(cases); i++) {
+ strbuf_addstr(&a, cases[i].a);
+ strbuf_addstr(&b, cases[i].b);
+ check_int(common_prefix_size(&a, &b), ==, cases[i].want);
+ strbuf_reset(&a);
+ strbuf_reset(&b);
+ }
+ strbuf_release(&a);
+ strbuf_release(&b);
+ }
-int cmd_main(int argc, const char *argv[])
-{
- TEST(test_common_prefix(), "common_prefix_size works");
- TEST(test_parse_names_normal(), "parse_names works for basic input");
- TEST(test_parse_names_drop_empty(), "parse_names drops empty string");
- TEST(test_binsearch(), "binary search with binsearch works");
- TEST(test_names_length(), "names_length retuns size of a NULL-terminated string array");
- TEST(test_names_equal(), "names_equal compares NULL-terminated string arrays");
- TEST(test_u24_roundtrip(), "put_be24 and get_be24 work");
- TEST(test_u16_roundtrip(), "put_be16 and get_be16 work");
+ if_test ("put_be24 and get_be24 work") {
+ uint32_t in = 0x112233;
+ uint8_t dest[3];
+ uint32_t out;
+ put_be24(dest, in);
+ out = get_be24(dest);
+ check_int(in, ==, out);
+ }
+
+ if_test ("put_be16 and get_be16 work") {
+ uint32_t in = 0xfef1;
+ uint8_t dest[3];
+ uint32_t out;
+ put_be16(dest, in);
+ out = get_be16(dest);
+ check_int(in, ==, out);
+ }
return test_done();
}
diff --git a/t/unit-tests/t-strvec.c b/t/unit-tests/t-strvec.c
index fa1a041469..c4bac8fc91 100644
--- a/t/unit-tests/t-strvec.c
+++ b/t/unit-tests/t-strvec.c
@@ -19,237 +19,193 @@
} \
} while (0)
-static void t_static_init(void)
-{
- struct strvec vec = STRVEC_INIT;
- check_pointer_eq(vec.v, empty_strvec);
- check_uint(vec.nr, ==, 0);
- check_uint(vec.alloc, ==, 0);
-}
-
-static void t_dynamic_init(void)
-{
- struct strvec vec;
- strvec_init(&vec);
- check_pointer_eq(vec.v, empty_strvec);
- check_uint(vec.nr, ==, 0);
- check_uint(vec.alloc, ==, 0);
-}
-
-static void t_clear(void)
-{
- struct strvec vec = STRVEC_INIT;
- strvec_push(&vec, "foo");
- strvec_clear(&vec);
- check_pointer_eq(vec.v, empty_strvec);
- check_uint(vec.nr, ==, 0);
- check_uint(vec.alloc, ==, 0);
-}
-
-static void t_push(void)
-{
- struct strvec vec = STRVEC_INIT;
-
- strvec_push(&vec, "foo");
- check_strvec(&vec, "foo", NULL);
-
- strvec_push(&vec, "bar");
- check_strvec(&vec, "foo", "bar", NULL);
-
- strvec_clear(&vec);
-}
-
-static void t_pushf(void)
-{
- struct strvec vec = STRVEC_INIT;
- strvec_pushf(&vec, "foo: %d", 1);
- check_strvec(&vec, "foo: 1", NULL);
- strvec_clear(&vec);
-}
-
-static void t_pushl(void)
-{
- struct strvec vec = STRVEC_INIT;
- strvec_pushl(&vec, "foo", "bar", "baz", NULL);
- check_strvec(&vec, "foo", "bar", "baz", NULL);
- strvec_clear(&vec);
-}
-
-static void t_pushv(void)
-{
- const char *strings[] = {
- "foo", "bar", "baz", NULL,
- };
- struct strvec vec = STRVEC_INIT;
-
- strvec_pushv(&vec, strings);
- check_strvec(&vec, "foo", "bar", "baz", NULL);
-
- strvec_clear(&vec);
-}
-
-static void t_replace_at_head(void)
-{
- struct strvec vec = STRVEC_INIT;
- strvec_pushl(&vec, "foo", "bar", "baz", NULL);
- strvec_replace(&vec, 0, "replaced");
- check_strvec(&vec, "replaced", "bar", "baz", NULL);
- strvec_clear(&vec);
-}
-
-static void t_replace_at_tail(void)
-{
- struct strvec vec = STRVEC_INIT;
- strvec_pushl(&vec, "foo", "bar", "baz", NULL);
- strvec_replace(&vec, 2, "replaced");
- check_strvec(&vec, "foo", "bar", "replaced", NULL);
- strvec_clear(&vec);
-}
-
-static void t_replace_in_between(void)
-{
- struct strvec vec = STRVEC_INIT;
- strvec_pushl(&vec, "foo", "bar", "baz", NULL);
- strvec_replace(&vec, 1, "replaced");
- check_strvec(&vec, "foo", "replaced", "baz", NULL);
- strvec_clear(&vec);
-}
-
-static void t_replace_with_substring(void)
-{
- struct strvec vec = STRVEC_INIT;
- strvec_pushl(&vec, "foo", NULL);
- strvec_replace(&vec, 0, vec.v[0] + 1);
- check_strvec(&vec, "oo", NULL);
- strvec_clear(&vec);
-}
-
-static void t_remove_at_head(void)
-{
- struct strvec vec = STRVEC_INIT;
- strvec_pushl(&vec, "foo", "bar", "baz", NULL);
- strvec_remove(&vec, 0);
- check_strvec(&vec, "bar", "baz", NULL);
- strvec_clear(&vec);
-}
-
-static void t_remove_at_tail(void)
-{
- struct strvec vec = STRVEC_INIT;
- strvec_pushl(&vec, "foo", "bar", "baz", NULL);
- strvec_remove(&vec, 2);
- check_strvec(&vec, "foo", "bar", NULL);
- strvec_clear(&vec);
-}
-
-static void t_remove_in_between(void)
-{
- struct strvec vec = STRVEC_INIT;
- strvec_pushl(&vec, "foo", "bar", "baz", NULL);
- strvec_remove(&vec, 1);
- check_strvec(&vec, "foo", "baz", NULL);
- strvec_clear(&vec);
-}
-
-static void t_pop_empty_array(void)
-{
- struct strvec vec = STRVEC_INIT;
- strvec_pop(&vec);
- check_strvec(&vec, NULL);
- strvec_clear(&vec);
-}
-
-static void t_pop_non_empty_array(void)
-{
- struct strvec vec = STRVEC_INIT;
- strvec_pushl(&vec, "foo", "bar", "baz", NULL);
- strvec_pop(&vec);
- check_strvec(&vec, "foo", "bar", NULL);
- strvec_clear(&vec);
-}
-
-static void t_split_empty_string(void)
-{
- struct strvec vec = STRVEC_INIT;
- strvec_split(&vec, "");
- check_strvec(&vec, NULL);
- strvec_clear(&vec);
-}
-
-static void t_split_single_item(void)
-{
- struct strvec vec = STRVEC_INIT;
- strvec_split(&vec, "foo");
- check_strvec(&vec, "foo", NULL);
- strvec_clear(&vec);
-}
-
-static void t_split_multiple_items(void)
-{
- struct strvec vec = STRVEC_INIT;
- strvec_split(&vec, "foo bar baz");
- check_strvec(&vec, "foo", "bar", "baz", NULL);
- strvec_clear(&vec);
-}
-
-static void t_split_whitespace_only(void)
-{
- struct strvec vec = STRVEC_INIT;
- strvec_split(&vec, " \t\n");
- check_strvec(&vec, NULL);
- strvec_clear(&vec);
-}
-
-static void t_split_multiple_consecutive_whitespaces(void)
-{
- struct strvec vec = STRVEC_INIT;
- strvec_split(&vec, "foo\n\t bar");
- check_strvec(&vec, "foo", "bar", NULL);
- strvec_clear(&vec);
-}
-
-static void t_detach(void)
-{
- struct strvec vec = STRVEC_INIT;
- const char **detached;
-
- strvec_push(&vec, "foo");
-
- detached = strvec_detach(&vec);
- check_str(detached[0], "foo");
- check_pointer_eq(detached[1], NULL);
-
- check_pointer_eq(vec.v, empty_strvec);
- check_uint(vec.nr, ==, 0);
- check_uint(vec.alloc, ==, 0);
-
- free((char *) detached[0]);
- free(detached);
-}
-
int cmd_main(int argc, const char **argv)
{
- TEST(t_static_init(), "static initialization");
- TEST(t_dynamic_init(), "dynamic initialization");
- TEST(t_clear(), "clear");
- TEST(t_push(), "push");
- TEST(t_pushf(), "pushf");
- TEST(t_pushl(), "pushl");
- TEST(t_pushv(), "pushv");
- TEST(t_replace_at_head(), "replace at head");
- TEST(t_replace_in_between(), "replace in between");
- TEST(t_replace_at_tail(), "replace at tail");
- TEST(t_replace_with_substring(), "replace with substring");
- TEST(t_remove_at_head(), "remove at head");
- TEST(t_remove_in_between(), "remove in between");
- TEST(t_remove_at_tail(), "remove at tail");
- TEST(t_pop_empty_array(), "pop with empty array");
- TEST(t_pop_non_empty_array(), "pop with non-empty array");
- TEST(t_split_empty_string(), "split empty string");
- TEST(t_split_single_item(), "split single item");
- TEST(t_split_multiple_items(), "split multiple items");
- TEST(t_split_whitespace_only(), "split whitespace only");
- TEST(t_split_multiple_consecutive_whitespaces(), "split multiple consecutive whitespaces");
- TEST(t_detach(), "detach");
+ if_test ("static initialization") {
+ struct strvec vec = STRVEC_INIT;
+ check_pointer_eq(vec.v, empty_strvec);
+ check_uint(vec.nr, ==, 0);
+ check_uint(vec.alloc, ==, 0);
+ }
+
+ if_test ("dynamic initialization") {
+ struct strvec vec;
+ strvec_init(&vec);
+ check_pointer_eq(vec.v, empty_strvec);
+ check_uint(vec.nr, ==, 0);
+ check_uint(vec.alloc, ==, 0);
+ }
+
+ if_test ("clear") {
+ struct strvec vec = STRVEC_INIT;
+ strvec_push(&vec, "foo");
+ strvec_clear(&vec);
+ check_pointer_eq(vec.v, empty_strvec);
+ check_uint(vec.nr, ==, 0);
+ check_uint(vec.alloc, ==, 0);
+ }
+
+ if_test ("push") {
+ struct strvec vec = STRVEC_INIT;
+
+ strvec_push(&vec, "foo");
+ check_strvec(&vec, "foo", NULL);
+
+ strvec_push(&vec, "bar");
+ check_strvec(&vec, "foo", "bar", NULL);
+
+ strvec_clear(&vec);
+ }
+
+ if_test ("pushf") {
+ struct strvec vec = STRVEC_INIT;
+ strvec_pushf(&vec, "foo: %d", 1);
+ check_strvec(&vec, "foo: 1", NULL);
+ strvec_clear(&vec);
+ }
+
+ if_test ("pushl") {
+ struct strvec vec = STRVEC_INIT;
+ strvec_pushl(&vec, "foo", "bar", "baz", NULL);
+ check_strvec(&vec, "foo", "bar", "baz", NULL);
+ strvec_clear(&vec);
+ }
+
+ if_test ("pushv") {
+ const char *strings[] = {
+ "foo", "bar", "baz", NULL,
+ };
+ struct strvec vec = STRVEC_INIT;
+
+ strvec_pushv(&vec, strings);
+ check_strvec(&vec, "foo", "bar", "baz", NULL);
+
+ strvec_clear(&vec);
+ }
+
+ if_test ("replace at head") {
+ struct strvec vec = STRVEC_INIT;
+ strvec_pushl(&vec, "foo", "bar", "baz", NULL);
+ strvec_replace(&vec, 0, "replaced");
+ check_strvec(&vec, "replaced", "bar", "baz", NULL);
+ strvec_clear(&vec);
+ }
+
+ if_test ("replace at tail") {
+ struct strvec vec = STRVEC_INIT;
+ strvec_pushl(&vec, "foo", "bar", "baz", NULL);
+ strvec_replace(&vec, 2, "replaced");
+ check_strvec(&vec, "foo", "bar", "replaced", NULL);
+ strvec_clear(&vec);
+ }
+
+ if_test ("replace in between") {
+ struct strvec vec = STRVEC_INIT;
+ strvec_pushl(&vec, "foo", "bar", "baz", NULL);
+ strvec_replace(&vec, 1, "replaced");
+ check_strvec(&vec, "foo", "replaced", "baz", NULL);
+ strvec_clear(&vec);
+ }
+
+ if_test ("replace with substring") {
+ struct strvec vec = STRVEC_INIT;
+ strvec_pushl(&vec, "foo", NULL);
+ strvec_replace(&vec, 0, vec.v[0] + 1);
+ check_strvec(&vec, "oo", NULL);
+ strvec_clear(&vec);
+ }
+
+ if_test ("remove at head") {
+ struct strvec vec = STRVEC_INIT;
+ strvec_pushl(&vec, "foo", "bar", "baz", NULL);
+ strvec_remove(&vec, 0);
+ check_strvec(&vec, "bar", "baz", NULL);
+ strvec_clear(&vec);
+ }
+
+ if_test ("remove at tail") {
+ struct strvec vec = STRVEC_INIT;
+ strvec_pushl(&vec, "foo", "bar", "baz", NULL);
+ strvec_remove(&vec, 2);
+ check_strvec(&vec, "foo", "bar", NULL);
+ strvec_clear(&vec);
+ }
+
+ if_test ("remove in between") {
+ struct strvec vec = STRVEC_INIT;
+ strvec_pushl(&vec, "foo", "bar", "baz", NULL);
+ strvec_remove(&vec, 1);
+ check_strvec(&vec, "foo", "baz", NULL);
+ strvec_clear(&vec);
+ }
+
+ if_test ("pop with empty array") {
+ struct strvec vec = STRVEC_INIT;
+ strvec_pop(&vec);
+ check_strvec(&vec, NULL);
+ strvec_clear(&vec);
+ }
+
+ if_test ("pop with non-empty array") {
+ struct strvec vec = STRVEC_INIT;
+ strvec_pushl(&vec, "foo", "bar", "baz", NULL);
+ strvec_pop(&vec);
+ check_strvec(&vec, "foo", "bar", NULL);
+ strvec_clear(&vec);
+ }
+
+ if_test ("split empty string") {
+ struct strvec vec = STRVEC_INIT;
+ strvec_split(&vec, "");
+ check_strvec(&vec, NULL);
+ strvec_clear(&vec);
+ }
+
+ if_test ("split single item") {
+ struct strvec vec = STRVEC_INIT;
+ strvec_split(&vec, "foo");
+ check_strvec(&vec, "foo", NULL);
+ strvec_clear(&vec);
+ }
+
+ if_test ("split multiple items") {
+ struct strvec vec = STRVEC_INIT;
+ strvec_split(&vec, "foo bar baz");
+ check_strvec(&vec, "foo", "bar", "baz", NULL);
+ strvec_clear(&vec);
+ }
+
+ if_test ("split whitespace only") {
+ struct strvec vec = STRVEC_INIT;
+ strvec_split(&vec, " \t\n");
+ check_strvec(&vec, NULL);
+ strvec_clear(&vec);
+ }
+
+ if_test ("split multiple consecutive whitespaces") {
+ struct strvec vec = STRVEC_INIT;
+ strvec_split(&vec, "foo\n\t bar");
+ check_strvec(&vec, "foo", "bar", NULL);
+ strvec_clear(&vec);
+ }
+
+ if_test ("detach") {
+ struct strvec vec = STRVEC_INIT;
+ const char **detached;
+
+ strvec_push(&vec, "foo");
+
+ detached = strvec_detach(&vec);
+ check_str(detached[0], "foo");
+ check_pointer_eq(detached[1], NULL);
+
+ check_pointer_eq(vec.v, empty_strvec);
+ check_uint(vec.nr, ==, 0);
+ check_uint(vec.alloc, ==, 0);
+
+ free((char *) detached[0]);
+ free(detached);
+ }
+
return test_done();
}
diff --git a/t/unit-tests/test-lib.c b/t/unit-tests/test-lib.c
index 3c513ce59a..fa1f95965c 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 location[100];
+ char description[100];
} ctx = {
.lazy_plan = 1,
.result = RESULT_NONE,
@@ -125,6 +127,8 @@ void test_plan(int count)
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);
if (ctx.lazy_plan)
@@ -167,13 +171,38 @@ void test_skip_all(const char *format, ...)
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)
{
+ if (ctx.running && ctx.location[0] && ctx.description[0])
+ test__run_end(1, ctx.location, "%s", ctx.description);
assert(!ctx.running);
ctx.count++;
ctx.result = RESULT_NONE;
ctx.running = 1;
+ ctx.location[0] = '\0';
+ ctx.description[0] = '\0';
return ctx.skip_all;
}
@@ -264,7 +293,12 @@ static void test_todo(void)
int test_assert(const char *location, const char *check, int ok)
{
- assert(ctx.running);
+ if (!ctx.running) {
+ test_msg("BUG: check outside of test at %s",
+ make_relative(location));
+ ctx.failed = 1;
+ return 0;
+ }
if (ctx.result == RESULT_SKIP) {
test_msg("skipping check '%s' at %s", check,
diff --git a/t/unit-tests/test-lib.h b/t/unit-tests/test-lib.h
index c59f646fd9..e4b234697f 100644
--- a/t/unit-tests/test-lib.h
+++ b/t/unit-tests/test-lib.h
@@ -15,6 +15,23 @@
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
* of tests is not known in advance test_done() will automatically
* print a plan at the end of the test program.
@@ -154,6 +171,9 @@ union test__tmp {
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);
__attribute__((format (printf, 3, 4)))
int test__run_end(int, const char *, const char *, ...);