{"thread":{"id":"65202","subject":"[GSoC PATCH] test-lib: print escape sequence names","startedAt":"2026-03-10T18:35:19Z","lastAt":"2026-03-11T20:49:04Z","messageCount":5,"participants":["Pablo Sabater","Pablo","Junio C Hamano"],"isPatch":true,"patchVersion":1,"patchTotal":null},"messages":[{"id":"538505","messageId":"20260310183513.1077875-1-pabloosabaterr@gmail.com","threadId":"65202","inReplyTo":null,"subject":"[GSoC PATCH] test-lib: print escape sequence names","fromName":"Pablo Sabater","fromEmail":"pabloosabaterr@gmail.com","sentAt":"2026-03-10T18:35:13Z","receivedAt":"2026-03-10T18:35:19Z","isPatch":true,"sender":{"key":"pabloosabaterr@gmail.com","avatar":"https://avatars.githubusercontent.com/u/63864637?v=4"},"body":"When printing expected/actual characters in failed checks, use\ntheir names (\\a, \\b, \\n, ...) instead of their octal representation,\nmaking it easier to read\n\n- Add tests to test-example-tap.c\n- Update t0080-unit-test-output.sh\n to match the desired output\n\nTeach 'print_one_char()' the equivalent name\n\nSigned-off-by: Pablo Sabater <pabloosabaterr@gmail.com>\n---\n t/helper/test-example-tap.c |  4 +++\n t/t0080-unit-test-output.sh | 58 ++++++++++++++++++++++---------------\n t/unit-tests/test-lib.c     | 19 ++++++++++--\n 3 files changed, 56 insertions(+), 25 deletions(-)\n\ndiff --git a/t/helper/test-example-tap.c b/t/helper/test-example-tap.c\nindex 229d495ecf..998a1f0b42 100644\n--- a/t/helper/test-example-tap.c\n+++ b/t/helper/test-example-tap.c\n@@ -63,6 +63,8 @@ static void t_messages(void)\n \tcheck_str(\"NULL\", NULL);\n \tcheck_char('a', ==, '\\n');\n \tcheck_char('\\\\', ==, '\\'');\n+\tcheck_char('\\a', ==, '\\v');\n+\tcheck_char('\\x00', ==, '\\x01');\n }\n \n static void t_empty(void)\n@@ -123,6 +125,8 @@ int cmd__example_tap(int argc UNUSED, const char **argv UNUSED)\n \t\tcheck_str(\"NULL\", NULL);\n \t\tcheck_char('a', ==, '\\n');\n \t\tcheck_char('\\\\', ==, '\\'');\n+\t\tcheck_char('\\a', ==, '\\v');\n+\t\tcheck_char('\\x00', ==, '\\x01');\n \t}\n \tif_test (\"if_test test with no checks\")\n \t\t; /* nothing */\ndiff --git a/t/t0080-unit-test-output.sh b/t/t0080-unit-test-output.sh\nindex 3db10f095c..11ab8b53bb 100755\n--- a/t/t0080-unit-test-output.sh\n+++ b/t/t0080-unit-test-output.sh\n@@ -6,10 +6,10 @@ test_description='Test the output of the unit test framework'\n \n test_expect_success 'TAP output from unit tests' - <<\\EOT\n \tcat >expect <<-EOF &&\n-\t# BUG: check outside of test at t/helper/test-example-tap.c:75\n+\t# BUG: check outside of test at t/helper/test-example-tap.c:77\n \tok 1 - passing test\n \tok 2 - passing test and assertion return 1\n-\t# check \"1 == 2\" failed at t/helper/test-example-tap.c:79\n+\t# check \"1 == 2\" failed at t/helper/test-example-tap.c:81\n \t#    left: 1\n \t#   right: 2\n \tnot ok 3 - failing test\n@@ -34,53 +34,65 @@ test_expect_success 'TAP output from unit tests' - <<\\EOT\n \tnot ok 15 - failing check after TEST_TODO()\n \tok 16 - failing check after TEST_TODO() returns 0\n \t# check \"!strcmp(\"\\thello\\\\\\\\\", \"there\\\"\\n\")\" failed at t/helper/test-example-tap.c:62\n-\t#    left: \"\\011hello\\\\\\\\\"\n-\t#   right: \"there\\\"\\012\"\n+\t#    left: \"\\thello\\\\\\\\\"\n+\t#   right: \"there\\\"\\n\"\n \t# check \"!strcmp(\"NULL\", NULL)\" failed at t/helper/test-example-tap.c:63\n \t#    left: \"NULL\"\n \t#   right: NULL\n \t# check \"'a' == '\\n'\" failed at t/helper/test-example-tap.c:64\n \t#    left: 'a'\n-\t#   right: '\\012'\n-\t# check \"'\\\\\\\\' == '\\\\''\" failed at t/helper/test-example-tap.c:65\n+\t#   right: '\\n'\n+\t# check \"'\\\\\\\\' == '\\''\" failed at t/helper/test-example-tap.c:65\n \t#    left: '\\\\\\\\'\n-\t#   right: '\\\\''\n+\t#   right: '\\''\n+\t# check \"'\\a' == '\\v'\" failed at t/helper/test-example-tap.c:66\n+\t#    left: '\\a'\n+\t#   right: '\\v'\n+\t# check \"'\\x00' == '\\x01'\" failed at t/helper/test-example-tap.c:67\n+\t#    left: '\\000'\n+\t#   right: '\\001'\n \tnot ok 17 - messages from failing string and char comparison\n-\t# BUG: test has no checks at t/helper/test-example-tap.c:94\n+\t# BUG: test has no checks at t/helper/test-example-tap.c:96\n \tnot ok 18 - test with no checks\n \tok 19 - test with no checks returns 0\n \tok 20 - if_test passing test\n-\t# check \"1 == 2\" failed at t/helper/test-example-tap.c:100\n+\t# check \"1 == 2\" failed at t/helper/test-example-tap.c:102\n \t#    left: 1\n \t#   right: 2\n \tnot ok 21 - if_test failing test\n \tnot ok 22 - if_test passing TEST_TODO() # TODO\n-\t# todo check 'check(1)' succeeded at t/helper/test-example-tap.c:104\n+\t# todo check 'check(1)' succeeded at t/helper/test-example-tap.c:106\n \tnot ok 23 - if_test failing TEST_TODO()\n-\t# check \"0\" failed at t/helper/test-example-tap.c:106\n+\t# check \"0\" failed at t/helper/test-example-tap.c:108\n \t# skipping test - missing prerequisite\n-\t# skipping check '1' at t/helper/test-example-tap.c:108\n+\t# skipping check '1' at t/helper/test-example-tap.c:110\n \tok 24 - if_test test_skip() # SKIP\n \t# skipping test - missing prerequisite\n \tok 25 - if_test test_skip() inside TEST_TODO() # SKIP\n-\t# check \"0\" failed at t/helper/test-example-tap.c:113\n+\t# check \"0\" failed at t/helper/test-example-tap.c:115\n \tnot ok 26 - if_test TEST_TODO() after failing check\n-\t# check \"0\" failed at t/helper/test-example-tap.c:119\n+\t# check \"0\" failed at t/helper/test-example-tap.c:121\n \tnot ok 27 - if_test failing check after TEST_TODO()\n-\t# check \"!strcmp(\"\\thello\\\\\\\\\", \"there\\\"\\n\")\" failed at t/helper/test-example-tap.c:122\n-\t#    left: \"\\011hello\\\\\\\\\"\n-\t#   right: \"there\\\"\\012\"\n-\t# check \"!strcmp(\"NULL\", NULL)\" failed at t/helper/test-example-tap.c:123\n+\t# check \"!strcmp(\"\\thello\\\\\\\\\", \"there\\\"\\n\")\" failed at t/helper/test-example-tap.c:124\n+\t#    left: \"\\thello\\\\\\\\\"\n+\t#   right: \"there\\\"\\n\"\n+\t# check \"!strcmp(\"NULL\", NULL)\" failed at t/helper/test-example-tap.c:125\n \t#    left: \"NULL\"\n \t#   right: NULL\n-\t# check \"'a' == '\\n'\" failed at t/helper/test-example-tap.c:124\n+\t# check \"'a' == '\\n'\" failed at t/helper/test-example-tap.c:126\n \t#    left: 'a'\n-\t#   right: '\\012'\n-\t# check \"'\\\\\\\\' == '\\\\''\" failed at t/helper/test-example-tap.c:125\n+\t#   right: '\\n'\n+\t# check \"'\\\\\\\\' == '\\''\" failed at t/helper/test-example-tap.c:127\n \t#    left: '\\\\\\\\'\n-\t#   right: '\\\\''\n+\t#   right: '\\''\n+\t# check \"'\\a' == '\\v'\" failed at t/helper/test-example-tap.c:128\n+\t#    left: '\\a'\n+\t#   right: '\\v'\n+\t# check \"'\\x00' == '\\x01'\" failed at t/helper/test-example-tap.c:129\n+\t#    left: '\\000'\n+\t#   right: '\\001'\n \tnot ok 28 - if_test messages from failing string and char comparison\n-\t# BUG: test has no checks at t/helper/test-example-tap.c:127\n+\t# BUG: test has no checks at t/helper/test-example-tap.c:131\n \tnot ok 29 - if_test test with no checks\n \t1..29\n \tEOF\ndiff --git a/t/unit-tests/test-lib.c b/t/unit-tests/test-lib.c\nindex 87e1f5c201..72ee20a06f 100644\n--- a/t/unit-tests/test-lib.c\n+++ b/t/unit-tests/test-lib.c\n@@ -396,8 +396,23 @@ int check_uint_loc(const char *loc, const char *check, int ok,\n static void print_one_char(char ch, char quote)\n {\n \tif ((unsigned char)ch < 0x20u || ch == 0x7f) {\n-\t\t/* TODO: improve handling of \\a, \\b, \\f ... */\n-\t\tprintf(\"\\\\%03o\", (unsigned char)ch);\n+\t\tchar esc;\n+\t\tswitch (ch) {\n+\t\tcase '\\a': esc = 'a'; break;\n+\t\tcase '\\b': esc = 'b'; break;\n+\t\tcase '\\t': esc = 't'; break;\n+\t\tcase '\\n': esc = 'n'; break;\n+\t\tcase '\\v': esc = 'v'; break;\n+\t\tcase '\\f': esc = 'f'; break;\n+\t\tcase '\\r': esc = 'r'; break;\n+\t\tdefault: esc = 0; break;\n+\t\t}\n+\t\tif (esc) {\n+\t\t\tputc('\\\\', stdout);\n+\t\t\tputc(esc, stdout);\n+\t\t} else {\n+\t\t\tprintf(\"\\\\%03o\", (unsigned char)ch);\n+\t\t}\n \t} else {\n \t\tif (ch == '\\\\' || ch == quote)\n \t\t\tputc('\\\\', stdout);\n-- \n2.43.0\n\n"},{"id":"538506","messageId":"CAN5EUNRZSBwnAzacA-w7S-vF6-66SH1LdOpZXtG_So45Xk1ViA@mail.gmail.com","threadId":"65202","inReplyTo":"20260310183513.1077875-1-pabloosabaterr@gmail.com","subject":"Re: [GSoC PATCH] test-lib: print escape sequence names","fromName":"Pablo","fromEmail":"pabloosabaterr@gmail.com","sentAt":"2026-03-10T18:48:31Z","receivedAt":"2026-03-10T18:48:47Z","isPatch":true,"sender":{"key":"pabloosabaterr@gmail.com","avatar":"https://avatars.githubusercontent.com/u/63864637?v=4"},"body":"I'm sorry, just rereading, on the expected output,\nI just saw that when updating lines because of\nthe new tests added, it got changed:\n\n # check \"'\\\\\\\\' == '\\\\''\" failed at t/helper/test-example-tap.c:65\nto:\n # check \"'\\\\\\\\' == '\\''\" failed at t/helper/test-example-tap.c:65\n\nand one more identical check some lines below\n\nIt should work the same way but it isn't directly related with what I did.\nI can undo this change on a v2 if necessary\n"},{"id":"538547","messageId":"20260311031442.11942-1-pabloosabaterr@gmail.com","threadId":"65202","inReplyTo":"20260310183513.1077875-1-pabloosabaterr@gmail.com","subject":"[GSoC PATCH v2] test-lib: print escape sequence names","fromName":"Pablo Sabater","fromEmail":"pabloosabaterr@gmail.com","sentAt":"2026-03-11T03:14:42Z","receivedAt":"2026-03-11T03:14:51Z","isPatch":true,"sender":{"key":"pabloosabaterr@gmail.com","avatar":"https://avatars.githubusercontent.com/u/63864637?v=4"},"body":"When printing expected/actual characters in failed checks, use\ntheir names (\\a, \\b, \\n, ...) instead of their octal representation,\nmaking it easier to read.\n\nAdd tests to test-example-tap.c\nUpdate t0080-unit-test-output.sh to match the desired output\n\nTeach 'print_one_char()' the equivalent name\n\nSigned-off-by: Pablo Sabater <pabloosabaterr@gmail.com>\n---\nChanges from v1:\nreverted unrelated test change '\\'' to '\\\\'' in t0080\n\n t/helper/test-example-tap.c |  4 +++\n t/t0080-unit-test-output.sh | 52 +++++++++++++++++++++++--------------\n t/unit-tests/test-lib.c     | 19 ++++++++++++--\n 3 files changed, 53 insertions(+), 22 deletions(-)\n\ndiff --git a/t/helper/test-example-tap.c b/t/helper/test-example-tap.c\nindex 229d495ecf..998a1f0b42 100644\n--- a/t/helper/test-example-tap.c\n+++ b/t/helper/test-example-tap.c\n@@ -63,6 +63,8 @@ static void t_messages(void)\n \tcheck_str(\"NULL\", NULL);\n \tcheck_char('a', ==, '\\n');\n \tcheck_char('\\\\', ==, '\\'');\n+\tcheck_char('\\a', ==, '\\v');\n+\tcheck_char('\\x00', ==, '\\x01');\n }\n \n static void t_empty(void)\n@@ -123,6 +125,8 @@ int cmd__example_tap(int argc UNUSED, const char **argv UNUSED)\n \t\tcheck_str(\"NULL\", NULL);\n \t\tcheck_char('a', ==, '\\n');\n \t\tcheck_char('\\\\', ==, '\\'');\n+\t\tcheck_char('\\a', ==, '\\v');\n+\t\tcheck_char('\\x00', ==, '\\x01');\n \t}\n \tif_test (\"if_test test with no checks\")\n \t\t; /* nothing */\ndiff --git a/t/t0080-unit-test-output.sh b/t/t0080-unit-test-output.sh\nindex 3db10f095c..66838a00b2 100755\n--- a/t/t0080-unit-test-output.sh\n+++ b/t/t0080-unit-test-output.sh\n@@ -6,10 +6,10 @@ test_description='Test the output of the unit test framework'\n \n test_expect_success 'TAP output from unit tests' - <<\\EOT\n \tcat >expect <<-EOF &&\n-\t# BUG: check outside of test at t/helper/test-example-tap.c:75\n+\t# BUG: check outside of test at t/helper/test-example-tap.c:77\n \tok 1 - passing test\n \tok 2 - passing test and assertion return 1\n-\t# check \"1 == 2\" failed at t/helper/test-example-tap.c:79\n+\t# check \"1 == 2\" failed at t/helper/test-example-tap.c:81\n \t#    left: 1\n \t#   right: 2\n \tnot ok 3 - failing test\n@@ -34,53 +34,65 @@ test_expect_success 'TAP output from unit tests' - <<\\EOT\n \tnot ok 15 - failing check after TEST_TODO()\n \tok 16 - failing check after TEST_TODO() returns 0\n \t# check \"!strcmp(\"\\thello\\\\\\\\\", \"there\\\"\\n\")\" failed at t/helper/test-example-tap.c:62\n-\t#    left: \"\\011hello\\\\\\\\\"\n-\t#   right: \"there\\\"\\012\"\n+\t#    left: \"\\thello\\\\\\\\\"\n+\t#   right: \"there\\\"\\n\"\n \t# check \"!strcmp(\"NULL\", NULL)\" failed at t/helper/test-example-tap.c:63\n \t#    left: \"NULL\"\n \t#   right: NULL\n \t# check \"'a' == '\\n'\" failed at t/helper/test-example-tap.c:64\n \t#    left: 'a'\n-\t#   right: '\\012'\n+\t#   right: '\\n'\n \t# check \"'\\\\\\\\' == '\\\\''\" failed at t/helper/test-example-tap.c:65\n \t#    left: '\\\\\\\\'\n \t#   right: '\\\\''\n+\t# check \"'\\a' == '\\v'\" failed at t/helper/test-example-tap.c:66\n+\t#    left: '\\a'\n+\t#   right: '\\v'\n+\t# check \"'\\x00' == '\\x01'\" failed at t/helper/test-example-tap.c:67\n+\t#    left: '\\000'\n+\t#   right: '\\001'\n \tnot ok 17 - messages from failing string and char comparison\n-\t# BUG: test has no checks at t/helper/test-example-tap.c:94\n+\t# BUG: test has no checks at t/helper/test-example-tap.c:96\n \tnot ok 18 - test with no checks\n \tok 19 - test with no checks returns 0\n \tok 20 - if_test passing test\n-\t# check \"1 == 2\" failed at t/helper/test-example-tap.c:100\n+\t# check \"1 == 2\" failed at t/helper/test-example-tap.c:102\n \t#    left: 1\n \t#   right: 2\n \tnot ok 21 - if_test failing test\n \tnot ok 22 - if_test passing TEST_TODO() # TODO\n-\t# todo check 'check(1)' succeeded at t/helper/test-example-tap.c:104\n+\t# todo check 'check(1)' succeeded at t/helper/test-example-tap.c:106\n \tnot ok 23 - if_test failing TEST_TODO()\n-\t# check \"0\" failed at t/helper/test-example-tap.c:106\n+\t# check \"0\" failed at t/helper/test-example-tap.c:108\n \t# skipping test - missing prerequisite\n-\t# skipping check '1' at t/helper/test-example-tap.c:108\n+\t# skipping check '1' at t/helper/test-example-tap.c:110\n \tok 24 - if_test test_skip() # SKIP\n \t# skipping test - missing prerequisite\n \tok 25 - if_test test_skip() inside TEST_TODO() # SKIP\n-\t# check \"0\" failed at t/helper/test-example-tap.c:113\n+\t# check \"0\" failed at t/helper/test-example-tap.c:115\n \tnot ok 26 - if_test TEST_TODO() after failing check\n-\t# check \"0\" failed at t/helper/test-example-tap.c:119\n+\t# check \"0\" failed at t/helper/test-example-tap.c:121\n \tnot ok 27 - if_test failing check after TEST_TODO()\n-\t# check \"!strcmp(\"\\thello\\\\\\\\\", \"there\\\"\\n\")\" failed at t/helper/test-example-tap.c:122\n-\t#    left: \"\\011hello\\\\\\\\\"\n-\t#   right: \"there\\\"\\012\"\n-\t# check \"!strcmp(\"NULL\", NULL)\" failed at t/helper/test-example-tap.c:123\n+\t# check \"!strcmp(\"\\thello\\\\\\\\\", \"there\\\"\\n\")\" failed at t/helper/test-example-tap.c:124\n+\t#    left: \"\\thello\\\\\\\\\"\n+\t#   right: \"there\\\"\\n\"\n+\t# check \"!strcmp(\"NULL\", NULL)\" failed at t/helper/test-example-tap.c:125\n \t#    left: \"NULL\"\n \t#   right: NULL\n-\t# check \"'a' == '\\n'\" failed at t/helper/test-example-tap.c:124\n+\t# check \"'a' == '\\n'\" failed at t/helper/test-example-tap.c:126\n \t#    left: 'a'\n-\t#   right: '\\012'\n-\t# check \"'\\\\\\\\' == '\\\\''\" failed at t/helper/test-example-tap.c:125\n+\t#   right: '\\n'\n+\t# check \"'\\\\\\\\' == '\\\\''\" failed at t/helper/test-example-tap.c:127\n \t#    left: '\\\\\\\\'\n \t#   right: '\\\\''\n+\t# check \"'\\a' == '\\v'\" failed at t/helper/test-example-tap.c:128\n+\t#    left: '\\a'\n+\t#   right: '\\v'\n+\t# check \"'\\x00' == '\\x01'\" failed at t/helper/test-example-tap.c:129\n+\t#    left: '\\000'\n+\t#   right: '\\001'\n \tnot ok 28 - if_test messages from failing string and char comparison\n-\t# BUG: test has no checks at t/helper/test-example-tap.c:127\n+\t# BUG: test has no checks at t/helper/test-example-tap.c:131\n \tnot ok 29 - if_test test with no checks\n \t1..29\n \tEOF\ndiff --git a/t/unit-tests/test-lib.c b/t/unit-tests/test-lib.c\nindex 87e1f5c201..72ee20a06f 100644\n--- a/t/unit-tests/test-lib.c\n+++ b/t/unit-tests/test-lib.c\n@@ -396,8 +396,23 @@ int check_uint_loc(const char *loc, const char *check, int ok,\n static void print_one_char(char ch, char quote)\n {\n \tif ((unsigned char)ch < 0x20u || ch == 0x7f) {\n-\t\t/* TODO: improve handling of \\a, \\b, \\f ... */\n-\t\tprintf(\"\\\\%03o\", (unsigned char)ch);\n+\t\tchar esc;\n+\t\tswitch (ch) {\n+\t\tcase '\\a': esc = 'a'; break;\n+\t\tcase '\\b': esc = 'b'; break;\n+\t\tcase '\\t': esc = 't'; break;\n+\t\tcase '\\n': esc = 'n'; break;\n+\t\tcase '\\v': esc = 'v'; break;\n+\t\tcase '\\f': esc = 'f'; break;\n+\t\tcase '\\r': esc = 'r'; break;\n+\t\tdefault: esc = 0; break;\n+\t\t}\n+\t\tif (esc) {\n+\t\t\tputc('\\\\', stdout);\n+\t\t\tputc(esc, stdout);\n+\t\t} else {\n+\t\t\tprintf(\"\\\\%03o\", (unsigned char)ch);\n+\t\t}\n \t} else {\n \t\tif (ch == '\\\\' || ch == quote)\n \t\t\tputc('\\\\', stdout);\n-- \n2.43.0\n\n"},{"id":"538579","messageId":"CAN5EUNTGO8hUms5mBPtW4XJtx+v1_bi2NoL0=titbeJ5asgrHQ@mail.gmail.com","threadId":"65202","inReplyTo":"20260311031442.11942-1-pabloosabaterr@gmail.com","subject":"Re: [GSoC PATCH v2] test-lib: print escape sequence names","fromName":"Pablo","fromEmail":"pabloosabaterr@gmail.com","sentAt":"2026-03-11T10:53:47Z","receivedAt":"2026-03-11T10:54:04Z","isPatch":true,"sender":{"key":"pabloosabaterr@gmail.com","avatar":"https://avatars.githubusercontent.com/u/63864637?v=4"},"body":"Adding project mentors to CC, sorry I should have done this earlier,\nbut I didn't have the project clear and didn't want to spam, I'll CC\non the proposal, introduction and microproject as well.\n\nThanks.\n"},{"id":"538678","messageId":"xmqqms0em6rm.fsf@gitster.g","threadId":"65202","inReplyTo":"20260311031442.11942-1-pabloosabaterr@gmail.com","subject":"Re: [GSoC PATCH v2] test-lib: print escape sequence names","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2026-03-11T20:49:01Z","receivedAt":"2026-03-11T20:49:04Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Pablo Sabater <pabloosabaterr@gmail.com> writes:\n\n> When printing expected/actual characters in failed checks, use\n> their names (\\a, \\b, \\n, ...) instead of their octal representation,\n> making it easier to read.\n>\n> Add tests to test-example-tap.c\n> Update t0080-unit-test-output.sh to match the desired output\n>\n> Teach 'print_one_char()' the equivalent name\n>\n> Signed-off-by: Pablo Sabater <pabloosabaterr@gmail.com>\n> ---\n> Changes from v1:\n> reverted unrelated test change '\\'' to '\\\\'' in t0080\n>\n>  t/helper/test-example-tap.c |  4 +++\n>  t/t0080-unit-test-output.sh | 52 +++++++++++++++++++++++--------------\n>  t/unit-tests/test-lib.c     | 19 ++++++++++++--\n>  3 files changed, 53 insertions(+), 22 deletions(-)\n\nLooking good.  Will queue.  Thanks.\n\n\n>\n> diff --git a/t/helper/test-example-tap.c b/t/helper/test-example-tap.c\n> index 229d495ecf..998a1f0b42 100644\n> --- a/t/helper/test-example-tap.c\n> +++ b/t/helper/test-example-tap.c\n> @@ -63,6 +63,8 @@ static void t_messages(void)\n>  \tcheck_str(\"NULL\", NULL);\n>  \tcheck_char('a', ==, '\\n');\n>  \tcheck_char('\\\\', ==, '\\'');\n> +\tcheck_char('\\a', ==, '\\v');\n> +\tcheck_char('\\x00', ==, '\\x01');\n>  }\n>  \n>  static void t_empty(void)\n> @@ -123,6 +125,8 @@ int cmd__example_tap(int argc UNUSED, const char **argv UNUSED)\n>  \t\tcheck_str(\"NULL\", NULL);\n>  \t\tcheck_char('a', ==, '\\n');\n>  \t\tcheck_char('\\\\', ==, '\\'');\n> +\t\tcheck_char('\\a', ==, '\\v');\n> +\t\tcheck_char('\\x00', ==, '\\x01');\n>  \t}\n>  \tif_test (\"if_test test with no checks\")\n>  \t\t; /* nothing */\n> diff --git a/t/t0080-unit-test-output.sh b/t/t0080-unit-test-output.sh\n> index 3db10f095c..66838a00b2 100755\n> --- a/t/t0080-unit-test-output.sh\n> +++ b/t/t0080-unit-test-output.sh\n> @@ -6,10 +6,10 @@ test_description='Test the output of the unit test framework'\n>  \n>  test_expect_success 'TAP output from unit tests' - <<\\EOT\n>  \tcat >expect <<-EOF &&\n> -\t# BUG: check outside of test at t/helper/test-example-tap.c:75\n> +\t# BUG: check outside of test at t/helper/test-example-tap.c:77\n>  \tok 1 - passing test\n>  \tok 2 - passing test and assertion return 1\n> -\t# check \"1 == 2\" failed at t/helper/test-example-tap.c:79\n> +\t# check \"1 == 2\" failed at t/helper/test-example-tap.c:81\n>  \t#    left: 1\n>  \t#   right: 2\n>  \tnot ok 3 - failing test\n> @@ -34,53 +34,65 @@ test_expect_success 'TAP output from unit tests' - <<\\EOT\n>  \tnot ok 15 - failing check after TEST_TODO()\n>  \tok 16 - failing check after TEST_TODO() returns 0\n>  \t# check \"!strcmp(\"\\thello\\\\\\\\\", \"there\\\"\\n\")\" failed at t/helper/test-example-tap.c:62\n> -\t#    left: \"\\011hello\\\\\\\\\"\n> -\t#   right: \"there\\\"\\012\"\n> +\t#    left: \"\\thello\\\\\\\\\"\n> +\t#   right: \"there\\\"\\n\"\n>  \t# check \"!strcmp(\"NULL\", NULL)\" failed at t/helper/test-example-tap.c:63\n>  \t#    left: \"NULL\"\n>  \t#   right: NULL\n>  \t# check \"'a' == '\\n'\" failed at t/helper/test-example-tap.c:64\n>  \t#    left: 'a'\n> -\t#   right: '\\012'\n> +\t#   right: '\\n'\n>  \t# check \"'\\\\\\\\' == '\\\\''\" failed at t/helper/test-example-tap.c:65\n>  \t#    left: '\\\\\\\\'\n>  \t#   right: '\\\\''\n> +\t# check \"'\\a' == '\\v'\" failed at t/helper/test-example-tap.c:66\n> +\t#    left: '\\a'\n> +\t#   right: '\\v'\n> +\t# check \"'\\x00' == '\\x01'\" failed at t/helper/test-example-tap.c:67\n> +\t#    left: '\\000'\n> +\t#   right: '\\001'\n>  \tnot ok 17 - messages from failing string and char comparison\n> -\t# BUG: test has no checks at t/helper/test-example-tap.c:94\n> +\t# BUG: test has no checks at t/helper/test-example-tap.c:96\n>  \tnot ok 18 - test with no checks\n>  \tok 19 - test with no checks returns 0\n>  \tok 20 - if_test passing test\n> -\t# check \"1 == 2\" failed at t/helper/test-example-tap.c:100\n> +\t# check \"1 == 2\" failed at t/helper/test-example-tap.c:102\n>  \t#    left: 1\n>  \t#   right: 2\n>  \tnot ok 21 - if_test failing test\n>  \tnot ok 22 - if_test passing TEST_TODO() # TODO\n> -\t# todo check 'check(1)' succeeded at t/helper/test-example-tap.c:104\n> +\t# todo check 'check(1)' succeeded at t/helper/test-example-tap.c:106\n>  \tnot ok 23 - if_test failing TEST_TODO()\n> -\t# check \"0\" failed at t/helper/test-example-tap.c:106\n> +\t# check \"0\" failed at t/helper/test-example-tap.c:108\n>  \t# skipping test - missing prerequisite\n> -\t# skipping check '1' at t/helper/test-example-tap.c:108\n> +\t# skipping check '1' at t/helper/test-example-tap.c:110\n>  \tok 24 - if_test test_skip() # SKIP\n>  \t# skipping test - missing prerequisite\n>  \tok 25 - if_test test_skip() inside TEST_TODO() # SKIP\n> -\t# check \"0\" failed at t/helper/test-example-tap.c:113\n> +\t# check \"0\" failed at t/helper/test-example-tap.c:115\n>  \tnot ok 26 - if_test TEST_TODO() after failing check\n> -\t# check \"0\" failed at t/helper/test-example-tap.c:119\n> +\t# check \"0\" failed at t/helper/test-example-tap.c:121\n>  \tnot ok 27 - if_test failing check after TEST_TODO()\n> -\t# check \"!strcmp(\"\\thello\\\\\\\\\", \"there\\\"\\n\")\" failed at t/helper/test-example-tap.c:122\n> -\t#    left: \"\\011hello\\\\\\\\\"\n> -\t#   right: \"there\\\"\\012\"\n> -\t# check \"!strcmp(\"NULL\", NULL)\" failed at t/helper/test-example-tap.c:123\n> +\t# check \"!strcmp(\"\\thello\\\\\\\\\", \"there\\\"\\n\")\" failed at t/helper/test-example-tap.c:124\n> +\t#    left: \"\\thello\\\\\\\\\"\n> +\t#   right: \"there\\\"\\n\"\n> +\t# check \"!strcmp(\"NULL\", NULL)\" failed at t/helper/test-example-tap.c:125\n>  \t#    left: \"NULL\"\n>  \t#   right: NULL\n> -\t# check \"'a' == '\\n'\" failed at t/helper/test-example-tap.c:124\n> +\t# check \"'a' == '\\n'\" failed at t/helper/test-example-tap.c:126\n>  \t#    left: 'a'\n> -\t#   right: '\\012'\n> -\t# check \"'\\\\\\\\' == '\\\\''\" failed at t/helper/test-example-tap.c:125\n> +\t#   right: '\\n'\n> +\t# check \"'\\\\\\\\' == '\\\\''\" failed at t/helper/test-example-tap.c:127\n>  \t#    left: '\\\\\\\\'\n>  \t#   right: '\\\\''\n> +\t# check \"'\\a' == '\\v'\" failed at t/helper/test-example-tap.c:128\n> +\t#    left: '\\a'\n> +\t#   right: '\\v'\n> +\t# check \"'\\x00' == '\\x01'\" failed at t/helper/test-example-tap.c:129\n> +\t#    left: '\\000'\n> +\t#   right: '\\001'\n>  \tnot ok 28 - if_test messages from failing string and char comparison\n> -\t# BUG: test has no checks at t/helper/test-example-tap.c:127\n> +\t# BUG: test has no checks at t/helper/test-example-tap.c:131\n>  \tnot ok 29 - if_test test with no checks\n>  \t1..29\n>  \tEOF\n> diff --git a/t/unit-tests/test-lib.c b/t/unit-tests/test-lib.c\n> index 87e1f5c201..72ee20a06f 100644\n> --- a/t/unit-tests/test-lib.c\n> +++ b/t/unit-tests/test-lib.c\n> @@ -396,8 +396,23 @@ int check_uint_loc(const char *loc, const char *check, int ok,\n>  static void print_one_char(char ch, char quote)\n>  {\n>  \tif ((unsigned char)ch < 0x20u || ch == 0x7f) {\n> -\t\t/* TODO: improve handling of \\a, \\b, \\f ... */\n> -\t\tprintf(\"\\\\%03o\", (unsigned char)ch);\n> +\t\tchar esc;\n> +\t\tswitch (ch) {\n> +\t\tcase '\\a': esc = 'a'; break;\n> +\t\tcase '\\b': esc = 'b'; break;\n> +\t\tcase '\\t': esc = 't'; break;\n> +\t\tcase '\\n': esc = 'n'; break;\n> +\t\tcase '\\v': esc = 'v'; break;\n> +\t\tcase '\\f': esc = 'f'; break;\n> +\t\tcase '\\r': esc = 'r'; break;\n> +\t\tdefault: esc = 0; break;\n> +\t\t}\n> +\t\tif (esc) {\n> +\t\t\tputc('\\\\', stdout);\n> +\t\t\tputc(esc, stdout);\n> +\t\t} else {\n> +\t\t\tprintf(\"\\\\%03o\", (unsigned char)ch);\n> +\t\t}\n>  \t} else {\n>  \t\tif (ch == '\\\\' || ch == quote)\n>  \t\t\tputc('\\\\', stdout);\n"}]}