samedi 22 août 2015

Compose a combined test-suite program from a collection of unit-tests

I'm building a set of modules with unit-tests and I want to automatically generate a combined program to execute all the tests.

Indulging my inner control freak, I decided to use the minunit.h framework and try to do it all manually. So I have two source files (there will be more).

-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

Each one has a unit-test embedded (so it's easier for me to keep updated, and maybe actually use it this time) guarded by #ifdef TESTMODULE.

I can then make a testing program with a very short file.

$ cat > io_test.c
#define TESTMODULE
#include "io.c"
$ make io_test
cc     io_test.c   -o io_test

I wrote a combined program by hand using the same sort of inclusion, but redefining any global names so they are unique.

# 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()  ; 
} 

Now I want to generate this automatically from the much shorter list of variable parts: io and st. I can do most of the work with X-macros.

#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 io_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) ;
}

But of course, that can never work because you can't force a newline with the C preprocessor. What can I use to workaround this limitation?

Aucun commentaire:

Enregistrer un commentaire