Я создаю набор модулей с модульными тестами и хотите автоматически сгенерировать комбинированную программу для выполнения всех тестов.
Потворствуя своему внутреннему фанатику контроля, я решил использовать структуру minunit.h и попробуй сделать все вручную. Итак, у меня есть два исходных файла (будет больше).
-rw-r--r-- 1 josh None 6192 Aug 21 23:15 io.c
-rw-r--r-- 1 josh None 2341 Aug 22 00:49 st.c
Каждый из них имеет встроенный модульный тест (поэтому мне легче следить за обновлениями и, возможно, на самом деле использовать его на этот раз), охраняемый #ifdef TESTMODULE
. В общих чертах:
...
//module code
...
#ifdef TESTMODULE
...
//unit tests
...
int main(){
// call unit tests
}
#endif
Затем я могу создать тестовую программу с очень коротким файлом.
$ cat > io_test.c
#define TESTMODULE
#include "io.c"
$ make io_test
cc io_test.c -o io_test
Я написал комбинированную программу вручную, используя тот же тип включения, но переопределяя все глобальные имена, чтобы они были уникальными.
# define main io_main
# define tests_run io_tests_run
# define all_tests io_all_tests
# include "io_test.c"
# undef main
# undef tests_run
# undef all_tests
int io_test(){
printf("running io_test\n");
return io_main();
}
# define main st_main
# define tests_run st_tests_run
# define all_tests st_all_tests
# include "st_test.c"
# undef main
# undef tests_run
# undef all_tests
int st_test(){
printf("running st_test\n");
return st_main();
}
int main(){
return
0 || io_test() || st_test() ;
}
Теперь я хочу сгенерировать это автоматически из гораздо более короткого списка переменных частей: io
и st
. Я могу сделать большую часть работы с X-макросами.
#define HASH #
#define UNITS(_) \
_(io) \
_(st) \
/**/
#define gen_unit_function(unit) \
HASH define main unit##_main \
HASH define tests_run unit##_tests_run \
HASH define all_tests unit##_all_tests \
HASH include STR(unit##_test.c) \
HASH undef main \
HASH undef tests_run \
HASH undef all_tests \
int unit##_test(){ \
printf("running " STR(unit) "_test\n"); \
return unit##_main(); \
}
#define gen_func_call(unit) \
|| unit##_test()
UNITS(gen_unit_function)
int main(){
return
0 UNITS(gen_func_call) ;
}
Но, конечно, это никогда не сработает, потому что вы не можете форсировать новую строку с помощью препроцессора C. Что можно использовать для обхода этого ограничения?