Logo AND Algorithmique Numérique Distribuée

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