"Accumulate a list" is not within the capabilities of the C preprocessor, I'm afraid.
But it's pretty easy to do with an external preprocessor, and any decent build system will have a way to automatically run an external preprocessor as part of the build process.
If you're careful not to use the sequence UNIT_TEST( anywhere in your source code other than in the definition of a unit test, and also to ensure that you never spread UNIT_TEST(a, b) over two lines (which doesn't seem like a big restriction), then you could use a simple shell script to build a stand-alone unit-test caller:
#!/bin/sh
echo '#define CONCAT_(a,b) a##b'
echo '#define UNIT_TEST(a,b) void CONCAT_(a,b)(void); CONCAT_(a,b)();'
echo 'void UnitTestRun(void) {';
grep -hEo 'UNIT_TEST\([^)]*)' "$@"
echo '}'
This allows you to define unit tests in various files, and accumulate them into a single file containing only the function UnitTestRun. The file is completely stand-alone; it contains both declarations and invocations of each unit test, so it doesn't require any #includes. (This does require C99; if you needed to separate the declarations from the invocations, you could do two scans over the files.)
Here's a simple sample run of the script. I placed declarations of the test functions in suite1.c and suite2.c, and the above script in unit_test_maker.sh:
$ # The input files
$ cat suite1.c
UNIT_TEST(Suite1, FirstTest) {
/* blah, blah, blah */
}
UNIT_TEST(Suite1, SecondTest) {
/* More blah */
}
$ cat suite2.c
UNIT_TEST(Suite2, OnlyTest) {
/* blah, blah, blah */
}
$ # The output of the script
$ ./unit_test_maker.sh suite1.c suite2.c
#define CONCAT_(a,b) a##b
#define UNIT_TEST(a,b) void CONCAT_(a,b)(void); CONCAT_(a,b)();
void UnitTestRun(void) {
UNIT_TEST(Suite1, FirstTest)
UNIT_TEST(Suite1, SecondTest)
UNIT_TEST(Suite2, OnlyTest)
}
$ # The output from preprocessing the script
$ ./unit_test_maker.sh suite1.c suite2.c | gcc -E -x c -
# 1 "<stdin>"
# 1 "<built-in>"
# 1 "<command-line>"
# 31 "<command-line>"
# 1 "/usr/include/stdc-predef.h" 1 3 4
# 32 "<command-line>" 2
# 1 "<stdin>"
void UnitTestRun(void) {
void Suite1FirstTest(void); Suite1FirstTest();
void Suite1SecondTest(void); Suite1SecondTest();
void Suite2OnlyTest(void); Suite2OnlyTest();
}
$ # Compiles without warnings with `-Wall`.
$ ./unit_test_maker.sh suite1.c suite2.c | gcc -Wall -x c -c -o unit_test_run.o -
$