commit 5bc4ca7fa3c49d5b57406f3872f169737984cc87 from: Sven M. Hallberg date: Wed Jul 23 15:32:53 2025 UTC test.h: add rem() commit - a6b35f66241ad24fdd4e12e934bbfc5c7e7e985e commit + 5bc4ca7fa3c49d5b57406f3872f169737984cc87 blob - 3285332f16238af772bb564dc58f816e6afd7374 blob + dc4a939317c2e7a83d535985ded67c49838312b6 --- lang/c/test.h +++ lang/c/test.h @@ -10,10 +10,13 @@ * TEST(function, ...); * RUNT(function, ...); * - * fail(fmt, ...); - * + * assert(expression); * expect(expression); * + * fail(fmt, ...); + * rem(fmt, ...); + * + * * DESCRIPTION * The TEST() macro calls the given function as a unit test. Any * additional arguments will be passed to function, allowing parameterized @@ -26,35 +29,43 @@ * unconditionally and prints the test result to standard output. It does * not depend on argc and argv being in scope. * - * Test functions may be defined with any return type, but the return - * value is ignored. To signal failure of a test, the fail() macro should - * be called with an appropriate error message, using printf(3)-style - * arguments. Any other diagnostics should be printed to stderr as usual. + * Test functions may be defined with any return type; their return value + * is ignored. To signal failure of a test, the fail() macro should be + * called with an appropriate error message, using printf(3)-style + * arguments. Diagnostics relating to the failure may be printed to stderr. * * The expect() macro tests a boolean condition. It calls fail() if the * given expression evaluates to false. The user should define custom * variants of expect() as suitable. * - * The fail() macro does not abort the current test unless the X - * environment variable is set (see below). Checks that always form a - * precondition for the continuation of the test should use assert(3). - * Meanwhile, RUNT() calls exit(3) after a failed test returns; see also - * the K environment variable. + * The rem() macro can be used to produce miscellaneous messages; it is + * ignored unless V is set. Messages should consist of a single line, + * without a trailing newline, and will be printed to stdout prefixed by + * a TAB character to maintain a simple TSV format. No other output should + * be made to stdout. * + * By default, the fail() macro does not immediately abort the running + * test. Checks that are a strict precondition for the continuation of + * the test should use assert(3); test.h includes assert.h for + * convenience. After a failed test returns, RUNT() normally calls + * exit(3), forgoing any remaining tests. See the K and X environment + * variables for changing the default behavior. + * * The global variable status is set to 1 upon test failure and should be - * used to return the correct value from main. + * used to return the correct value from main (when K is set). * * ENVIRONMENT * The following variables serve as flags. They enable the stated behavior * whenever set, regardless of value. * - * D Dry run; print tests without executing them. + * D Dry run. Print tests without executing them. * - * V Print tests that are skipped. + * V Verbose. Print any tests that are skipped and enable + * informational output from rem(). * - * K Do not exit after a failed test. + * K Keep going after a failed test instead of exiting. * - * X Call abort(3) immediately when fail() is called. + * X Exit with a call to abort(3) as soon as fail() is called. * * EXAMPLES * The following shows a test program: @@ -160,4 +171,12 @@ static int failed_; failed_ = 1; \ } while (0) +#define rem(...) do { \ + if (getenv("V") == NULL) /* V = verbose */ \ + break; \ + printf("\t"); \ + printf(__VA_ARGS__); \ + printf("\n"); \ +} while (0) + #endif /* TEST_H */ blob - /dev/null blob + a7f07d8ab51c6619f6ff3f948535293cc4a6a919 (mode 755) --- /dev/null +++ tests/lang/c/rem.t @@ -0,0 +1,69 @@ +#!/bin/sh + +set -e + +unset D V K X +export CFLAGS=-I../../lang/c + +# rem() ignored when not V +./assert-c 0 \ + "" \ + "foo()\tOK\nbar()\tOK\n" \ + "main\n" \ +<<-EOF + #include + #include "test.h" + + void + foo(void) + { + rem("foo called"); + } + + void + bar(void) + { + rem("bar called"); + } + + int + main(int argc, char *argv[]) + { + fputs("main\n", stderr); + TEST(foo); + TEST(bar); + return 0; + } +EOF + +# rem() prints when V set +V=1 \ +./assert-c 0 \ + "" \ + "\tfoo called\nfoo()\tOK\n\tbar called\nbar()\tOK\n" \ + "main\n" \ +<<-EOF + #include + #include "test.h" + + void + foo(void) + { + rem("foo called"); + } + + void + bar(void) + { + rem("bar called"); + } + + int + main(int argc, char *argv[]) + { + fputs("main\n", stderr); + TEST(foo); + TEST(bar); + return 0; + } +EOF