Git fork

Merge branch 'rs/unit-tests-test-run'

Unit-test framework has learned a simple control structure to allow
embedding test statements in-line instead of having to create a new
function to contain them.

* rs/unit-tests-test-run:
t-strvec: use if_test
t-reftable-basics: use if_test
t-ctype: use if_test
unit-tests: add if_test
unit-tests: show location of checks outside of tests
t0080: use here-doc test body

+403 -337
+5
.clang-format
··· 196 196 - 'strmap_for_each_entry' 197 197 - 'strset_for_each_entry' 198 198 199 + # A list of macros that should be interpreted as conditionals instead of as 200 + # function calls. 201 + IfMacros: 202 + - 'if_test' 203 + 199 204 # The maximum number of consecutive empty lines to keep. 200 205 MaxEmptyLinesToKeep: 1 201 206
+35
t/helper/test-example-tap.c
··· 72 72 73 73 int cmd__example_tap(int argc, const char **argv) 74 74 { 75 + check(1); 76 + 75 77 test_res = TEST(check_res = check_int(1, ==, 1), "passing test"); 76 78 TEST(t_res(1), "passing test and assertion return 1"); 77 79 test_res = TEST(check_res = check_int(1, ==, 2), "failing test"); ··· 91 93 TEST(t_messages(), "messages from failing string and char comparison"); 92 94 test_res = TEST(t_empty(), "test with no checks"); 93 95 TEST(check_int(test_res, ==, 0), "test with no checks returns 0"); 96 + 97 + if_test ("if_test passing test") 98 + check_int(1, ==, 1); 99 + if_test ("if_test failing test") 100 + check_int(1, ==, 2); 101 + if_test ("if_test passing TEST_TODO()") 102 + TEST_TODO(check(0)); 103 + if_test ("if_test failing TEST_TODO()") 104 + TEST_TODO(check(1)); 105 + if_test ("if_test test_skip()") { 106 + check(0); 107 + test_skip("missing prerequisite"); 108 + check(1); 109 + } 110 + if_test ("if_test test_skip() inside TEST_TODO()") 111 + TEST_TODO((test_skip("missing prerequisite"), 1)); 112 + if_test ("if_test TEST_TODO() after failing check") { 113 + check(0); 114 + TEST_TODO(check(0)); 115 + } 116 + if_test ("if_test failing check after TEST_TODO()") { 117 + check(1); 118 + TEST_TODO(check(0)); 119 + check(0); 120 + } 121 + if_test ("if_test messages from failing string and char comparison") { 122 + check_str("\thello\\", "there\"\n"); 123 + check_str("NULL", NULL); 124 + check_char('a', ==, '\n'); 125 + check_char('\\', ==, '\''); 126 + } 127 + if_test ("if_test test with no checks") 128 + ; /* nothing */ 94 129 95 130 return test_done(); 96 131 }
+47 -13
t/t0080-unit-test-output.sh
··· 5 5 TEST_PASSES_SANITIZE_LEAK=true 6 6 . ./test-lib.sh 7 7 8 - test_expect_success 'TAP output from unit tests' ' 8 + test_expect_success 'TAP output from unit tests' - <<\EOT 9 9 cat >expect <<-EOF && 10 + # BUG: check outside of test at t/helper/test-example-tap.c:75 10 11 ok 1 - passing test 11 12 ok 2 - passing test and assertion return 1 12 - # check "1 == 2" failed at t/helper/test-example-tap.c:77 13 + # check "1 == 2" failed at t/helper/test-example-tap.c:79 13 14 # left: 1 14 15 # right: 2 15 16 not ok 3 - failing test 16 17 ok 4 - failing test and assertion return 0 17 18 not ok 5 - passing TEST_TODO() # TODO 18 19 ok 6 - passing TEST_TODO() returns 1 19 - # todo check ${SQ}check(x)${SQ} succeeded at t/helper/test-example-tap.c:26 20 + # todo check 'check(x)' succeeded at t/helper/test-example-tap.c:26 20 21 not ok 7 - failing TEST_TODO() 21 22 ok 8 - failing TEST_TODO() returns 0 22 23 # check "0" failed at t/helper/test-example-tap.c:31 23 24 # skipping test - missing prerequisite 24 - # skipping check ${SQ}1${SQ} at t/helper/test-example-tap.c:33 25 + # skipping check '1' at t/helper/test-example-tap.c:33 25 26 ok 9 - test_skip() # SKIP 26 27 ok 10 - skipped test returns 1 27 28 # skipping test - missing prerequisite ··· 39 40 # check "!strcmp("NULL", NULL)" failed at t/helper/test-example-tap.c:63 40 41 # left: "NULL" 41 42 # right: NULL 42 - # check "${SQ}a${SQ} == ${SQ}\n${SQ}" failed at t/helper/test-example-tap.c:64 43 - # left: ${SQ}a${SQ} 44 - # right: ${SQ}\012${SQ} 45 - # check "${SQ}\\\\${SQ} == ${SQ}\\${SQ}${SQ}" failed at t/helper/test-example-tap.c:65 46 - # left: ${SQ}\\\\${SQ} 47 - # right: ${SQ}\\${SQ}${SQ} 43 + # check "'a' == '\n'" failed at t/helper/test-example-tap.c:64 44 + # left: 'a' 45 + # right: '\012' 46 + # check "'\\\\' == '\\''" failed at t/helper/test-example-tap.c:65 47 + # left: '\\\\' 48 + # right: '\\'' 48 49 not ok 17 - messages from failing string and char comparison 49 - # BUG: test has no checks at t/helper/test-example-tap.c:92 50 + # BUG: test has no checks at t/helper/test-example-tap.c:94 50 51 not ok 18 - test with no checks 51 52 ok 19 - test with no checks returns 0 52 - 1..19 53 + ok 20 - if_test passing test 54 + # check "1 == 2" failed at t/helper/test-example-tap.c:100 55 + # left: 1 56 + # right: 2 57 + not ok 21 - if_test failing test 58 + not ok 22 - if_test passing TEST_TODO() # TODO 59 + # todo check 'check(1)' succeeded at t/helper/test-example-tap.c:104 60 + not ok 23 - if_test failing TEST_TODO() 61 + # check "0" failed at t/helper/test-example-tap.c:106 62 + # skipping test - missing prerequisite 63 + # skipping check '1' at t/helper/test-example-tap.c:108 64 + ok 24 - if_test test_skip() # SKIP 65 + # skipping test - missing prerequisite 66 + ok 25 - if_test test_skip() inside TEST_TODO() # SKIP 67 + # check "0" failed at t/helper/test-example-tap.c:113 68 + not ok 26 - if_test TEST_TODO() after failing check 69 + # check "0" failed at t/helper/test-example-tap.c:119 70 + not ok 27 - if_test failing check after TEST_TODO() 71 + # check "!strcmp("\thello\\\\", "there\"\n")" failed at t/helper/test-example-tap.c:122 72 + # left: "\011hello\\\\" 73 + # right: "there\"\012" 74 + # check "!strcmp("NULL", NULL)" failed at t/helper/test-example-tap.c:123 75 + # left: "NULL" 76 + # right: NULL 77 + # check "'a' == '\n'" failed at t/helper/test-example-tap.c:124 78 + # left: 'a' 79 + # right: '\012' 80 + # check "'\\\\' == '\\''" failed at t/helper/test-example-tap.c:125 81 + # left: '\\\\' 82 + # right: '\\'' 83 + not ok 28 - if_test messages from failing string and char comparison 84 + # BUG: test has no checks at t/helper/test-example-tap.c:127 85 + not ok 29 - if_test test with no checks 86 + 1..29 53 87 EOF 54 88 55 89 ! test-tool example-tap >actual && 56 90 test_cmp expect actual 57 - ' 91 + EOT 58 92 59 93 test_done
+1 -3
t/unit-tests/t-ctype.c
··· 4 4 size_t len = ARRAY_SIZE(string) - 1 + \ 5 5 BUILD_ASSERT_OR_ZERO(ARRAY_SIZE(string) > 0) + \ 6 6 BUILD_ASSERT_OR_ZERO(sizeof(string[0]) == sizeof(char)); \ 7 - int skip = test__run_begin(); \ 8 - if (!skip) { \ 7 + if_test (#class " works") { \ 9 8 for (int i = 0; i < 256; i++) { \ 10 9 if (!check_int(class(i), ==, !!memchr(string, i, len)))\ 11 10 test_msg(" i: 0x%02x", i); \ 12 11 } \ 13 12 check(!class(EOF)); \ 14 13 } \ 15 - test__run_end(!skip, TEST_LOCATION(), #class " works"); \ 16 14 } while (0) 17 15 18 16 #define DIGIT "0123456789"
+104 -120
t/unit-tests/t-reftable-basics.c
··· 20 20 return args->needle <= args->haystack[i]; 21 21 } 22 22 23 - static void test_binsearch(void) 23 + int cmd_main(int argc, const char *argv[]) 24 24 { 25 - int haystack[] = { 2, 4, 6, 8, 10 }; 26 - struct { 27 - int needle; 28 - size_t expected_idx; 29 - } testcases[] = { 30 - {-9000, 0}, 31 - {-1, 0}, 32 - {0, 0}, 33 - {2, 0}, 34 - {3, 1}, 35 - {4, 1}, 36 - {7, 3}, 37 - {9, 4}, 38 - {10, 4}, 39 - {11, 5}, 40 - {9000, 5}, 41 - }; 42 - 43 - for (size_t i = 0; i < ARRAY_SIZE(testcases); i++) { 44 - struct integer_needle_lesseq_args args = { 45 - .haystack = haystack, 46 - .needle = testcases[i].needle, 25 + if_test ("binary search with binsearch works") { 26 + int haystack[] = { 2, 4, 6, 8, 10 }; 27 + struct { 28 + int needle; 29 + size_t expected_idx; 30 + } testcases[] = { 31 + {-9000, 0}, 32 + {-1, 0}, 33 + {0, 0}, 34 + {2, 0}, 35 + {3, 1}, 36 + {4, 1}, 37 + {7, 3}, 38 + {9, 4}, 39 + {10, 4}, 40 + {11, 5}, 41 + {9000, 5}, 47 42 }; 48 - size_t idx; 49 43 50 - idx = binsearch(ARRAY_SIZE(haystack), &integer_needle_lesseq, &args); 51 - check_int(idx, ==, testcases[i].expected_idx); 44 + for (size_t i = 0; i < ARRAY_SIZE(testcases); i++) { 45 + struct integer_needle_lesseq_args args = { 46 + .haystack = haystack, 47 + .needle = testcases[i].needle, 48 + }; 49 + size_t idx; 50 + 51 + idx = binsearch(ARRAY_SIZE(haystack), 52 + &integer_needle_lesseq, &args); 53 + check_int(idx, ==, testcases[i].expected_idx); 54 + } 52 55 } 53 - } 54 56 55 - static void test_names_length(void) 56 - { 57 - const char *a[] = { "a", "b", NULL }; 58 - check_int(names_length(a), ==, 2); 59 - } 57 + if_test ("names_length retuns size of a NULL-terminated string array") { 58 + const char *a[] = { "a", "b", NULL }; 59 + check_int(names_length(a), ==, 2); 60 + } 60 61 61 - static void test_names_equal(void) 62 - { 63 - const char *a[] = { "a", "b", "c", NULL }; 64 - const char *b[] = { "a", "b", "d", NULL }; 65 - const char *c[] = { "a", "b", NULL }; 62 + if_test ("names_equal compares NULL-terminated string arrays") { 63 + const char *a[] = { "a", "b", "c", NULL }; 64 + const char *b[] = { "a", "b", "d", NULL }; 65 + const char *c[] = { "a", "b", NULL }; 66 66 67 - check(names_equal(a, a)); 68 - check(!names_equal(a, b)); 69 - check(!names_equal(a, c)); 70 - } 67 + check(names_equal(a, a)); 68 + check(!names_equal(a, b)); 69 + check(!names_equal(a, c)); 70 + } 71 71 72 - static void test_parse_names_normal(void) 73 - { 74 - char in1[] = "line\n"; 75 - char in2[] = "a\nb\nc"; 76 - char **out = NULL; 77 - parse_names(in1, strlen(in1), &out); 78 - check_str(out[0], "line"); 79 - check(!out[1]); 80 - free_names(out); 72 + if_test ("parse_names works for basic input") { 73 + char in1[] = "line\n"; 74 + char in2[] = "a\nb\nc"; 75 + char **out = NULL; 76 + parse_names(in1, strlen(in1), &out); 77 + check_str(out[0], "line"); 78 + check(!out[1]); 79 + free_names(out); 81 80 82 - parse_names(in2, strlen(in2), &out); 83 - check_str(out[0], "a"); 84 - check_str(out[1], "b"); 85 - check_str(out[2], "c"); 86 - check(!out[3]); 87 - free_names(out); 88 - } 81 + parse_names(in2, strlen(in2), &out); 82 + check_str(out[0], "a"); 83 + check_str(out[1], "b"); 84 + check_str(out[2], "c"); 85 + check(!out[3]); 86 + free_names(out); 87 + } 89 88 90 - static void test_parse_names_drop_empty(void) 91 - { 92 - char in[] = "a\n\nb\n"; 93 - char **out = NULL; 94 - parse_names(in, strlen(in), &out); 95 - check_str(out[0], "a"); 96 - /* simply '\n' should be dropped as empty string */ 97 - check_str(out[1], "b"); 98 - check(!out[2]); 99 - free_names(out); 100 - } 89 + if_test ("parse_names drops empty string") { 90 + char in[] = "a\n\nb\n"; 91 + char **out = NULL; 92 + parse_names(in, strlen(in), &out); 93 + check_str(out[0], "a"); 94 + /* simply '\n' should be dropped as empty string */ 95 + check_str(out[1], "b"); 96 + check(!out[2]); 97 + free_names(out); 98 + } 101 99 102 - static void test_common_prefix(void) 103 - { 104 - struct strbuf a = STRBUF_INIT; 105 - struct strbuf b = STRBUF_INIT; 106 - struct { 107 - const char *a, *b; 108 - int want; 109 - } cases[] = { 110 - {"abcdef", "abc", 3}, 111 - { "abc", "ab", 2 }, 112 - { "", "abc", 0 }, 113 - { "abc", "abd", 2 }, 114 - { "abc", "pqr", 0 }, 115 - }; 100 + if_test ("common_prefix_size works") { 101 + struct strbuf a = STRBUF_INIT; 102 + struct strbuf b = STRBUF_INIT; 103 + struct { 104 + const char *a, *b; 105 + int want; 106 + } cases[] = { 107 + {"abcdef", "abc", 3}, 108 + { "abc", "ab", 2 }, 109 + { "", "abc", 0 }, 110 + { "abc", "abd", 2 }, 111 + { "abc", "pqr", 0 }, 112 + }; 116 113 117 - for (size_t i = 0; i < ARRAY_SIZE(cases); i++) { 118 - strbuf_addstr(&a, cases[i].a); 119 - strbuf_addstr(&b, cases[i].b); 120 - check_int(common_prefix_size(&a, &b), ==, cases[i].want); 121 - strbuf_reset(&a); 122 - strbuf_reset(&b); 114 + for (size_t i = 0; i < ARRAY_SIZE(cases); i++) { 115 + strbuf_addstr(&a, cases[i].a); 116 + strbuf_addstr(&b, cases[i].b); 117 + check_int(common_prefix_size(&a, &b), ==, cases[i].want); 118 + strbuf_reset(&a); 119 + strbuf_reset(&b); 120 + } 121 + strbuf_release(&a); 122 + strbuf_release(&b); 123 123 } 124 - strbuf_release(&a); 125 - strbuf_release(&b); 126 - } 127 124 128 - static void test_u24_roundtrip(void) 129 - { 130 - uint32_t in = 0x112233; 131 - uint8_t dest[3]; 132 - uint32_t out; 133 - put_be24(dest, in); 134 - out = get_be24(dest); 135 - check_int(in, ==, out); 136 - } 137 - 138 - static void test_u16_roundtrip(void) 139 - { 140 - uint32_t in = 0xfef1; 141 - uint8_t dest[3]; 142 - uint32_t out; 143 - put_be16(dest, in); 144 - out = get_be16(dest); 145 - check_int(in, ==, out); 146 - } 125 + if_test ("put_be24 and get_be24 work") { 126 + uint32_t in = 0x112233; 127 + uint8_t dest[3]; 128 + uint32_t out; 129 + put_be24(dest, in); 130 + out = get_be24(dest); 131 + check_int(in, ==, out); 132 + } 147 133 148 - int cmd_main(int argc, const char *argv[]) 149 - { 150 - TEST(test_common_prefix(), "common_prefix_size works"); 151 - TEST(test_parse_names_normal(), "parse_names works for basic input"); 152 - TEST(test_parse_names_drop_empty(), "parse_names drops empty string"); 153 - TEST(test_binsearch(), "binary search with binsearch works"); 154 - TEST(test_names_length(), "names_length retuns size of a NULL-terminated string array"); 155 - TEST(test_names_equal(), "names_equal compares NULL-terminated string arrays"); 156 - TEST(test_u24_roundtrip(), "put_be24 and get_be24 work"); 157 - TEST(test_u16_roundtrip(), "put_be16 and get_be16 work"); 134 + if_test ("put_be16 and get_be16 work") { 135 + uint32_t in = 0xfef1; 136 + uint8_t dest[3]; 137 + uint32_t out; 138 + put_be16(dest, in); 139 + out = get_be16(dest); 140 + check_int(in, ==, out); 141 + } 158 142 159 143 return test_done(); 160 144 }
+156 -200
t/unit-tests/t-strvec.c
··· 19 19 } \ 20 20 } while (0) 21 21 22 - static void t_static_init(void) 22 + int cmd_main(int argc, const char **argv) 23 23 { 24 - struct strvec vec = STRVEC_INIT; 25 - check_pointer_eq(vec.v, empty_strvec); 26 - check_uint(vec.nr, ==, 0); 27 - check_uint(vec.alloc, ==, 0); 28 - } 24 + if_test ("static initialization") { 25 + struct strvec vec = STRVEC_INIT; 26 + check_pointer_eq(vec.v, empty_strvec); 27 + check_uint(vec.nr, ==, 0); 28 + check_uint(vec.alloc, ==, 0); 29 + } 29 30 30 - static void t_dynamic_init(void) 31 - { 32 - struct strvec vec; 33 - strvec_init(&vec); 34 - check_pointer_eq(vec.v, empty_strvec); 35 - check_uint(vec.nr, ==, 0); 36 - check_uint(vec.alloc, ==, 0); 37 - } 31 + if_test ("dynamic initialization") { 32 + struct strvec vec; 33 + strvec_init(&vec); 34 + check_pointer_eq(vec.v, empty_strvec); 35 + check_uint(vec.nr, ==, 0); 36 + check_uint(vec.alloc, ==, 0); 37 + } 38 38 39 - static void t_clear(void) 40 - { 41 - struct strvec vec = STRVEC_INIT; 42 - strvec_push(&vec, "foo"); 43 - strvec_clear(&vec); 44 - check_pointer_eq(vec.v, empty_strvec); 45 - check_uint(vec.nr, ==, 0); 46 - check_uint(vec.alloc, ==, 0); 47 - } 39 + if_test ("clear") { 40 + struct strvec vec = STRVEC_INIT; 41 + strvec_push(&vec, "foo"); 42 + strvec_clear(&vec); 43 + check_pointer_eq(vec.v, empty_strvec); 44 + check_uint(vec.nr, ==, 0); 45 + check_uint(vec.alloc, ==, 0); 46 + } 48 47 49 - static void t_push(void) 50 - { 51 - struct strvec vec = STRVEC_INIT; 48 + if_test ("push") { 49 + struct strvec vec = STRVEC_INIT; 52 50 53 - strvec_push(&vec, "foo"); 54 - check_strvec(&vec, "foo", NULL); 51 + strvec_push(&vec, "foo"); 52 + check_strvec(&vec, "foo", NULL); 55 53 56 - strvec_push(&vec, "bar"); 57 - check_strvec(&vec, "foo", "bar", NULL); 54 + strvec_push(&vec, "bar"); 55 + check_strvec(&vec, "foo", "bar", NULL); 58 56 59 - strvec_clear(&vec); 60 - } 57 + strvec_clear(&vec); 58 + } 61 59 62 - static void t_pushf(void) 63 - { 64 - struct strvec vec = STRVEC_INIT; 65 - strvec_pushf(&vec, "foo: %d", 1); 66 - check_strvec(&vec, "foo: 1", NULL); 67 - strvec_clear(&vec); 68 - } 60 + if_test ("pushf") { 61 + struct strvec vec = STRVEC_INIT; 62 + strvec_pushf(&vec, "foo: %d", 1); 63 + check_strvec(&vec, "foo: 1", NULL); 64 + strvec_clear(&vec); 65 + } 69 66 70 - static void t_pushl(void) 71 - { 72 - struct strvec vec = STRVEC_INIT; 73 - strvec_pushl(&vec, "foo", "bar", "baz", NULL); 74 - check_strvec(&vec, "foo", "bar", "baz", NULL); 75 - strvec_clear(&vec); 76 - } 67 + if_test ("pushl") { 68 + struct strvec vec = STRVEC_INIT; 69 + strvec_pushl(&vec, "foo", "bar", "baz", NULL); 70 + check_strvec(&vec, "foo", "bar", "baz", NULL); 71 + strvec_clear(&vec); 72 + } 77 73 78 - static void t_pushv(void) 79 - { 80 - const char *strings[] = { 81 - "foo", "bar", "baz", NULL, 82 - }; 83 - struct strvec vec = STRVEC_INIT; 74 + if_test ("pushv") { 75 + const char *strings[] = { 76 + "foo", "bar", "baz", NULL, 77 + }; 78 + struct strvec vec = STRVEC_INIT; 84 79 85 - strvec_pushv(&vec, strings); 86 - check_strvec(&vec, "foo", "bar", "baz", NULL); 80 + strvec_pushv(&vec, strings); 81 + check_strvec(&vec, "foo", "bar", "baz", NULL); 87 82 88 - strvec_clear(&vec); 89 - } 83 + strvec_clear(&vec); 84 + } 90 85 91 - static void t_replace_at_head(void) 92 - { 93 - struct strvec vec = STRVEC_INIT; 94 - strvec_pushl(&vec, "foo", "bar", "baz", NULL); 95 - strvec_replace(&vec, 0, "replaced"); 96 - check_strvec(&vec, "replaced", "bar", "baz", NULL); 97 - strvec_clear(&vec); 98 - } 86 + if_test ("replace at head") { 87 + struct strvec vec = STRVEC_INIT; 88 + strvec_pushl(&vec, "foo", "bar", "baz", NULL); 89 + strvec_replace(&vec, 0, "replaced"); 90 + check_strvec(&vec, "replaced", "bar", "baz", NULL); 91 + strvec_clear(&vec); 92 + } 99 93 100 - static void t_replace_at_tail(void) 101 - { 102 - struct strvec vec = STRVEC_INIT; 103 - strvec_pushl(&vec, "foo", "bar", "baz", NULL); 104 - strvec_replace(&vec, 2, "replaced"); 105 - check_strvec(&vec, "foo", "bar", "replaced", NULL); 106 - strvec_clear(&vec); 107 - } 94 + if_test ("replace at tail") { 95 + struct strvec vec = STRVEC_INIT; 96 + strvec_pushl(&vec, "foo", "bar", "baz", NULL); 97 + strvec_replace(&vec, 2, "replaced"); 98 + check_strvec(&vec, "foo", "bar", "replaced", NULL); 99 + strvec_clear(&vec); 100 + } 108 101 109 - static void t_replace_in_between(void) 110 - { 111 - struct strvec vec = STRVEC_INIT; 112 - strvec_pushl(&vec, "foo", "bar", "baz", NULL); 113 - strvec_replace(&vec, 1, "replaced"); 114 - check_strvec(&vec, "foo", "replaced", "baz", NULL); 115 - strvec_clear(&vec); 116 - } 102 + if_test ("replace in between") { 103 + struct strvec vec = STRVEC_INIT; 104 + strvec_pushl(&vec, "foo", "bar", "baz", NULL); 105 + strvec_replace(&vec, 1, "replaced"); 106 + check_strvec(&vec, "foo", "replaced", "baz", NULL); 107 + strvec_clear(&vec); 108 + } 117 109 118 - static void t_replace_with_substring(void) 119 - { 120 - struct strvec vec = STRVEC_INIT; 121 - strvec_pushl(&vec, "foo", NULL); 122 - strvec_replace(&vec, 0, vec.v[0] + 1); 123 - check_strvec(&vec, "oo", NULL); 124 - strvec_clear(&vec); 125 - } 110 + if_test ("replace with substring") { 111 + struct strvec vec = STRVEC_INIT; 112 + strvec_pushl(&vec, "foo", NULL); 113 + strvec_replace(&vec, 0, vec.v[0] + 1); 114 + check_strvec(&vec, "oo", NULL); 115 + strvec_clear(&vec); 116 + } 126 117 127 - static void t_remove_at_head(void) 128 - { 129 - struct strvec vec = STRVEC_INIT; 130 - strvec_pushl(&vec, "foo", "bar", "baz", NULL); 131 - strvec_remove(&vec, 0); 132 - check_strvec(&vec, "bar", "baz", NULL); 133 - strvec_clear(&vec); 134 - } 118 + if_test ("remove at head") { 119 + struct strvec vec = STRVEC_INIT; 120 + strvec_pushl(&vec, "foo", "bar", "baz", NULL); 121 + strvec_remove(&vec, 0); 122 + check_strvec(&vec, "bar", "baz", NULL); 123 + strvec_clear(&vec); 124 + } 135 125 136 - static void t_remove_at_tail(void) 137 - { 138 - struct strvec vec = STRVEC_INIT; 139 - strvec_pushl(&vec, "foo", "bar", "baz", NULL); 140 - strvec_remove(&vec, 2); 141 - check_strvec(&vec, "foo", "bar", NULL); 142 - strvec_clear(&vec); 143 - } 126 + if_test ("remove at tail") { 127 + struct strvec vec = STRVEC_INIT; 128 + strvec_pushl(&vec, "foo", "bar", "baz", NULL); 129 + strvec_remove(&vec, 2); 130 + check_strvec(&vec, "foo", "bar", NULL); 131 + strvec_clear(&vec); 132 + } 144 133 145 - static void t_remove_in_between(void) 146 - { 147 - struct strvec vec = STRVEC_INIT; 148 - strvec_pushl(&vec, "foo", "bar", "baz", NULL); 149 - strvec_remove(&vec, 1); 150 - check_strvec(&vec, "foo", "baz", NULL); 151 - strvec_clear(&vec); 152 - } 134 + if_test ("remove in between") { 135 + struct strvec vec = STRVEC_INIT; 136 + strvec_pushl(&vec, "foo", "bar", "baz", NULL); 137 + strvec_remove(&vec, 1); 138 + check_strvec(&vec, "foo", "baz", NULL); 139 + strvec_clear(&vec); 140 + } 153 141 154 - static void t_pop_empty_array(void) 155 - { 156 - struct strvec vec = STRVEC_INIT; 157 - strvec_pop(&vec); 158 - check_strvec(&vec, NULL); 159 - strvec_clear(&vec); 160 - } 142 + if_test ("pop with empty array") { 143 + struct strvec vec = STRVEC_INIT; 144 + strvec_pop(&vec); 145 + check_strvec(&vec, NULL); 146 + strvec_clear(&vec); 147 + } 161 148 162 - static void t_pop_non_empty_array(void) 163 - { 164 - struct strvec vec = STRVEC_INIT; 165 - strvec_pushl(&vec, "foo", "bar", "baz", NULL); 166 - strvec_pop(&vec); 167 - check_strvec(&vec, "foo", "bar", NULL); 168 - strvec_clear(&vec); 169 - } 149 + if_test ("pop with non-empty array") { 150 + struct strvec vec = STRVEC_INIT; 151 + strvec_pushl(&vec, "foo", "bar", "baz", NULL); 152 + strvec_pop(&vec); 153 + check_strvec(&vec, "foo", "bar", NULL); 154 + strvec_clear(&vec); 155 + } 170 156 171 - static void t_split_empty_string(void) 172 - { 173 - struct strvec vec = STRVEC_INIT; 174 - strvec_split(&vec, ""); 175 - check_strvec(&vec, NULL); 176 - strvec_clear(&vec); 177 - } 157 + if_test ("split empty string") { 158 + struct strvec vec = STRVEC_INIT; 159 + strvec_split(&vec, ""); 160 + check_strvec(&vec, NULL); 161 + strvec_clear(&vec); 162 + } 178 163 179 - static void t_split_single_item(void) 180 - { 181 - struct strvec vec = STRVEC_INIT; 182 - strvec_split(&vec, "foo"); 183 - check_strvec(&vec, "foo", NULL); 184 - strvec_clear(&vec); 185 - } 164 + if_test ("split single item") { 165 + struct strvec vec = STRVEC_INIT; 166 + strvec_split(&vec, "foo"); 167 + check_strvec(&vec, "foo", NULL); 168 + strvec_clear(&vec); 169 + } 186 170 187 - static void t_split_multiple_items(void) 188 - { 189 - struct strvec vec = STRVEC_INIT; 190 - strvec_split(&vec, "foo bar baz"); 191 - check_strvec(&vec, "foo", "bar", "baz", NULL); 192 - strvec_clear(&vec); 193 - } 171 + if_test ("split multiple items") { 172 + struct strvec vec = STRVEC_INIT; 173 + strvec_split(&vec, "foo bar baz"); 174 + check_strvec(&vec, "foo", "bar", "baz", NULL); 175 + strvec_clear(&vec); 176 + } 194 177 195 - static void t_split_whitespace_only(void) 196 - { 197 - struct strvec vec = STRVEC_INIT; 198 - strvec_split(&vec, " \t\n"); 199 - check_strvec(&vec, NULL); 200 - strvec_clear(&vec); 201 - } 178 + if_test ("split whitespace only") { 179 + struct strvec vec = STRVEC_INIT; 180 + strvec_split(&vec, " \t\n"); 181 + check_strvec(&vec, NULL); 182 + strvec_clear(&vec); 183 + } 202 184 203 - static void t_split_multiple_consecutive_whitespaces(void) 204 - { 205 - struct strvec vec = STRVEC_INIT; 206 - strvec_split(&vec, "foo\n\t bar"); 207 - check_strvec(&vec, "foo", "bar", NULL); 208 - strvec_clear(&vec); 209 - } 185 + if_test ("split multiple consecutive whitespaces") { 186 + struct strvec vec = STRVEC_INIT; 187 + strvec_split(&vec, "foo\n\t bar"); 188 + check_strvec(&vec, "foo", "bar", NULL); 189 + strvec_clear(&vec); 190 + } 210 191 211 - static void t_detach(void) 212 - { 213 - struct strvec vec = STRVEC_INIT; 214 - const char **detached; 192 + if_test ("detach") { 193 + struct strvec vec = STRVEC_INIT; 194 + const char **detached; 215 195 216 - strvec_push(&vec, "foo"); 196 + strvec_push(&vec, "foo"); 217 197 218 - detached = strvec_detach(&vec); 219 - check_str(detached[0], "foo"); 220 - check_pointer_eq(detached[1], NULL); 198 + detached = strvec_detach(&vec); 199 + check_str(detached[0], "foo"); 200 + check_pointer_eq(detached[1], NULL); 221 201 222 - check_pointer_eq(vec.v, empty_strvec); 223 - check_uint(vec.nr, ==, 0); 224 - check_uint(vec.alloc, ==, 0); 202 + check_pointer_eq(vec.v, empty_strvec); 203 + check_uint(vec.nr, ==, 0); 204 + check_uint(vec.alloc, ==, 0); 225 205 226 - free((char *) detached[0]); 227 - free(detached); 228 - } 206 + free((char *) detached[0]); 207 + free(detached); 208 + } 229 209 230 - int cmd_main(int argc, const char **argv) 231 - { 232 - TEST(t_static_init(), "static initialization"); 233 - TEST(t_dynamic_init(), "dynamic initialization"); 234 - TEST(t_clear(), "clear"); 235 - TEST(t_push(), "push"); 236 - TEST(t_pushf(), "pushf"); 237 - TEST(t_pushl(), "pushl"); 238 - TEST(t_pushv(), "pushv"); 239 - TEST(t_replace_at_head(), "replace at head"); 240 - TEST(t_replace_in_between(), "replace in between"); 241 - TEST(t_replace_at_tail(), "replace at tail"); 242 - TEST(t_replace_with_substring(), "replace with substring"); 243 - TEST(t_remove_at_head(), "remove at head"); 244 - TEST(t_remove_in_between(), "remove in between"); 245 - TEST(t_remove_at_tail(), "remove at tail"); 246 - TEST(t_pop_empty_array(), "pop with empty array"); 247 - TEST(t_pop_non_empty_array(), "pop with non-empty array"); 248 - TEST(t_split_empty_string(), "split empty string"); 249 - TEST(t_split_single_item(), "split single item"); 250 - TEST(t_split_multiple_items(), "split multiple items"); 251 - TEST(t_split_whitespace_only(), "split whitespace only"); 252 - TEST(t_split_multiple_consecutive_whitespaces(), "split multiple consecutive whitespaces"); 253 - TEST(t_detach(), "detach"); 254 210 return test_done(); 255 211 }
+35 -1
t/unit-tests/test-lib.c
··· 16 16 unsigned running :1; 17 17 unsigned skip_all :1; 18 18 unsigned todo :1; 19 + char location[100]; 20 + char description[100]; 19 21 } ctx = { 20 22 .lazy_plan = 1, 21 23 .result = RESULT_NONE, ··· 125 127 126 128 int test_done(void) 127 129 { 130 + if (ctx.running && ctx.location[0] && ctx.description[0]) 131 + test__run_end(1, ctx.location, "%s", ctx.description); 128 132 assert(!ctx.running); 129 133 130 134 if (ctx.lazy_plan) ··· 167 171 va_end(ap); 168 172 } 169 173 174 + void test__run_describe(const char *location, const char *format, ...) 175 + { 176 + va_list ap; 177 + int len; 178 + 179 + assert(ctx.running); 180 + assert(!ctx.location[0]); 181 + assert(!ctx.description[0]); 182 + 183 + xsnprintf(ctx.location, sizeof(ctx.location), "%s", 184 + make_relative(location)); 185 + 186 + va_start(ap, format); 187 + len = vsnprintf(ctx.description, sizeof(ctx.description), format, ap); 188 + va_end(ap); 189 + if (len < 0) 190 + die("unable to format message: %s", format); 191 + if (len >= sizeof(ctx.description)) 192 + BUG("ctx.description too small to format %s", format); 193 + } 194 + 170 195 int test__run_begin(void) 171 196 { 197 + if (ctx.running && ctx.location[0] && ctx.description[0]) 198 + test__run_end(1, ctx.location, "%s", ctx.description); 172 199 assert(!ctx.running); 173 200 174 201 ctx.count++; 175 202 ctx.result = RESULT_NONE; 176 203 ctx.running = 1; 204 + ctx.location[0] = '\0'; 205 + ctx.description[0] = '\0'; 177 206 178 207 return ctx.skip_all; 179 208 } ··· 264 293 265 294 int test_assert(const char *location, const char *check, int ok) 266 295 { 267 - assert(ctx.running); 296 + if (!ctx.running) { 297 + test_msg("BUG: check outside of test at %s", 298 + make_relative(location)); 299 + ctx.failed = 1; 300 + return 0; 301 + } 268 302 269 303 if (ctx.result == RESULT_SKIP) { 270 304 test_msg("skipping check '%s' at %s", check,
+20
t/unit-tests/test-lib.h
··· 15 15 TEST_LOCATION(), __VA_ARGS__) 16 16 17 17 /* 18 + * Run a test unless test_skip_all() has been called. Acts like a 19 + * conditional; the test body is expected as a statement or block after 20 + * the closing parenthesis. The description for each test should be 21 + * unique. E.g.: 22 + * 23 + * if_test ("something else %d %d", arg1, arg2) { 24 + * prepare(); 25 + * test_something_else(arg1, arg2); 26 + * cleanup(); 27 + * } 28 + */ 29 + #define if_test(...) \ 30 + if (test__run_begin() ? \ 31 + (test__run_end(0, TEST_LOCATION(), __VA_ARGS__), 0) : \ 32 + (test__run_describe(TEST_LOCATION(), __VA_ARGS__), 1)) 33 + 34 + /* 18 35 * Print a test plan, should be called before any tests. If the number 19 36 * of tests is not known in advance test_done() will automatically 20 37 * print a plan at the end of the test program. ··· 153 170 }; 154 171 155 172 extern union test__tmp test__tmp[2]; 173 + 174 + __attribute__((format (printf, 2, 3))) 175 + void test__run_describe(const char *, const char *, ...); 156 176 157 177 int test__run_begin(void); 158 178 __attribute__((format (printf, 3, 4)))