Changes since v3: - Replace for_test with if_test, a more robust conditional-like macro. It stores description and location like v1, but without using strbuf. - Drop patch 7 for t-strbuf to avoid hindering Kyle's cleanup idea. Side note: Created with --creation-factor=60, as the default of 999 in v2.46.0 pairs dropped patch 7 with new patch 4 and reports old patch 4 as dropped, which is confusing. t0080: use here-doc test body unit-tests: show location of checks outside of tests unit-tests: add if_test t-ctype: use if_test t-reftable-basics: use if_test t-strvec: use if_test .clang-format | 5 + t/helper/test-example-tap.c | 35 +++ t/t0080-unit-test-output.sh | 60 ++++-- t/unit-tests/t-ctype.c | 4 +- t/unit-tests/t-reftable-basics.c | 228 +++++++++----------- t/unit-tests/t-strvec.c | 356 ++++++++++++++----------------- t/unit-tests/test-lib.c | 36 +++- t/unit-tests/test-lib.h | 20 ++ 8 files changed, 405 insertions(+), 339 deletions(-) Range-Diff gegen v3: 1: 497002df9e = 1: 497002df9e t0080: use here-doc test body 2: 0c1503fb5a = 2: f85d4f9455 unit-tests: show location of checks outside of tests 3: 27f1f18b3d < -: ---------- unit-tests: add for_test -: ---------- > 3: 77c7dfa1ad unit-tests: add if_test 4: 98a1e7abdf ! 4: 63fba50876 t-ctype: use for_test @@ Metadata Author: René Scharfe <l.s.r@xxxxxx> ## Commit message ## - t-ctype: use for_test + t-ctype: use if_test - Use the documented macro for_test instead of the internal functions + Use the documented macro if_test instead of the internal functions test__run_begin() and test__run_end(), which are supposed to be private to the unit test framework. @@ t/unit-tests/t-ctype.c BUILD_ASSERT_OR_ZERO(sizeof(string[0]) == sizeof(char)); \ - int skip = test__run_begin(); \ - if (!skip) { \ -+ for_test (#class " works") { \ ++ 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); \ 5: 7c954f0864 ! 5: ab86673484 t-reftable-basics: use for_test @@ Metadata Author: René Scharfe <l.s.r@xxxxxx> ## Commit message ## - t-reftable-basics: use for_test + t-reftable-basics: use if_test The macro TEST takes a single expression. If a test requires multiple statements then they need to be placed in a function that's called in the TEST expression. Remove the overhead of defining and calling single-use functions by - using for_test instead. + using if_test instead. Run the tests in the order of definition. We can reorder them like that because they are independent. Technically this changes the output, but @@ t/unit-tests/t-reftable-basics.c: static int integer_needle_lesseq(size_t i, voi - struct integer_needle_lesseq_args args = { - .haystack = haystack, - .needle = testcases[i].needle, -+ for_test ("binary search with binsearch works") { ++ if_test ("binary search with binsearch works") { + int haystack[] = { 2, 4, 6, 8, 10 }; + struct { + int needle; @@ t/unit-tests/t-reftable-basics.c: static int integer_needle_lesseq(size_t i, voi - const char *a[] = { "a", "b", "c", NULL }; - const char *b[] = { "a", "b", "d", NULL }; - const char *c[] = { "a", "b", NULL }; -+ for_test ("names_length retuns size of a NULL-terminated string array") { ++ if_test ("names_length retuns size of a NULL-terminated string array") { + const char *a[] = { "a", "b", NULL }; + check_int(names_length(a), ==, 2); + } @@ t/unit-tests/t-reftable-basics.c: static int integer_needle_lesseq(size_t i, voi - check(!names_equal(a, b)); - check(!names_equal(a, c)); -} -+ for_test ("names_equal compares NULL-terminated string arrays") { ++ 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 }; @@ t/unit-tests/t-reftable-basics.c: static int integer_needle_lesseq(size_t i, voi - check(!out[2]); - free_names(out); -} -+ for_test ("parse_names works for basic input") { ++ if_test ("parse_names works for basic input") { + char in1[] = "line\n"; + char in2[] = "a\nb\nc"; + char **out = NULL; @@ t/unit-tests/t-reftable-basics.c: static int integer_needle_lesseq(size_t i, voi - check_int(common_prefix_size(&a, &b), ==, cases[i].want); - strbuf_reset(&a); - strbuf_reset(&b); -+ for_test ("parse_names drops empty string") { ++ if_test ("parse_names drops empty string") { + char in[] = "a\n\nb\n"; + char **out = NULL; + parse_names(in, strlen(in), &out); @@ t/unit-tests/t-reftable-basics.c: static int integer_needle_lesseq(size_t i, voi - out = get_be24(dest); - check_int(in, ==, out); -} -+ for_test ("common_prefix_size works") { ++ if_test ("common_prefix_size works") { + struct strbuf a = STRBUF_INIT; + struct strbuf b = STRBUF_INIT; + struct { @@ t/unit-tests/t-reftable-basics.c: static int integer_needle_lesseq(size_t i, voi - 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"); -+ for_test ("put_be24 and get_be24 work") { ++ if_test ("put_be24 and get_be24 work") { + uint32_t in = 0x112233; + uint8_t dest[3]; + uint32_t out; @@ t/unit-tests/t-reftable-basics.c: static int integer_needle_lesseq(size_t i, voi + check_int(in, ==, out); + } + -+ for_test ("put_be16 and get_be16 work") { ++ if_test ("put_be16 and get_be16 work") { + uint32_t in = 0xfef1; + uint8_t dest[3]; + uint32_t out; 6: d619a756d7 ! 6: 64bb731ba6 t-strvec: use for_test @@ Metadata Author: René Scharfe <l.s.r@xxxxxx> ## Commit message ## - t-strvec: use for_test + t-strvec: use if_test The macro TEST takes a single expression. If a test requires multiple statements then they need to be placed in a function that's called in the TEST expression. Remove the cognitive overhead of defining and calling single-use - functions by using for_test instead. + functions by using if_test instead. + + Signed-off-by: René Scharfe <l.s.r@xxxxxx> ## t/unit-tests/t-strvec.c ## @@ t/unit-tests/t-strvec.c: static void check_strvec_loc(const char *loc, struct strvec *vec, ...) @@ t/unit-tests/t-strvec.c: static void check_strvec_loc(const char *loc, struct st - check_uint(vec.nr, ==, 0); - check_uint(vec.alloc, ==, 0); -} -+ for_test ("static initialization") { ++ if_test ("static initialization") { + struct strvec vec = STRVEC_INIT; + check_pointer_eq(vec.v, empty_strvec); + check_uint(vec.nr, ==, 0); @@ t/unit-tests/t-strvec.c: static void check_strvec_loc(const char *loc, struct st - check_uint(vec.nr, ==, 0); - check_uint(vec.alloc, ==, 0); -} -+ for_test ("dynamic initialization") { ++ if_test ("dynamic initialization") { + struct strvec vec; + strvec_init(&vec); + check_pointer_eq(vec.v, empty_strvec); @@ t/unit-tests/t-strvec.c: static void check_strvec_loc(const char *loc, struct st - check_uint(vec.nr, ==, 0); - check_uint(vec.alloc, ==, 0); -} -+ for_test ("clear") { ++ if_test ("clear") { + struct strvec vec = STRVEC_INIT; + strvec_push(&vec, "foo"); + strvec_clear(&vec); @@ t/unit-tests/t-strvec.c: static void check_strvec_loc(const char *loc, struct st -static void t_push(void) -{ - struct strvec vec = STRVEC_INIT; -+ for_test ("push") { ++ if_test ("push") { + struct strvec vec = STRVEC_INIT; - strvec_push(&vec, "foo"); @@ t/unit-tests/t-strvec.c: static void check_strvec_loc(const char *loc, struct st - check_strvec(&vec, "foo: 1", NULL); - strvec_clear(&vec); -} -+ for_test ("pushf") { ++ if_test ("pushf") { + struct strvec vec = STRVEC_INIT; + strvec_pushf(&vec, "foo: %d", 1); + check_strvec(&vec, "foo: 1", NULL); @@ t/unit-tests/t-strvec.c: static void check_strvec_loc(const char *loc, struct st - check_strvec(&vec, "foo", "bar", "baz", NULL); - strvec_clear(&vec); -} -+ for_test ("pushl") { ++ if_test ("pushl") { + struct strvec vec = STRVEC_INIT; + strvec_pushl(&vec, "foo", "bar", "baz", NULL); + check_strvec(&vec, "foo", "bar", "baz", NULL); @@ t/unit-tests/t-strvec.c: static void check_strvec_loc(const char *loc, struct st - "foo", "bar", "baz", NULL, - }; - struct strvec vec = STRVEC_INIT; -+ for_test ("pushv") { ++ if_test ("pushv") { + const char *strings[] = { + "foo", "bar", "baz", NULL, + }; @@ t/unit-tests/t-strvec.c: static void check_strvec_loc(const char *loc, struct st - check_strvec(&vec, "replaced", "bar", "baz", NULL); - strvec_clear(&vec); -} -+ for_test ("replace at head") { ++ if_test ("replace at head") { + struct strvec vec = STRVEC_INIT; + strvec_pushl(&vec, "foo", "bar", "baz", NULL); + strvec_replace(&vec, 0, "replaced"); @@ t/unit-tests/t-strvec.c: static void check_strvec_loc(const char *loc, struct st - check_strvec(&vec, "foo", "bar", "replaced", NULL); - strvec_clear(&vec); -} -+ for_test ("replace at tail") { ++ if_test ("replace at tail") { + struct strvec vec = STRVEC_INIT; + strvec_pushl(&vec, "foo", "bar", "baz", NULL); + strvec_replace(&vec, 2, "replaced"); @@ t/unit-tests/t-strvec.c: static void check_strvec_loc(const char *loc, struct st - check_strvec(&vec, "foo", "replaced", "baz", NULL); - strvec_clear(&vec); -} -+ for_test ("replace in between") { ++ if_test ("replace in between") { + struct strvec vec = STRVEC_INIT; + strvec_pushl(&vec, "foo", "bar", "baz", NULL); + strvec_replace(&vec, 1, "replaced"); @@ t/unit-tests/t-strvec.c: static void check_strvec_loc(const char *loc, struct st - check_strvec(&vec, "oo", NULL); - strvec_clear(&vec); -} -+ for_test ("replace with substring") { ++ if_test ("replace with substring") { + struct strvec vec = STRVEC_INIT; + strvec_pushl(&vec, "foo", NULL); + strvec_replace(&vec, 0, vec.v[0] + 1); @@ t/unit-tests/t-strvec.c: static void check_strvec_loc(const char *loc, struct st - check_strvec(&vec, "bar", "baz", NULL); - strvec_clear(&vec); -} -+ for_test ("remove at head") { ++ if_test ("remove at head") { + struct strvec vec = STRVEC_INIT; + strvec_pushl(&vec, "foo", "bar", "baz", NULL); + strvec_remove(&vec, 0); @@ t/unit-tests/t-strvec.c: static void check_strvec_loc(const char *loc, struct st - check_strvec(&vec, "foo", "bar", NULL); - strvec_clear(&vec); -} -+ for_test ("remove at tail") { ++ if_test ("remove at tail") { + struct strvec vec = STRVEC_INIT; + strvec_pushl(&vec, "foo", "bar", "baz", NULL); + strvec_remove(&vec, 2); @@ t/unit-tests/t-strvec.c: static void check_strvec_loc(const char *loc, struct st - check_strvec(&vec, "foo", "baz", NULL); - strvec_clear(&vec); -} -+ for_test ("remove in between") { ++ if_test ("remove in between") { + struct strvec vec = STRVEC_INIT; + strvec_pushl(&vec, "foo", "bar", "baz", NULL); + strvec_remove(&vec, 1); @@ t/unit-tests/t-strvec.c: static void check_strvec_loc(const char *loc, struct st - check_strvec(&vec, NULL); - strvec_clear(&vec); -} -+ for_test ("pop with empty array") { ++ if_test ("pop with empty array") { + struct strvec vec = STRVEC_INIT; + strvec_pop(&vec); + check_strvec(&vec, NULL); @@ t/unit-tests/t-strvec.c: static void check_strvec_loc(const char *loc, struct st - check_strvec(&vec, "foo", "bar", NULL); - strvec_clear(&vec); -} -+ for_test ("pop with non-empty array") { ++ if_test ("pop with non-empty array") { + struct strvec vec = STRVEC_INIT; + strvec_pushl(&vec, "foo", "bar", "baz", NULL); + strvec_pop(&vec); @@ t/unit-tests/t-strvec.c: static void check_strvec_loc(const char *loc, struct st - check_strvec(&vec, NULL); - strvec_clear(&vec); -} -+ for_test ("split empty string") { ++ if_test ("split empty string") { + struct strvec vec = STRVEC_INIT; + strvec_split(&vec, ""); + check_strvec(&vec, NULL); @@ t/unit-tests/t-strvec.c: static void check_strvec_loc(const char *loc, struct st - check_strvec(&vec, "foo", NULL); - strvec_clear(&vec); -} -+ for_test ("split single item") { ++ if_test ("split single item") { + struct strvec vec = STRVEC_INIT; + strvec_split(&vec, "foo"); + check_strvec(&vec, "foo", NULL); @@ t/unit-tests/t-strvec.c: static void check_strvec_loc(const char *loc, struct st - check_strvec(&vec, "foo", "bar", "baz", NULL); - strvec_clear(&vec); -} -+ for_test ("split multiple items") { ++ if_test ("split multiple items") { + struct strvec vec = STRVEC_INIT; + strvec_split(&vec, "foo bar baz"); + check_strvec(&vec, "foo", "bar", "baz", NULL); @@ t/unit-tests/t-strvec.c: static void check_strvec_loc(const char *loc, struct st - check_strvec(&vec, NULL); - strvec_clear(&vec); -} -+ for_test ("split whitespace only") { ++ if_test ("split whitespace only") { + struct strvec vec = STRVEC_INIT; + strvec_split(&vec, " \t\n"); + check_strvec(&vec, NULL); @@ t/unit-tests/t-strvec.c: static void check_strvec_loc(const char *loc, struct st - check_strvec(&vec, "foo", "bar", NULL); - strvec_clear(&vec); -} -+ for_test ("split multiple consecutive whitespaces") { ++ if_test ("split multiple consecutive whitespaces") { + struct strvec vec = STRVEC_INIT; + strvec_split(&vec, "foo\n\t bar"); + check_strvec(&vec, "foo", "bar", NULL); @@ t/unit-tests/t-strvec.c: static void check_strvec_loc(const char *loc, struct st -{ - struct strvec vec = STRVEC_INIT; - const char **detached; -+ for_test ("detach") { ++ if_test ("detach") { + struct strvec vec = STRVEC_INIT; + const char **detached; 7: ea088728ad < -: ---------- t-strbuf: use for_test -- 2.46.0