Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
Readd the example we need in the documentation, they used to live in testsuite/xbt...
[simgrid.git] / src / xbt / cunit.c
1 /* $Id$ */
2
3 /* cunit - A little C Unit facility                                         */
4
5 /* Copyright (c) 2005 Martin Quinson. All rights reserved.                  */
6
7 /* This program is free software; you can redistribute it and/or modify it
8  * under the terms of the license (GNU LGPL) which comes with this package. */
9
10 /* This is partially inspirated from the OSSP ts (Test Suite Library)       */
11
12 #include "gras_config.h"
13
14 #include "xbt/sysdep.h"    /* vasprintf */
15 #include "xbt/cunit.h"
16 #include "xbt/dynar.h"
17
18 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(testsuite,xbt,"Test infrastructure");
19
20 /* collection of all suites */
21 static xbt_dynar_t _xbt_test_suites = NULL; 
22 /* global statistics */
23 static int _xbt_test_nb_tests = 0;
24 static int _xbt_test_test_failed = 0;
25 static int _xbt_test_test_ignore = 0;
26 static int _xbt_test_test_expect = 0;
27
28 static int _xbt_test_nb_units    = 0;
29 static int _xbt_test_unit_failed = 0;
30 static int _xbt_test_unit_ignore = 0;
31
32 static int _xbt_test_nb_suites    = 0;
33 static int _xbt_test_suite_failed = 0;
34 static int _xbt_test_suite_ignore = 0;
35
36
37 /* test suite test log */
38 typedef struct s_xbt_test_log {
39   char              *text;
40   const char        *file;
41   int                line;
42 } *xbt_test_log_t;
43
44 static void xbt_test_log_dump(xbt_test_log_t log) {
45   if (log)
46     fprintf(stderr,"      log %p(%s:%d)=%s\n",log,log->file,log->line,log->text);
47   else
48     fprintf(stderr,"      log=NULL\n");    
49 }
50 static void xbt_test_log_free(xbt_test_log_t log) {
51   if (!log)
52     return;
53   if (log->text)
54     free(log->text);
55   free(log);
56 }
57
58 /* test suite test check */
59 typedef struct s_xbt_test_test {
60   char        *title;
61   int          failed;
62   int          expected_failure;
63   int          ignored;
64   const char  *file;
65   int          line;
66   xbt_dynar_t  logs;
67 } *xbt_test_test_t;
68
69 static void xbt_test_test_dump(xbt_test_test_t test){
70   if (test) {
71     xbt_test_log_t log;
72     int it_log;
73     fprintf(stderr,"    test %p(%s:%d)=%s (%s)\n",
74             test,test->file,test->line,test->title,
75             test->failed?"failed":"not failed");
76     xbt_dynar_foreach(test->logs,it_log,log)
77       xbt_test_log_dump(log);
78   }
79   else
80     fprintf(stderr,"    test=NULL\n");     
81 }
82
83 /* test suite test unit */
84 struct s_xbt_test_unit {
85   char        *title;
86   ts_test_cb_t func;
87   const char  *file;
88   int          line;
89   xbt_dynar_t  tests; /* of xbt_test_test_t*/
90
91   int nb_tests;
92   int test_failed,test_ignore,test_expect;
93 };
94
95 static void xbt_test_unit_dump(xbt_test_unit_t unit) {
96   if (unit) {
97     xbt_test_test_t test;
98     int it_test;
99     fprintf(stderr,"  unit %p(%s:%d)=%s (func=%p)\n",
100             unit,unit->file,unit->line,unit->title,unit->file);
101     xbt_dynar_foreach(unit->tests,it_test,test)
102       xbt_test_test_dump(test);
103   } else {
104     fprintf(stderr,"  unit=NULL\n");
105   }
106 }
107
108 /* test suite */
109 struct s_xbt_test_suite {
110   const char *name;
111   char       *title;
112   xbt_dynar_t units; /* of xbt_test_unit_t */
113
114   int nb_tests,nb_units;
115   int test_failed,test_ignore,test_expect;
116   int unit_failed,unit_ignore;
117 };
118
119 /* destroy test suite */
120 static void xbt_test_suite_free(void *s) {
121   xbt_test_suite_t suite = *(xbt_test_suite_t*) s;
122
123   if (suite == NULL)
124     return;
125   xbt_dynar_free(&suite->units);
126   free(suite->title);
127   free(suite);
128 }
129
130 /** @brief create test suite */
131 xbt_test_suite_t xbt_test_suite_new(const char *name, const char *fmt, ...) {
132   xbt_test_suite_t suite = xbt_new0(struct s_xbt_test_suite,1);
133   va_list ap;
134
135   if (!_xbt_test_suites) 
136     _xbt_test_suites = xbt_dynar_new(sizeof(xbt_test_suite_t),&xbt_test_suite_free);
137
138   va_start(ap, fmt);
139   vasprintf(&suite->title,fmt, ap);
140   suite->units = xbt_dynar_new(sizeof(xbt_test_unit_t), NULL);
141   va_end(ap);
142   suite->name=name;
143
144   xbt_dynar_push(_xbt_test_suites,&suite);
145
146   return suite;
147 }
148
149 /** @brief retrive a testsuite from name, or create a new one */
150 xbt_test_suite_t xbt_test_suite_by_name(const char *name,const char *fmt, ...) {
151   xbt_test_suite_t suite;
152   int it_suite;
153
154   char *bufname;
155   va_list ap;
156
157   if (_xbt_test_suites)
158     xbt_dynar_foreach(_xbt_test_suites, it_suite, suite)
159       if (!strcmp(suite->name,name))
160         return suite;
161   
162   va_start(ap, fmt);
163   vasprintf(&bufname,fmt, ap);
164   va_end(ap);
165   suite = xbt_test_suite_new(name,bufname,NULL);
166   free(bufname);
167   
168   return suite;
169 }
170
171 void xbt_test_suite_dump(xbt_test_suite_t suite) {
172   if (suite) {
173     xbt_test_unit_t unit;
174     int it_unit;
175     fprintf(stderr,"DUMP suite %s\n",suite->title);
176     xbt_dynar_foreach(suite->units,it_unit,unit)
177       xbt_test_unit_dump(unit);
178   } else {
179     fprintf(stderr,"suite=NULL\n");
180   }
181 }
182
183 /* add test case to test suite */
184 void xbt_test_suite_push(xbt_test_suite_t suite, ts_test_cb_t func, const char *fmt, ...) {
185   xbt_test_unit_t unit;
186   va_list ap;
187   
188   xbt_assert(suite);
189   xbt_assert(func);
190   xbt_assert(fmt);
191
192   unit = xbt_new(struct s_xbt_test_unit,1);
193   va_start(ap, fmt);
194   vasprintf(&unit->title, fmt, ap);
195   va_end(ap);
196   unit->func = func;
197   unit->file = NULL;
198   unit->line = 0;
199   unit->tests = xbt_dynar_new(sizeof(xbt_test_test_t), NULL);
200   
201   xbt_dynar_push(suite->units, &unit);
202   return;
203 }
204
205 /* run test one suite */
206 static int xbt_test_suite_run(xbt_test_suite_t suite) {
207   xbt_test_unit_t unit;
208   xbt_test_test_t test;
209   xbt_test_log_t log;
210
211   const char *file;
212   int line;
213   char *cp;
214   int it_unit,it_test,it_log;
215
216   if (suite == NULL)
217     return 0;
218
219   /* iterate through all tests to see how much failed */
220   xbt_dynar_foreach(suite->units, it_unit, unit) {
221     /* init unit case counters */
222     unit->nb_tests = 0;
223     unit->test_ignore = 0;
224     unit->test_failed = 0;
225     unit->test_expect = 0;
226
227     /* run the test case function */
228     unit->func(unit);
229   
230     /* iterate through all performed tests to determine status */
231     xbt_dynar_foreach(unit->tests,it_test, test) {
232       if (test->ignored) {
233         unit->test_ignore++;
234       } else {
235         unit->nb_tests++;
236
237         if ( test->failed && !test->expected_failure) unit->test_failed++;
238         if (!test->failed &&  test->expected_failure) unit->test_failed++;
239         if (test->expected_failure)
240           unit->test_expect++;
241       }
242     }
243     
244     /* Accumulate test counts into the suite */
245     suite->nb_tests    += unit->nb_tests;
246     suite->test_failed += unit->test_failed;
247     suite->test_ignore += unit->test_ignore;
248     suite->test_expect += unit->test_expect;
249
250     _xbt_test_nb_tests    += unit->nb_tests;
251     _xbt_test_test_failed += unit->test_failed;
252     _xbt_test_test_ignore += unit->test_ignore;
253     _xbt_test_test_expect += unit->test_expect;
254     
255     /* What's the conclusion of this test anyway? */
256     if (unit->nb_tests) {
257       suite->nb_units++;
258       if (unit->test_failed)
259         suite->unit_failed++;
260     } else {
261       suite->unit_ignore++;
262     }
263   }
264   _xbt_test_nb_units    += suite->nb_units;
265   _xbt_test_unit_failed += suite->unit_failed;
266   _xbt_test_unit_ignore += suite->unit_ignore;
267
268   if (suite->nb_units) {
269     _xbt_test_nb_suites++;
270     if (suite->test_failed)
271       _xbt_test_suite_failed++;
272   } else {
273     _xbt_test_suite_ignore++;
274   }
275
276   /* suite title pretty-printing */
277   {
278     char suite_title[80];
279     int suite_len=strlen(suite->title);
280     int i;
281
282     xbt_assert2(suite_len<70,"suite title \"%s\" too long (%d should be less than 70",
283                 suite->title,suite_len);
284     
285     suite_title[0]=' ';
286     for (i=1;i<79;i++)
287       suite_title[i]='=';
288     suite_title[i]='\0';
289
290     sprintf(suite_title + 40 - (suite_len+4)/2, "[ %s ]", suite->title);
291     suite_title[40 + (suite_len+4)/2] = '=';
292
293     fprintf(stderr, "\n%s  %s\n",suite_title,
294             (suite->nb_units?(suite->unit_failed?"FAILED":"OK"):"SKIP"));
295     
296   }
297   
298   /* iterate through all test cases to display details */
299   xbt_dynar_foreach(suite->units, it_unit, unit) {
300     asprintf(&cp," Unit: %s ........................................"
301              "........................................", unit->title);
302     cp[72] = '\0';
303     fprintf(stderr, "%s", cp);
304     free(cp);
305     
306     if (unit->test_failed > 0 || unit->test_expect) {
307       /* some tests failed (or were supposed to), so do detailed reporting of test case */
308       if (unit->test_failed > 0) {
309         fprintf(stderr, " failed\n");
310       } else if (unit->nb_tests) {
311         fprintf(stderr, ".... ok\n"); /* successful, but show about expected */
312       } else {
313         fprintf(stderr, ".. skip\n"); /* shouldn't happen, but I'm a bit lost with this logic */
314       }
315       xbt_dynar_foreach(unit->tests,it_test, test) {
316         file = (test->file != NULL ? test->file : unit->file);
317         line = (test->line != 0    ? test->line : unit->line);
318         fprintf(stderr, "      %s: %s [%s:%d]\n", 
319                 (test->ignored?" SKIP":(test->expected_failure?(test->failed?"EFAIL":"EPASS"):
320                                                                  (test->failed?" FAIL":" PASS"))),
321                 test->title, file, line);
322
323         xbt_dynar_foreach(test->logs,it_log,log) {
324           file = (log->file != NULL ? log->file : file);
325           line = (log->line != 0    ? log->line : line);
326             fprintf(stderr, "             %s:%d: %s\n", 
327                     file, line,log->text);
328
329         }
330       }
331       fprintf(stderr, "    Summary: %d of %d tests failed",unit->test_failed, unit->nb_tests);
332       if (unit->test_ignore) {
333         fprintf(stderr," (%d tests ignored)\n",unit->test_ignore);
334       } else {
335         fprintf(stderr,"\n");
336       }
337     } else if (unit->nb_tests) {
338       fprintf(stderr, ".... ok\n"); /* successful */
339     } else {
340       fprintf(stderr, ".. skip\n"); /* no test were run */
341     }
342   }
343   
344   /* print test suite summary */
345   fprintf(stderr, " ==============================================================================\n");
346   fprintf(stderr, " Summary: Units: %.0f%% ok (%d units: ", 
347           suite->nb_units?((1-(double)suite->unit_failed/(double)suite->nb_units)*100.0):100.0,
348           suite->nb_units);
349   int first=1;
350   if (suite->nb_units != suite->unit_failed) {
351     fprintf(stderr, "%s%d ok",(first?"":", "),suite->nb_units - suite->unit_failed);
352     first = 0;
353   }
354   if (suite->unit_failed) {
355     fprintf(stderr, "%s%d failed",(first?"":", "),suite->unit_failed);
356     first = 0;
357   }
358   if (suite->unit_ignore) {
359     fprintf(stderr, "%s%d ignored",(first?"":", "),suite->unit_ignore);
360     first = 0;
361   }
362   fprintf(stderr,")\n          Tests: %.0f%% ok (%d tests: ",
363           suite->nb_tests?((1-(double)suite->test_failed/(double)suite->nb_tests)*100.0):100.0,
364           suite->nb_tests);
365
366   first=1;
367   if (suite->nb_tests != suite->test_failed) {
368     fprintf(stderr, "%s%d ok",(first?"":", "),suite->nb_tests - suite->test_failed);
369     first = 0;
370   }
371   if (suite->test_failed) {
372     fprintf(stderr, "%s%d failed",(first?"":", "),suite->test_failed);
373     first = 0;
374   }
375   if (suite->test_ignore) {
376     fprintf(stderr, "%s%d ignored",(first?"":"; "),suite->test_ignore);
377     first = 0;
378   }
379   if (suite->test_expect) {
380     fprintf(stderr, "%s%d expected to fail",(first?"":"; "),suite->test_expect);
381     first = 0;
382   }
383   fprintf(stderr,")\n");
384
385   return suite->unit_failed;
386 }
387
388 int xbt_test_run(void) {
389   
390   if (_xbt_test_suites) {
391     int it_suite;
392     xbt_test_suite_t suite;
393     int first=1;
394     
395     /* Run all the suites */
396     xbt_dynar_foreach(_xbt_test_suites,it_suite,suite) 
397       xbt_test_suite_run(suite);
398
399     /* Display some more statistics */
400     fprintf(stderr,"\n\n TOTAL: Suites: %.0f%% ok (%d suites: ",
401             _xbt_test_nb_suites
402               ? ((1-(double)_xbt_test_suite_failed/(double)_xbt_test_nb_suites)*100.0)
403               : 100.0,
404             _xbt_test_nb_suites);
405     if (_xbt_test_nb_suites != _xbt_test_suite_failed) {
406       fprintf(stderr, "%d ok",_xbt_test_nb_suites - _xbt_test_suite_failed);
407       first = 0;
408     }
409     if (_xbt_test_suite_failed) {
410       fprintf(stderr, "%s%d failed",(first?"":", "),_xbt_test_suite_failed);
411       first = 0;
412     }
413     
414     if (_xbt_test_suite_ignore) {
415       fprintf(stderr, "%s%d ignored",(first?"":", "),_xbt_test_suite_ignore);
416       first = 0;
417     }
418     fprintf(stderr,")\n        Units:  %.0f%% ok (%d units:  ",
419             _xbt_test_nb_units?((1-(double)_xbt_test_unit_failed/(double)_xbt_test_nb_units)*100.0):100.0,
420             _xbt_test_nb_units);
421     first=1;
422     if (_xbt_test_nb_units != _xbt_test_unit_failed) {
423       fprintf(stderr, "%s%d ok",(first?"":", "),_xbt_test_nb_units - _xbt_test_unit_failed);
424       first = 0;
425     }
426     if (_xbt_test_unit_failed) {
427       fprintf(stderr, "%s%d failed",(first?"":", "),_xbt_test_unit_failed);
428       first = 0;
429     }
430     if (_xbt_test_unit_ignore) {
431       fprintf(stderr, "%s%d ignored",(first?"":", "),_xbt_test_unit_ignore);
432       first = 0;
433     }
434     fprintf(stderr,")\n        Tests:  %.0f%% ok (%d tests:  ",
435             _xbt_test_nb_tests?((1-(double)_xbt_test_test_failed/(double)_xbt_test_nb_tests)*100.0):100.0,
436             _xbt_test_nb_tests);
437     first=1;
438     if (_xbt_test_nb_tests != _xbt_test_test_failed) {
439       fprintf(stderr, "%s%d ok",(first?"":", "),_xbt_test_nb_tests - _xbt_test_test_failed);
440       first = 0;
441     }
442     if (_xbt_test_test_failed) {
443       fprintf(stderr, "%s%d failed",(first?"":", "),_xbt_test_test_failed);
444       first = 0;
445     }
446     if (_xbt_test_test_ignore) {
447       fprintf(stderr, "%s%d ignored",(first?"":", "),_xbt_test_test_ignore);
448       first = 0;
449     }
450     if (_xbt_test_test_expect) {
451       fprintf(stderr, "%s%d expected to fail",(first?"":", "),_xbt_test_test_expect);
452     }
453     
454     fprintf(stderr,")\n");
455   } else {
456     fprintf(stderr,"No unit to run!\n");
457     _xbt_test_unit_failed++;
458   }
459   return _xbt_test_unit_failed;
460 }
461
462
463 /* annotate test case with test */
464 void _xbt_test_add(xbt_test_unit_t unit, const char*file,int line, const char *fmt, ...) {
465   xbt_test_test_t test;
466   va_list ap;
467   
468   xbt_assert(unit);
469   xbt_assert(fmt);
470
471   test = xbt_new(struct s_xbt_test_test,1);
472   va_start(ap, fmt);
473   vasprintf(&test->title, fmt, ap);
474   va_end(ap);
475   test->failed = 0;
476   test->expected_failure = 0;
477   test->ignored = 0;
478   test->file = file;
479   test->line = line;
480   test->logs = xbt_dynar_new(sizeof(xbt_test_log_t),NULL);
481   xbt_dynar_push(unit->tests,&test);
482   return;
483 }
484
485 /* annotate test case with log message and failure */
486 void _xbt_test_fail(xbt_test_unit_t unit,  const char*file,int line,const char *fmt, ...) {
487   xbt_test_test_t test;
488   xbt_test_log_t log;
489   va_list ap;
490   
491   xbt_assert(unit);
492   xbt_assert(fmt);
493
494   log = xbt_new(struct s_xbt_test_log,1);
495   va_start(ap, fmt);
496   vasprintf(&log->text,fmt, ap);
497   va_end(ap);
498   log->file = file;
499   log->line = line;
500
501   test = xbt_dynar_getlast_as(unit->tests, xbt_test_test_t);
502   xbt_dynar_push(test->logs, &log);
503
504   test->failed = 1;
505 }
506
507 void _xbt_test_expect_failure(xbt_test_unit_t unit) {
508   xbt_test_test_t test = xbt_dynar_getlast_as(unit->tests,xbt_test_test_t);
509   test->expected_failure = 1;
510 }
511 void _xbt_test_skip(xbt_test_unit_t unit) {
512   xbt_test_test_t test = xbt_dynar_getlast_as(unit->tests,xbt_test_test_t);
513   test->ignored = 1;
514 }
515
516 /* annotate test case with log message only */
517 void _xbt_test_log(xbt_test_unit_t unit, const char*file,int line,const char *fmt, ...) {
518   xbt_test_test_t test;
519   xbt_test_log_t log;
520   va_list ap;
521
522   xbt_assert(unit);
523   xbt_assert(fmt);
524
525   log = xbt_new(struct s_xbt_test_log,1);
526   va_start(ap, fmt);
527   vasprintf(&log->text, fmt, ap);
528   va_end(ap);
529   log->file = file;
530   log->line = line;
531
532   test = xbt_dynar_getlast_as(unit->tests,xbt_test_test_t);
533   xbt_dynar_push(test->logs, &log);
534 }
535
536
537
538
539 #ifdef SIMGRID_TEST
540
541 XBT_TEST_SUITE("cuint","Testsuite Autotest %d",0);
542
543 XBT_TEST_UNIT("expect",test_expected_failure,"expected failures") {
544     xbt_test_add0("Skipped test");
545     xbt_test_skip(); 
546
547     xbt_test_add2("%s %s","EXPECTED","FAILURE");
548     xbt_test_expect_failure();
549     xbt_test_log2("%s %s","Test","log");
550     xbt_test_fail0("EXPECTED FAILURE");
551 }
552
553 #endif /* SIMGRID_TEST */