Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
Add a tool to automatically extract the test units from the source code of the librar...
authormquinson <mquinson@48e7efb5-ca39-0410-a469-dd3cf9ba447f>
Sun, 23 Oct 2005 10:18:21 +0000 (10:18 +0000)
committermquinson <mquinson@48e7efb5-ca39-0410-a469-dd3cf9ba447f>
Sun, 23 Oct 2005 10:18:21 +0000 (10:18 +0000)
git-svn-id: svn+ssh://scm.gforge.inria.fr/svn/simgrid/simgrid/trunk@1802 48e7efb5-ca39-0410-a469-dd3cf9ba447f

include/xbt/cunit.h
src/.cvsignore
src/Makefile.am
src/xbt/cunit.c
src/xbt/ex.c
testsuite/xbt/ex_test.c
tools/sg_unit_extractor.pl [new file with mode: 0755]

index bdffc53..99114dc 100644 (file)
@@ -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_ */
 
index 1baec79..067612c 100644 (file)
@@ -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*
index ddf0471..aa2f1d5 100644 (file)
@@ -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
index 0f8b625..6f8faf5 100644 (file)
@@ -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 */
index 7e53f12..31209f5 100644 (file)
@@ -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 */
index 21dbd89..78b2f57 100644 (file)
 **  ex_test.c: exception handling test suite
 */
 
-#include <stdio.h>
-#include <stdlib.h>
-#include <time.h>
-#include <string.h>
-
 #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 (executable)
index 0000000..e7d1422
--- /dev/null
@@ -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 (<IN>) {
+  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 (<IN>) {
+    $newmain .= $_;
+#    print "Look for proto: $_";
+    last if /SGU: BEGIN PROTOTYPES/;
+  }
+
+  # search my prototype
+  while (<IN>) {
+#    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 (<IN>) {
+      last if /SGU: END FILE/;
+    }
+    $_ = <IN>; # 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 (<IN>) {
+    $newmain .= $_ unless /SGU: END PROTOTYPES/;
+    last if /SGU: BEGIN SUITES DECLARATION/;
+  }
+
+  ###┬áDone with prototypes. And now, the actual code
+  
+  # search my prototype
+  while (<IN>) {
+    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 (<IN>) {
+      last if /SGU: END FILE/;
+    }
+    $_ = <IN>; # 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 (<IN>) {
+    $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