Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
Display what's going on as the unit is running, not afterward (some of them are a...
[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   if (suite == NULL)
219     return 0;
220
221   /* suite title pretty-printing */
222   {
223     char suite_title[80];
224     int suite_len=strlen(suite->title);
225     int i;
226
227     xbt_assert2(suite_len<70,"suite title \"%s\" too long (%d should be less than 70",
228                 suite->title,suite_len);
229     
230     suite_title[0]=' ';
231     for (i=1;i<79;i++)
232       suite_title[i]='=';
233     suite_title[i]='\0';
234
235     sprintf(suite_title + 40 - (suite_len+4)/2, "[ %s ]", suite->title);
236     suite_title[40 + (suite_len+5)/2] = '=';
237     fprintf(stderr, "\n%s\n",suite_title);
238   }
239
240   /* iterate through all tests */
241   xbt_dynar_foreach(suite->units, it_unit, unit) {
242     /* init unit case counters */
243     unit->nb_tests = 0;
244     unit->test_ignore = 0;
245     unit->test_failed = 0;
246     unit->test_expect = 0;
247
248     /* display unit title */
249     asprintf(&cp," Unit: %s ........................................"
250              "........................................", unit->title);
251     cp[72] = '\0';
252     fprintf(stderr, "%s", cp);
253     free(cp);
254
255     /* run the test case function */
256     _xbt_test_current_unit = unit;
257     unit->func();
258     
259     /* iterate through all performed tests to determine status */
260     xbt_dynar_foreach(unit->tests,it_test, test) {
261       if (test->ignored) {
262         unit->test_ignore++;
263       } else {
264         unit->nb_tests++;
265
266         if ( test->failed && !test->expected_failure) unit->test_failed++;
267         if (!test->failed &&  test->expected_failure) unit->test_failed++;
268         if (test->expected_failure)
269           unit->test_expect++;
270       }
271     }
272
273     /* Display whether this unit went well */
274     if (unit->test_failed > 0 || unit->test_expect) {
275       /* some tests failed (or were supposed to), so do detailed reporting of test case */
276       if (unit->test_failed > 0) {
277         fprintf(stderr, " failed\n");
278       } else if (unit->nb_tests) {
279         fprintf(stderr, ".... ok\n"); /* successful, but show about expected */
280       } else {
281         fprintf(stderr, ".. skip\n"); /* shouldn't happen, but I'm a bit lost with this logic */
282       }
283       xbt_dynar_foreach(unit->tests,it_test, test) {
284         file = (test->file != NULL ? test->file : unit->file);
285         line = (test->line != 0    ? test->line : unit->line);
286         fprintf(stderr, "      %s: %s [%s:%d]\n", 
287                 (test->ignored?" SKIP":(test->expected_failure?(test->failed?"EFAIL":"EPASS"):
288                                                                  (test->failed?" FAIL":" PASS"))),
289                 test->title, file, line);
290
291         xbt_dynar_foreach(test->logs,it_log,log) {
292           file = (log->file != NULL ? log->file : file);
293           line = (log->line != 0    ? log->line : line);
294             fprintf(stderr, "             %s:%d: %s\n", 
295                     file, line,log->text);
296
297         }
298       }
299       fprintf(stderr, "    Summary: %d of %d tests failed",unit->test_failed, unit->nb_tests);
300       if (unit->test_ignore) {
301         fprintf(stderr," (%d tests ignored)\n",unit->test_ignore);
302       } else {
303         fprintf(stderr,"\n");
304       }
305     } else if (unit->nb_tests) {
306       fprintf(stderr, ".... ok\n"); /* successful */
307     } else {
308       fprintf(stderr, ".. skip\n"); /* no test were run */
309     }
310
311
312     
313
314     /* Accumulate test counts into the suite */
315     suite->nb_tests    += unit->nb_tests;
316     suite->test_failed += unit->test_failed;
317     suite->test_ignore += unit->test_ignore;
318     suite->test_expect += unit->test_expect;
319
320     _xbt_test_nb_tests    += unit->nb_tests;
321     _xbt_test_test_failed += unit->test_failed;
322     _xbt_test_test_ignore += unit->test_ignore;
323     _xbt_test_test_expect += unit->test_expect;
324     
325     /* What's the conclusion of this test anyway? */
326     if (unit->nb_tests) {
327       suite->nb_units++;
328       if (unit->test_failed)
329         suite->unit_failed++;
330     } else {
331       suite->unit_ignore++;
332     }
333   }
334   _xbt_test_nb_units    += suite->nb_units;
335   _xbt_test_unit_failed += suite->unit_failed;
336   _xbt_test_unit_ignore += suite->unit_ignore;
337
338   if (suite->nb_units) {
339     _xbt_test_nb_suites++;
340     if (suite->test_failed)
341       _xbt_test_suite_failed++;
342   } else {
343     _xbt_test_suite_ignore++;
344   }
345
346   
347   /* print test suite summary */
348   fprintf(stderr,
349           " =======================================================================%s\n",
350           (suite->nb_units?(suite->unit_failed?" FAILED":"==== OK"):"== SKIP"));
351   fprintf(stderr, " Summary: Units: %.0f%% ok (%d units: ", 
352           suite->nb_units?((1-(double)suite->unit_failed/(double)suite->nb_units)*100.0):100.0,
353           suite->nb_units);
354   int first=1;
355   if (suite->nb_units != suite->unit_failed) {
356     fprintf(stderr, "%s%d ok",(first?"":", "),suite->nb_units - suite->unit_failed);
357     first = 0;
358   }
359   if (suite->unit_failed) {
360     fprintf(stderr, "%s%d failed",(first?"":", "),suite->unit_failed);
361     first = 0;
362   }
363   if (suite->unit_ignore) {
364     fprintf(stderr, "%s%d ignored",(first?"":", "),suite->unit_ignore);
365     first = 0;
366   }
367   fprintf(stderr,")\n          Tests: %.0f%% ok (%d tests: ",
368           suite->nb_tests?((1-(double)suite->test_failed/(double)suite->nb_tests)*100.0):100.0,
369           suite->nb_tests);
370
371   first=1;
372   if (suite->nb_tests != suite->test_failed) {
373     fprintf(stderr, "%s%d ok",(first?"":", "),suite->nb_tests - suite->test_failed);
374     first = 0;
375   }
376   if (suite->test_failed) {
377     fprintf(stderr, "%s%d failed",(first?"":", "),suite->test_failed);
378     first = 0;
379   }
380   if (suite->test_ignore) {
381     fprintf(stderr, "%s%d ignored",(first?"":"; "),suite->test_ignore);
382     first = 0;
383   }
384   if (suite->test_expect) {
385     fprintf(stderr, "%s%d expected to fail",(first?"":"; "),suite->test_expect);
386     first = 0;
387   }
388   fprintf(stderr,")\n");
389
390   return suite->unit_failed;
391 }
392
393 int xbt_test_run(void) {
394   
395   if (_xbt_test_suites) {
396     int it_suite;
397     xbt_test_suite_t suite;
398     int first=1;
399     
400     /* Run all the suites */
401     xbt_dynar_foreach(_xbt_test_suites,it_suite,suite) 
402       xbt_test_suite_run(suite);
403
404     /* Display some more statistics */
405     fprintf(stderr,"\n\n TOTAL: Suites: %.0f%% ok (%d suites: ",
406             _xbt_test_nb_suites
407               ? ((1-(double)_xbt_test_suite_failed/(double)_xbt_test_nb_suites)*100.0)
408               : 100.0,
409             _xbt_test_nb_suites);
410     if (_xbt_test_nb_suites != _xbt_test_suite_failed) {
411       fprintf(stderr, "%d ok",_xbt_test_nb_suites - _xbt_test_suite_failed);
412       first = 0;
413     }
414     if (_xbt_test_suite_failed) {
415       fprintf(stderr, "%s%d failed",(first?"":", "),_xbt_test_suite_failed);
416       first = 0;
417     }
418     
419     if (_xbt_test_suite_ignore) {
420       fprintf(stderr, "%s%d ignored",(first?"":", "),_xbt_test_suite_ignore);
421       first = 0;
422     }
423     fprintf(stderr,")\n        Units:  %.0f%% ok (%d units: ",
424             _xbt_test_nb_units?((1-(double)_xbt_test_unit_failed/(double)_xbt_test_nb_units)*100.0):100.0,
425             _xbt_test_nb_units);
426     first=1;
427     if (_xbt_test_nb_units != _xbt_test_unit_failed) {
428       fprintf(stderr, "%s%d ok",(first?"":", "),_xbt_test_nb_units - _xbt_test_unit_failed);
429       first = 0;
430     }
431     if (_xbt_test_unit_failed) {
432       fprintf(stderr, "%s%d failed",(first?"":", "),_xbt_test_unit_failed);
433       first = 0;
434     }
435     if (_xbt_test_unit_ignore) {
436       fprintf(stderr, "%s%d ignored",(first?"":", "),_xbt_test_unit_ignore);
437       first = 0;
438     }
439     fprintf(stderr,")\n        Tests:  %.0f%% ok (%d tests: ",
440             _xbt_test_nb_tests?((1-(double)_xbt_test_test_failed/(double)_xbt_test_nb_tests)*100.0):100.0,
441             _xbt_test_nb_tests);
442     first=1;
443     if (_xbt_test_nb_tests != _xbt_test_test_failed) {
444       fprintf(stderr, "%s%d ok",(first?"":", "),_xbt_test_nb_tests - _xbt_test_test_failed);
445       first = 0;
446     }
447     if (_xbt_test_test_failed) {
448       fprintf(stderr, "%s%d failed",(first?"":", "),_xbt_test_test_failed);
449       first = 0;
450     }
451     if (_xbt_test_test_ignore) {
452       fprintf(stderr, "%s%d ignored",(first?"":", "),_xbt_test_test_ignore);
453       first = 0;
454     }
455     if (_xbt_test_test_expect) {
456       fprintf(stderr, "%s%d expected to fail",(first?"":", "),_xbt_test_test_expect);
457     }
458     
459     fprintf(stderr,")\n");
460   } else {
461     fprintf(stderr,"No unit to run!\n");
462     _xbt_test_unit_failed++;
463   }
464   return _xbt_test_unit_failed;
465 }
466
467
468 /* annotate test case with test */
469 void _xbt_test_add(const char*file,int line, const char *fmt, ...) {
470   xbt_test_unit_t unit=_xbt_test_current_unit;
471   xbt_test_test_t test;
472   va_list ap;
473   
474   xbt_assert(unit);
475   xbt_assert(fmt);
476
477   test = xbt_new(struct s_xbt_test_test,1);
478   va_start(ap, fmt);
479   vasprintf(&test->title, fmt, ap);
480   va_end(ap);
481   test->failed = 0;
482   test->expected_failure = 0;
483   test->ignored = 0;
484   test->file = file;
485   test->line = line;
486   test->logs = xbt_dynar_new(sizeof(xbt_test_log_t),NULL);
487   xbt_dynar_push(unit->tests,&test);
488   return;
489 }
490
491 /* annotate test case with log message and failure */
492 void _xbt_test_fail(const char*file,int line,const char *fmt, ...) {
493   xbt_test_unit_t unit = _xbt_test_current_unit;
494   xbt_test_test_t test;
495   xbt_test_log_t log;
496   va_list ap;
497   
498   xbt_assert(unit);
499   xbt_assert(fmt);
500
501   xbt_assert1(xbt_dynar_length(_xbt_test_current_unit->tests),
502               "Test failed even before being declared (broken unit: %s)",
503               unit->title);
504
505   log = xbt_new(struct s_xbt_test_log,1);
506   va_start(ap, fmt);
507   vasprintf(&log->text,fmt, ap);
508   va_end(ap);
509   log->file = file;
510   log->line = line;
511
512   test = xbt_dynar_getlast_as(unit->tests, xbt_test_test_t);
513   xbt_dynar_push(test->logs, &log);
514
515   test->failed = 1;
516 }
517
518 void xbt_test_exception(xbt_ex_t e) {
519   _xbt_test_fail(e.file,e.line,"Exception %s raised: %s",xbt_ex_catname(e.category),e.msg);
520 }
521
522 void xbt_test_expect_failure(void) {
523   xbt_test_test_t test;
524   xbt_assert1(xbt_dynar_length(_xbt_test_current_unit->tests),
525               "Cannot expect the failure of a test before declaring it (broken unit: %s)",
526               _xbt_test_current_unit->title);
527   test = xbt_dynar_getlast_as(_xbt_test_current_unit->tests,xbt_test_test_t);
528   test->expected_failure = 1;
529 }
530 void xbt_test_skip(void) {
531   xbt_test_test_t test;
532
533   xbt_assert1(xbt_dynar_length(_xbt_test_current_unit->tests),
534               "Test skiped even before being declared (broken unit: %s)",
535               _xbt_test_current_unit->title);
536
537   test = xbt_dynar_getlast_as(_xbt_test_current_unit->tests,
538                               xbt_test_test_t);
539   test->ignored = 1;
540 }
541
542 /* annotate test case with log message only */
543 void _xbt_test_log(const char*file,int line,const char *fmt, ...) {
544   xbt_test_unit_t unit=_xbt_test_current_unit;
545   xbt_test_test_t test;
546   xbt_test_log_t log;
547   va_list ap;
548
549   xbt_assert(unit);
550   xbt_assert(fmt);
551
552   xbt_assert1(xbt_dynar_length(_xbt_test_current_unit->tests),
553               "Test logged into even before being declared (broken test unit: %s)",unit->title);
554
555   log = xbt_new(struct s_xbt_test_log,1);
556   va_start(ap, fmt);
557   vasprintf(&log->text, fmt, ap);
558   va_end(ap);
559   log->file = file;
560   log->line = line;
561
562   test = xbt_dynar_getlast_as(unit->tests,xbt_test_test_t);
563   xbt_dynar_push(test->logs, &log);
564 }
565
566
567
568
569 #ifdef SIMGRID_TEST
570
571 XBT_TEST_SUITE("cuint","Testsuite Autotest %d",0);
572
573 XBT_TEST_UNIT("expect",test_expected_failure,"expected failures") {
574     xbt_test_add0("Skipped test");
575     xbt_test_skip(); 
576
577     xbt_test_add2("%s %s","EXPECTED","FAILURE");
578     xbt_test_expect_failure();
579     xbt_test_log2("%s %s","Test","log");
580     xbt_test_fail0("EXPECTED FAILURE");
581 }
582
583 #endif /* SIMGRID_TEST */