Commit Diff


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 <stdio.h>
+	#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 <stdio.h>
+	#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