From: mquinson Date: Sun, 23 Oct 2005 10:18:21 +0000 (+0000) Subject: Add a tool to automatically extract the test units from the source code of the librar... X-Git-Tag: v3.3~3556 X-Git-Url: http://info.iut-bm.univ-fcomte.fr/pub/gitweb/simgrid.git/commitdiff_plain/7a59d4ae96a5ab66d5ba0ba146aa4fc275c8ab5a Add a tool to automatically extract the test units from the source code of the libraries, change the library makefile to use it on declared files and convert modules 'ex' and 'cunit' to this system git-svn-id: svn+ssh://scm.gforge.inria.fr/svn/simgrid/simgrid/trunk@1802 48e7efb5-ca39-0410-a469-dd3cf9ba447f --- diff --git a/include/xbt/cunit.h b/include/xbt/cunit.h index bdffc53de7..99114dc1f9 100644 --- a/include/xbt/cunit.h +++ b/include/xbt/cunit.h @@ -24,7 +24,8 @@ typedef struct s_xbt_test_unit *xbt_test_unit_t; typedef void (*ts_test_cb_t)(xbt_test_unit_t); /* test suite operations */ -xbt_test_suite_t xbt_test_suite_new (const char *fmt, ...); +xbt_test_suite_t xbt_test_suite_new (const char *name,const char *fmt, ...); +xbt_test_suite_t xbt_test_suite_by_name(const char *name,const char *fmt, ...); void xbt_test_suite_dump (xbt_test_suite_t suite); void xbt_test_suite_push (xbt_test_suite_t suite, ts_test_cb_t func, const char *fmt, ...); @@ -33,13 +34,13 @@ int xbt_test_run (void); /* test operations */ -void _xbt_test(xbt_test_unit_t u, const char*file,int line, const char *fmt, ...)_XBT_GNUC_PRINTF(4,5); -#define xbt_test0(fmt) _xbt_test(_unit,__FILE__,__LINE__,fmt) -#define xbt_test1(fmt,a) _xbt_test(_unit,__FILE__,__LINE__,fmt,a) -#define xbt_test2(fmt,a,b) _xbt_test(_unit,__FILE__,__LINE__,fmt,a,b) -#define xbt_test3(fmt,a,b,c) _xbt_test(_unit,__FILE__,__LINE__,fmt,a,b,c) -#define xbt_test4(fmt,a,b,c,d) _xbt_test(_unit,__FILE__,__LINE__,fmt,a,b,c,d) -#define xbt_test5(fmt,a,b,c,d,e) _xbt_test(_unit,__FILE__,__LINE__,fmt,a,b,c,d,e) +void _xbt_test_add(xbt_test_unit_t u, const char*file,int line, const char *fmt, ...)_XBT_GNUC_PRINTF(4,5); +#define xbt_test_add0(fmt) _xbt_test_add(_unit,__FILE__,__LINE__,fmt) +#define xbt_test_add1(fmt,a) _xbt_test_add(_unit,__FILE__,__LINE__,fmt,a) +#define xbt_test_add2(fmt,a,b) _xbt_test_add(_unit,__FILE__,__LINE__,fmt,a,b) +#define xbt_test_add3(fmt,a,b,c) _xbt_test_add(_unit,__FILE__,__LINE__,fmt,a,b,c) +#define xbt_test_add4(fmt,a,b,c,d) _xbt_test_add(_unit,__FILE__,__LINE__,fmt,a,b,c,d) +#define xbt_test_add5(fmt,a,b,c,d,e) _xbt_test_add(_unit,__FILE__,__LINE__,fmt,a,b,c,d,e) void _xbt_test_fail(xbt_test_unit_t u, const char*file,int line, const char *fmt, ...) _XBT_GNUC_PRINTF(4,5); #define xbt_test_fail0(fmt) _xbt_test_fail(_unit, __FILE__, __LINE__, fmt) @@ -64,8 +65,9 @@ void _xbt_test_skip(xbt_test_unit_t unit); #define xbt_test_skip() _xbt_test_skip(_unit) /* test suite short-cut macros */ -#define XBT_TEST_UNIT(name) \ - static void name(xbt_test_unit_t _unit) +#define XBT_TEST_UNIT(name,func,title) \ + void func(xbt_test_unit_t _unit); /*prototype*/ \ + void func(xbt_test_unit_t _unit) #endif /* _TS_H_ */ diff --git a/src/.cvsignore b/src/.cvsignore index 1baec79a8b..067612c165 100644 --- a/src/.cvsignore +++ b/src/.cvsignore @@ -5,3 +5,4 @@ gras_config.h.in gras_config.h stamp-h.in stamp-h stamp-h1 *.loT ucontext_stack.h +*_unit.c simgrid_units_main.c testall* diff --git a/src/Makefile.am b/src/Makefile.am index ddf0471ea9..aa2f1d54dc 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -94,6 +94,7 @@ VERSION_INFO= -release 20050627 -version-info 0:0:0 # using this trick is ready for a "stable" release (say, in Debian). lib_LTLIBRARIES= libsimgrid.la libgras.la +noinst_PROGRAMS=testall COMMON_SRC=\ \ @@ -169,8 +170,40 @@ AMOK_SRC= \ amok/base.c \ amok/Bandwidth/bandwidth.c amok/Bandwidth/saturate.c +### +### Testing infrastructure +### + +TEST_CFILES=xbt/cunit.c xbt/ex.c +TEST_UNITS= cunit_unit.c ex_unit.c + BUILT_SOURCES=../include/surf/surfxml.h surf/surfxml.c \ - gras/DataDesc/ddt_parse.yy.c + gras/DataDesc/ddt_parse.yy.c \ + $(TEST_UNITS) simgrid_units_main.c + +testall_SOURCES= $(TEST_UNITS) simgrid_units_main.c +testall_LDADD=libgras.la + +if MAINTAINER_MODE +%_unit.c: $(TEST_CFILES) @top_srcdir@/tools/sg_unit_extractor.pl + @echo TEST_UNITS=$(TEST_UNITS) + @echo testall_SOURCES=$(testall_SOURCES) + @lookfor=`echo $@ | sed 's/_unit.c$$/.c/'`; \ + for s in $(TEST_CFILES) ; do \ + if echo $$s | grep $$lookfor >/dev/null; then \ + src="$$src $$s"; \ + fi; \ + done; \ + echo "Generate Testing Suite $@ from$$src"; \ + @top_srcdir@/tools/sg_unit_extractor.pl $$src + +simgrid_units_main.c: $(TEST_UNITS) +endif + +### +### Regenerate what needs to with flex & flexml +### + gras/DataDesc/ddt_parse.yy.c: gras/DataDesc/ddt_parse.yy.l @LEX@ -o$@ -Pgras_ddt_parse_ $^ @@ -194,6 +227,10 @@ else endif endif +### +### Declare the library content +### + libgras_la_SOURCES= $(COMMON_SRC) $(RL_SRC) $(AMOK_SRC) libgras_la_LDFLAGS = $(VERSION_INFO) @GRAS_DEP@ @LD_DYNAMIC_FLAGS@ -lm @@ -201,4 +238,5 @@ libsimgrid_la_SOURCES= $(COMMON_SRC) $(SG_SRC) $(AMOK_SRC) libsimgrid_la_LDFLAGS = $(VERSION_INFO) @SIMGRID_DEP@ @LD_DYNAMIC_FLAGS@ -lm + include $(top_srcdir)/acmacro/dist-files.mk diff --git a/src/xbt/cunit.c b/src/xbt/cunit.c index 0f8b6256b5..6f8faf5a56 100644 --- a/src/xbt/cunit.c +++ b/src/xbt/cunit.c @@ -107,6 +107,7 @@ static void xbt_test_unit_dump(xbt_test_unit_t unit) { /* test suite */ struct s_xbt_test_suite { + const char *name; char *title; xbt_dynar_t units; /* of xbt_test_unit_t */ @@ -127,7 +128,7 @@ static void xbt_test_suite_free(void *s) { } /** @brief create test suite */ -xbt_test_suite_t xbt_test_suite_new(const char *fmt, ...) { +xbt_test_suite_t xbt_test_suite_new(const char *name, const char *fmt, ...) { xbt_test_suite_t suite = xbt_new0(struct s_xbt_test_suite,1); va_list ap; @@ -138,12 +139,35 @@ xbt_test_suite_t xbt_test_suite_new(const char *fmt, ...) { vasprintf(&suite->title,fmt, ap); suite->units = xbt_dynar_new(sizeof(xbt_test_unit_t), NULL); va_end(ap); + suite->name=name; xbt_dynar_push(_xbt_test_suites,&suite); return suite; } +/** @brief retrive a testsuite from name, or create a new one */ +xbt_test_suite_t xbt_test_suite_by_name(const char *name,const char *fmt, ...) { + xbt_test_suite_t suite; + int it_suite; + + char *bufname; + va_list ap; + + if (_xbt_test_suites) + xbt_dynar_foreach(_xbt_test_suites, it_suite, suite) + if (!strcmp(suite->name,name)) + return suite; + + va_start(ap, fmt); + vasprintf(&bufname,fmt, ap); + va_end(ap); + suite = xbt_test_suite_new(name,bufname,NULL); + free(bufname); + + return suite; +} + void xbt_test_suite_dump(xbt_test_suite_t suite) { if (suite) { xbt_test_unit_t unit; @@ -437,7 +461,7 @@ int xbt_test_run(void) { /* annotate test case with test */ -void _xbt_test(xbt_test_unit_t unit, const char*file,int line, const char *fmt, ...) { +void _xbt_test_add(xbt_test_unit_t unit, const char*file,int line, const char *fmt, ...) { xbt_test_test_t test; va_list ap; @@ -509,3 +533,21 @@ void _xbt_test_log(xbt_test_unit_t unit, const char*file,int line,const char *fm xbt_dynar_push(test->logs, &log); } + + + +#ifdef SIMGRID_TEST + +XBT_TEST_SUITE("cuint","Testsuite Autotest %d",0); + +XBT_TEST_UNIT("expect",test_expected_failure,"expected failures") { + xbt_test_add0("Skipped test"); + xbt_test_skip(); + + xbt_test_add2("%s %s","EXPECTED","FAILURE"); + xbt_test_expect_failure(); + xbt_test_log2("%s %s","Test","log"); + xbt_test_fail0("EXPECTED FAILURE"); +} + +#endif /* SIMGRID_TEST */ diff --git a/src/xbt/ex.c b/src/xbt/ex.c index 7e53f12fd8..31209f5a17 100644 --- a/src/xbt/ex.c +++ b/src/xbt/ex.c @@ -108,3 +108,109 @@ int backtrace (void **__array, int __size) { } #endif + +#ifdef SIMGRID_TEST +#include "xbt/ex.h" + +XBT_TEST_SUITE("xbt_ex","Exception Handling"); + +XBT_TEST_UNIT("controlflow",test_controlflow, "basic nested control flow") { + xbt_ex_t ex; + volatile int n=1; + + xbt_test_add0("basic nested control flow"); + + TRY { + if (n != 1) + xbt_test_fail1("M1: n=%d (!= 1)", n); + n++; + TRY { + if (n != 2) + xbt_test_fail1("M2: n=%d (!= 2)", n); + n++; + THROW0(unknown_error,0,"something"); + } CATCH (ex) { + if (n != 3) + xbt_test_fail1("M3: n=%d (!= 1)", n); + n++; + RETHROW; + } + xbt_test_fail1("MX: n=%d (shouldn't reach this point)", n); + } + CATCH(ex) { + if (n != 4) + xbt_test_fail1("M4: n=%d (!= 4)", n); + n++; + xbt_ex_free(ex); + } + if (n != 5) + xbt_test_fail1("M5: n=%d (!= 5)", n); +} + +XBT_TEST_UNIT("value",test_value,"exception value passing") { + xbt_ex_t ex; + + TRY { + THROW0(unknown_error, 2, "toto"); + } CATCH(ex) { + xbt_test_add0("exception value passing"); + if (ex.category != unknown_error) + xbt_test_fail1("category=%d (!= 1)", ex.category); + if (ex.value != 2) + xbt_test_fail1("value=%d (!= 2)", ex.value); + if (strcmp(ex.msg,"toto")) + xbt_test_fail1("message=%s (!= toto)", ex.msg); + xbt_ex_free(ex); + } +} + +XBT_TEST_UNIT("variables",test_variables,"variable value preservation") { + xbt_ex_t ex; + int r1, r2; + volatile int v1, v2; + + r1 = r2 = v1 = v2 = 1234; + TRY { + r2 = 5678; + v2 = 5678; + THROW0(unknown_error, 0, "toto"); + } CATCH(ex) { + xbt_test_add0("variable preservation"); + if (r1 != 1234) + xbt_test_fail1("r1=%d (!= 1234)", r1); + if (v1 != 1234) + xbt_test_fail1("v1=%d (!= 1234)", v1); + /* r2 is allowed to be destroyed because not volatile */ + if (v2 != 5678) + xbt_test_fail1("v2=%d (!= 5678)", v2); + xbt_ex_free(ex); + } +} + +XBT_TEST_UNIT("cleanup",test_cleanup,"cleanup handling") { + xbt_ex_t ex; + volatile int v1; + int c; + + xbt_test_add0("cleanup handling"); + + v1 = 1234; + c = 0; + TRY { + v1 = 5678; + THROW0(1, 2, "blah"); + } CLEANUP { + if (v1 != 5678) + xbt_test_fail1("v1 = %d (!= 5678)", v1); + c = 1; + } CATCH(ex) { + if (v1 != 5678) + xbt_test_fail1("v1 = %d (!= 5678)", v1); + if (!(ex.category == 1 && ex.value == 2 && !strcmp(ex.msg,"blah"))) + xbt_test_fail0("unexpected exception contents"); + xbt_ex_free(ex); + } + if (!c) + xbt_test_fail0("xbt_ex_free not executed"); +} +#endif /* SIMGRID_TEST */ diff --git a/testsuite/xbt/ex_test.c b/testsuite/xbt/ex_test.c index 21dbd8973a..78b2f5797d 100644 --- a/testsuite/xbt/ex_test.c +++ b/testsuite/xbt/ex_test.c @@ -28,11 +28,6 @@ ** ex_test.c: exception handling test suite */ -#include -#include -#include -#include - #include "xbt/cunit.h" #include "xbt/ex.h" #include "xbt/log.h" diff --git a/tools/sg_unit_extractor.pl b/tools/sg_unit_extractor.pl new file mode 100755 index 0000000000..e7d14228fe --- /dev/null +++ b/tools/sg_unit_extractor.pl @@ -0,0 +1,188 @@ +#! /usr/bin/perl + +use strict; + +my $progname="sg_unit_extractor"; +# Get the args +die "USAGE: $progname infile [outfile]\n" + if (scalar @ARGV == 0 || scalar @ARGV > 2); +my ($infile,$outfile) = @ARGV; + +if (not defined($outfile)) { + $outfile = $infile; + $outfile =~ s/\.c$/_unit.c/; + $outfile =~ s|.*/([^/]*)$|$1| if $outfile =~ m|/|; +} + +# Get the unit data +my ($unit_source,$suite_name,$suite_title)=("","",""); +my (%tests); # to detect multiple definition +my (@tests); # actual content + +open IN, "$infile" || die "$progname: Cannot open input file '$infile': $!\n"; + +my $takeit=0; +while () { + if (m/ifdef +SIMGRID_TEST/) { + $takeit = 1; + next; + } + if (m/endif.*SIMGRID_TEST/) { + $takeit = 0; + next + } + + if (m/XBT_TEST_SUITE\(\w*"([^"]*)"\w*,(.*?)\);/) { #" + die "$progname: Multiple suites in the same file ($infile) are not supported yet\n" + if length($suite_name); + ($suite_name,$suite_title)=($1,$2); + next; + } + + if (m/XBT_TEST_UNIT\(\w*"([^"]*)"\w*,([^,]*),(.*?)\)/) { #" + die "$progname: multiply defined test in file $infile: $1\n" + if (defined($tests{$1})); + + my @t=($1,$2,$3); + push @tests,\@t; + $tests{$1} = 1; + } + $unit_source .= $_ if $takeit; +} +close IN || die "$progname: cannot close input file '$infile': $!\n"; + + +if ($takeit) { + die "$progname: end of file reached in SIMGRID_TEST block.\n". + "You should end each of the with a line matching: /endif.*SIMGRID_TEST/\n". + "Example:\n". + "#endif /* SIMGRID_TEST */\n" +} + +die "$progname: no suite defined in $infile\n" + unless (length($suite_name)); + +# Write the test + +my ($GENERATED)=("/*******************************/\n". + "/* GENERATED FILE, DO NOT EDIT */\n". + "/*******************************/\n\n"); + +open OUT,">$outfile" || die "$progname: Cannot open output file '$outfile': $!\n"; +print OUT $GENERATED; +print OUT "#include \"xbt.h\"\n"; +print OUT $GENERATED; +print OUT "$unit_source"; +print OUT $GENERATED; +close OUT || die "$progname: Cannot close output file '$outfile': $!\n"; + +# write the main skeleton if needed +if (! -e "simgrid_units_main.c") { + open OUT,">simgrid_units_main.c" || die "$progname: Cannot open main file 'simgrid_units_main.c': $!\n"; + print OUT $GENERATED; + print OUT "#include \"xbt.h\"\n\n"; + print OUT "/* SGU: BEGIN PROTOTYPES */\n"; + print OUT "/* SGU: END PROTOTYPES */\n\n"; + print OUT $GENERATED; + print OUT "int main(int argc, char *argv[]) {\n"; + print OUT " xbt_test_suite_t suite;\n\n"; + print OUT " /* SGU: BEGIN SUITES DECLARATION */\n"; + print OUT " /* SGU: END SUITES DECLARATION */\n\n"; + print OUT " return xbt_test_run();\n"; + print OUT "}\n"; + print OUT $GENERATED; + close OUT || die "$progname: Cannot close main file 'simgrid_units_main.c': $!\n"; +} + +print " Suite $suite_name: $suite_title (".(scalar @tests)." tests)\n"; +map { + my ($name,$func,$title) = @{$_}; + print " test $name: func=$func; title=$title\n"; +} @tests; + +#while (my $t = shift @tests) { + +# add this suite to the main +my $newmain=""; +open IN,"simgrid_units_main.c" || die "$progname: Cannot open main file 'simgrid_units_main.c': $!\n"; + # search prototypes + while () { + $newmain .= $_; +# print "Look for proto: $_"; + last if /SGU: BEGIN PROTOTYPES/; + } + + # search my prototype + while () { +# print "Seek protos: $_"; + last if (/SGU: END PROTOTYPES/ || /SGU: BEGIN FILE $infile/); + $newmain .= $_; + } + if (/SGU: BEGIN FILE $infile/) { # found an old section for this file. Kill it + while () { + last if /SGU: END FILE/; + } + $_ = ; # pass extra blank line + chomp; + die "this line should be blank ($_). Did you edit the file?" if /\W/; + } + my ($old_)=($_); + # add my section + $newmain .= " /* SGU: BEGIN FILE $infile */\n"; + map { + my ($name,$func,$title) = @{$_}; + $newmain .= " void $func(xbt_test_unit_t _unit);\n" + } @tests; + + $newmain .= " /* SGU: END FILE */\n\n"; + if ($old_ =~ /SGU: BEGIN FILE/ || $old_ =~ /SGU: END PROTOTYPES/) { + $newmain .= $old_; + } + + # pass remaining prototypes, search declarations + while () { + $newmain .= $_ unless /SGU: END PROTOTYPES/; + last if /SGU: BEGIN SUITES DECLARATION/; + } + + ### Done with prototypes. And now, the actual code + + # search my prototype + while () { + last if (/SGU: END SUITES DECLARATION/ || /SGU: BEGIN FILE $infile/); + $newmain .= $_; + } + if (/SGU: BEGIN FILE $infile/) { # found an old section for this file. Kill it + while () { + last if /SGU: END FILE/; + } + $_ = ; # pass extra blank line + chomp; + die "this line should be blank ($_). Did you edit the file?" if /\W/; + } + my ($old_)=($_); + # add my section + $newmain .= " /* SGU: BEGIN FILE $infile */\n"; + $newmain .= " suite = xbt_test_suite_by_name(\"$suite_name\",$suite_title);\n"; + map { + my ($name,$func,$title) = @{$_}; + $newmain .= " xbt_test_suite_push(suite, $func, $title);\n"; + } @tests; + + $newmain .= " /* SGU: END FILE */\n\n"; + if ($old_ =~ /SGU: BEGIN FILE/ || $old_ =~ /SGU: END SUITES DECLARATION/) { + $newmain .= $old_; + } + + # pass the remaining + while () { + $newmain .= $_; + } +close IN || die "$progname: Cannot close main file 'simgrid_units_main.c': $!\n"; + +# write it back to main +open OUT,">simgrid_units_main.c" || die "$progname: Cannot open main file 'simgrid_units_main.c': $!\n"; +print OUT $newmain; +close OUT || die "$progname: Cannot close main file 'simgrid_units_main.c': $!\n"; + +0; \ No newline at end of file