From: mquinson Date: Sat, 22 Oct 2005 22:45:23 +0000 (+0000) Subject: Rename testsuite to cunit (more sexy name); integrate it properly into SimGrid; use... X-Git-Tag: v3.3~3558 X-Git-Url: http://info.iut-bm.univ-fcomte.fr/pub/gitweb/simgrid.git/commitdiff_plain/423d998b546e97c9b535e6e703768fb6a7ebb2fc?ds=sidebyside Rename testsuite to cunit (more sexy name); integrate it properly into SimGrid; use it to test exceptions and itself git-svn-id: svn+ssh://scm.gforge.inria.fr/svn/simgrid/simgrid/trunk@1800 48e7efb5-ca39-0410-a469-dd3cf9ba447f --- diff --git a/ChangeLog b/ChangeLog index 0f61356d57..7e4d312ffb 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,7 +1,8 @@ SimGrid (3.0.2) unstable; urgency=low XBT: - * New module: testsuite [MQ] + * New module: cunit [MQ] + * New functions: xbt_dynar_getfirst_as() and xbt_dynar_getlast_as() [MQ] -- diff --git a/include/xbt.h b/include/xbt.h index 75ef4df957..64fbbc414d 100644 --- a/include/xbt.h +++ b/include/xbt.h @@ -25,6 +25,6 @@ #include #include -#include +#include #endif /* xbt_H */ diff --git a/include/xbt/cunit.h b/include/xbt/cunit.h new file mode 100644 index 0000000000..bdffc53de7 --- /dev/null +++ b/include/xbt/cunit.h @@ -0,0 +1,71 @@ +/* $Id$ */ + +/* cunit - A little C Unit facility */ + +/* Copyright (c) 2005 Martin Quinson. All rights reserved. */ + +/* This program is free software; you can redistribute it and/or modify it + * under the terms of the license (GNU LGPL) which comes with this package. */ + +/* This is partially inspirated from the OSSP ts (Test Suite Library) */ + +#ifndef _XBT_CUNIT_H_ +#define _XBT_CUNIT_H_ + +#include "xbt/sysdep.h" /* XBT_GNU_PRINTF */ + +/* test suite object type */ +typedef struct s_xbt_test_suite *xbt_test_suite_t; + +/* test object type */ +typedef struct s_xbt_test_unit *xbt_test_unit_t; + +/* test callback function type */ +typedef void (*ts_test_cb_t)(xbt_test_unit_t); + +/* test suite operations */ +xbt_test_suite_t xbt_test_suite_new (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, ...); + +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_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) +#define xbt_test_fail1(fmt,a) _xbt_test_fail(_unit, __FILE__, __LINE__, fmt,a) +#define xbt_test_fail2(fmt,a,b) _xbt_test_fail(_unit, __FILE__, __LINE__, fmt,a,b) +#define xbt_test_fail3(fmt,a,b,c) _xbt_test_fail(_unit, __FILE__, __LINE__, fmt,a,b,c) +#define xbt_test_fail4(fmt,a,b,c,d) _xbt_test_fail(_unit, __FILE__, __LINE__, fmt,a,b,c,d) +#define xbt_test_fail5(fmt,a,b,c,d,e) _xbt_test_fail(_unit, __FILE__, __LINE__, fmt,a,b,c,d,e) + +void _xbt_test_log (xbt_test_unit_t u, const char*file,int line, const char *fmt, ...)_XBT_GNUC_PRINTF(4,5); +#define xbt_test_log0(fmt) _xbt_test_log(_unit, __FILE__, __LINE__, fmt) +#define xbt_test_log1(fmt,a) _xbt_test_log(_unit, __FILE__, __LINE__, fmt,a) +#define xbt_test_log2(fmt,a,b) _xbt_test_log(_unit, __FILE__, __LINE__, fmt,a,b) +#define xbt_test_log3(fmt,a,b,c) _xbt_test_log(_unit, __FILE__, __LINE__, fmt,a,b,c) +#define xbt_test_log4(fmt,a,b,c,d) _xbt_test_log(_unit, __FILE__, __LINE__, fmt,a,b,c,d) +#define xbt_test_log5(fmt,a,b,c,d,e) _xbt_test_log(_unit, __FILE__, __LINE__, fmt,a,b,c,d,e) + +void _xbt_test_expect_failure(xbt_test_unit_t unit); +#define xbt_test_expect_failure() _xbt_test_expect_failure(_unit) + +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) + +#endif /* _TS_H_ */ + diff --git a/include/xbt/testsuite.h b/include/xbt/testsuite.h deleted file mode 100644 index 8d01123157..0000000000 --- a/include/xbt/testsuite.h +++ /dev/null @@ -1,64 +0,0 @@ -/* -** OSSP ts - Test Suite Library -** Copyright (c) 2001-2004 Ralf S. Engelschall -** Copyright (c) 2001-2004 The OSSP Project -** Copyright (c) 2001-2004 Cable & Wireless -** -** This file is part of OSSP ts, a small test suite library which -** can be found at http://www.ossp.org/pkg/lib/ts/. -** -** Permission to use, copy, modify, and distribute this software for -** any purpose with or without fee is hereby granted, provided that -** the above copyright notice and this permission notice appear in all -** copies. -** -** THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED -** WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -** IN NO EVENT SHALL THE AUTHORS AND COPYRIGHT HOLDERS AND THEIR -** CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF -** USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -** ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -** OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT -** OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -** SUCH DAMAGE. -** -** ts.h: test suite library API -*/ - -#ifndef _TS_H_ -#define _TS_H_ - -/* test suite object type */ -struct ts_suite_st; -typedef struct ts_suite_st ts_suite_t; - -/* test object type */ -struct ts_test_st; -typedef struct ts_test_st ts_test_t; - -/* test callback function type */ -typedef void (*ts_test_cb_t)(ts_test_t *); - -/* test suite operations */ -ts_suite_t *ts_suite_new (const char *fmt, ...); -void ts_suite_test (ts_suite_t *s, ts_test_cb_t func, const char *fmt, ...); -int ts_suite_run (ts_suite_t *s); -void ts_suite_free (ts_suite_t *s); - -/* test operations */ -ts_test_t *ts_test_ctx (ts_test_t *t, const char *file, int line); -void ts_test_check (ts_test_t *t, const char *fmt, ...); -void ts_test_fail (ts_test_t *t, const char *fmt, ...); -void ts_test_log (ts_test_t *t, const char *fmt, ...); - -/* test suite short-cut macros */ -#define TS_TEST(name) \ - static void name(ts_test_t *_t) -#define TS_CTX \ - ts_test_ctx(_t, __FILE__, __LINE__) - -#endif /* _TS_H_ */ - diff --git a/src/Makefile.am b/src/Makefile.am index 09ca7f59a8..ddf0471ea9 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -114,7 +114,7 @@ COMMON_SRC=\ xbt/set.c \ xbt/module.c \ xbt/config.c \ - xbt/testsuite.c \ + xbt/cunit.c \ \ gras/gras.c \ \ diff --git a/src/xbt/cunit.c b/src/xbt/cunit.c new file mode 100644 index 0000000000..0f8b6256b5 --- /dev/null +++ b/src/xbt/cunit.c @@ -0,0 +1,511 @@ +/* $Id$ */ + +/* cunit - A little C Unit facility */ + +/* Copyright (c) 2005 Martin Quinson. All rights reserved. */ + +/* This program is free software; you can redistribute it and/or modify it + * under the terms of the license (GNU LGPL) which comes with this package. */ + +/* This is partially inspirated from the OSSP ts (Test Suite Library) */ + +#include "gras_config.h" + +#include "xbt/sysdep.h" /* vasprintf */ +#include "xbt/cunit.h" +#include "xbt/dynar.h" + +XBT_LOG_NEW_DEFAULT_SUBCATEGORY(testsuite,xbt,"Test infrastructure"); + +/* collection of all suites */ +static xbt_dynar_t _xbt_test_suites = NULL; +/* global statistics */ +static int _xbt_test_nb_tests = 0; +static int _xbt_test_test_failed = 0; +static int _xbt_test_test_ignore = 0; +static int _xbt_test_test_expect = 0; + +static int _xbt_test_nb_units = 0; +static int _xbt_test_unit_failed = 0; +static int _xbt_test_unit_ignore = 0; + +static int _xbt_test_nb_suites = 0; +static int _xbt_test_suite_failed = 0; +static int _xbt_test_suite_ignore = 0; + + +/* test suite test log */ +typedef struct s_xbt_test_log { + char *text; + const char *file; + int line; +} *xbt_test_log_t; + +static void xbt_test_log_dump(xbt_test_log_t log) { + if (log) + fprintf(stderr," log %p(%s:%d)=%s\n",log,log->file,log->line,log->text); + else + fprintf(stderr," log=NULL\n"); +} +static void xbt_test_log_free(xbt_test_log_t log) { + if (!log) + return; + if (log->text) + free(log->text); + free(log); +} + +/* test suite test check */ +typedef struct s_xbt_test_test { + char *title; + int failed; + int expected_failure; + int ignored; + const char *file; + int line; + xbt_dynar_t logs; +} *xbt_test_test_t; + +static void xbt_test_test_dump(xbt_test_test_t test){ + if (test) { + xbt_test_log_t log; + int it_log; + fprintf(stderr," test %p(%s:%d)=%s (%s)\n", + test,test->file,test->line,test->title, + test->failed?"failed":"not failed"); + xbt_dynar_foreach(test->logs,it_log,log) + xbt_test_log_dump(log); + } + else + fprintf(stderr," test=NULL\n"); +} + +/* test suite test unit */ +struct s_xbt_test_unit { + char *title; + ts_test_cb_t func; + const char *file; + int line; + xbt_dynar_t tests; /* of xbt_test_test_t*/ + + int nb_tests; + int test_failed,test_ignore,test_expect; +}; + +static void xbt_test_unit_dump(xbt_test_unit_t unit) { + if (unit) { + xbt_test_test_t test; + int it_test; + fprintf(stderr," unit %p(%s:%d)=%s (func=%p)\n", + unit,unit->file,unit->line,unit->title,unit->file); + xbt_dynar_foreach(unit->tests,it_test,test) + xbt_test_test_dump(test); + } else { + fprintf(stderr," unit=NULL\n"); + } +} + +/* test suite */ +struct s_xbt_test_suite { + char *title; + xbt_dynar_t units; /* of xbt_test_unit_t */ + + int nb_tests,nb_units; + int test_failed,test_ignore,test_expect; + int unit_failed,unit_ignore; +}; + +/* destroy test suite */ +static void xbt_test_suite_free(void *s) { + xbt_test_suite_t suite = *(xbt_test_suite_t*) s; + + if (suite == NULL) + return; + xbt_dynar_free(&suite->units); + free(suite->title); + free(suite); +} + +/** @brief create test suite */ +xbt_test_suite_t xbt_test_suite_new(const char *fmt, ...) { + xbt_test_suite_t suite = xbt_new0(struct s_xbt_test_suite,1); + va_list ap; + + if (!_xbt_test_suites) + _xbt_test_suites = xbt_dynar_new(sizeof(xbt_test_suite_t),&xbt_test_suite_free); + + va_start(ap, fmt); + vasprintf(&suite->title,fmt, ap); + suite->units = xbt_dynar_new(sizeof(xbt_test_unit_t), NULL); + va_end(ap); + + xbt_dynar_push(_xbt_test_suites,&suite); + + return suite; +} + +void xbt_test_suite_dump(xbt_test_suite_t suite) { + if (suite) { + xbt_test_unit_t unit; + int it_unit; + fprintf(stderr,"DUMP suite %s\n",suite->title); + xbt_dynar_foreach(suite->units,it_unit,unit) + xbt_test_unit_dump(unit); + } else { + fprintf(stderr,"suite=NULL\n"); + } +} + +/* add test case to test suite */ +void xbt_test_suite_push(xbt_test_suite_t suite, ts_test_cb_t func, const char *fmt, ...) { + xbt_test_unit_t unit; + va_list ap; + + xbt_assert(suite); + xbt_assert(func); + xbt_assert(fmt); + + unit = xbt_new(struct s_xbt_test_unit,1); + va_start(ap, fmt); + vasprintf(&unit->title, fmt, ap); + va_end(ap); + unit->func = func; + unit->file = NULL; + unit->line = 0; + unit->tests = xbt_dynar_new(sizeof(xbt_test_test_t), NULL); + + xbt_dynar_push(suite->units, &unit); + return; +} + +/* run test one suite */ +static int xbt_test_suite_run(xbt_test_suite_t suite) { + xbt_test_unit_t unit; + xbt_test_test_t test; + xbt_test_log_t log; + + const char *file; + int line; + char *cp; + int it_unit,it_test,it_log; + + if (suite == NULL) + return 0; + + /* iterate through all tests to see how much failed */ + xbt_dynar_foreach(suite->units, it_unit, unit) { + /* init unit case counters */ + unit->nb_tests = 0; + unit->test_ignore = 0; + unit->test_failed = 0; + unit->test_expect = 0; + + /* run the test case function */ + unit->func(unit); + + /* iterate through all performed tests to determine status */ + xbt_dynar_foreach(unit->tests,it_test, test) { + if (test->ignored) { + unit->test_ignore++; + } else { + unit->nb_tests++; + + if ( test->failed && !test->expected_failure) unit->test_failed++; + if (!test->failed && test->expected_failure) unit->test_failed++; + if (test->expected_failure) + unit->test_expect++; + } + } + + /* Accumulate test counts into the suite */ + suite->nb_tests += unit->nb_tests; + suite->test_failed += unit->test_failed; + suite->test_ignore += unit->test_ignore; + suite->test_expect += unit->test_expect; + + _xbt_test_nb_tests += unit->nb_tests; + _xbt_test_test_failed += unit->test_failed; + _xbt_test_test_ignore += unit->test_ignore; + _xbt_test_test_expect += unit->test_expect; + + /* What's the conclusion of this test anyway? */ + if (unit->nb_tests) { + suite->nb_units++; + if (unit->test_failed) + suite->unit_failed++; + } else { + suite->unit_ignore++; + } + } + _xbt_test_nb_units += suite->nb_units; + _xbt_test_unit_failed += suite->unit_failed; + _xbt_test_unit_ignore += suite->unit_ignore; + + if (suite->nb_units) { + _xbt_test_nb_suites++; + if (suite->test_failed) + _xbt_test_suite_failed++; + } else { + _xbt_test_suite_ignore++; + } + + /* suite title pretty-printing */ + { + char suite_title[80]; + int suite_len=strlen(suite->title); + int i; + + xbt_assert2(suite_len<70,"suite title \"%s\" too long (%d should be less than 70", + suite->title,suite_len); + + suite_title[0]=' '; + for (i=1;i<79;i++) + suite_title[i]='='; + suite_title[i]='\0'; + + sprintf(suite_title + 40 - (suite_len+4)/2, "[ %s ]", suite->title); + suite_title[40 + (suite_len+4)/2] = '='; + + fprintf(stderr, "\n%s %s\n",suite_title, + (suite->nb_units?(suite->unit_failed?"FAILED":"OK"):"SKIP")); + + } + + /* iterate through all test cases to display details */ + xbt_dynar_foreach(suite->units, it_unit, unit) { + asprintf(&cp," Unit: %s ........................................" + "........................................", unit->title); + cp[72] = '\0'; + fprintf(stderr, "%s", cp); + free(cp); + + if (unit->test_failed > 0 || unit->test_expect) { + /* some tests failed (or were supposed to), so do detailed reporting of test case */ + if (unit->test_failed > 0) { + fprintf(stderr, " failed\n"); + } else if (unit->nb_tests) { + fprintf(stderr, ".... ok\n"); /* successful, but show about expected */ + } else { + fprintf(stderr, ".. skip\n"); /* shouldn't happen, but I'm a bit lost with this logic */ + } + xbt_dynar_foreach(unit->tests,it_test, test) { + file = (test->file != NULL ? test->file : unit->file); + line = (test->line != 0 ? test->line : unit->line); + fprintf(stderr, " %s: %s [%s:%d]\n", + (test->ignored?" SKIP":(test->expected_failure?(test->failed?"EFAIL":"EPASS"): + (test->failed?" FAIL":" PASS"))), + test->title, file, line); + + xbt_dynar_foreach(test->logs,it_log,log) { + file = (log->file != NULL ? log->file : file); + line = (log->line != 0 ? log->line : line); + fprintf(stderr, " %s:%d: %s\n", + file, line,log->text); + + } + } + fprintf(stderr, " Summary: %d of %d tests failed",unit->test_failed, unit->nb_tests); + if (unit->test_ignore) { + fprintf(stderr," (%d tests ignored)\n",unit->test_ignore); + } else { + fprintf(stderr,"\n"); + } + } else if (unit->nb_tests) { + fprintf(stderr, ".... ok\n"); /* successful */ + } else { + fprintf(stderr, ".. skip\n"); /* no test were run */ + } + } + + /* print test suite summary */ + fprintf(stderr, " ==============================================================================\n"); + fprintf(stderr, " Summary: Units: %.0f%% ok (%d units: ", + suite->nb_units?((1-(double)suite->unit_failed/(double)suite->nb_units)*100.0):100.0, + suite->nb_units); + int first=1; + if (suite->nb_units != suite->unit_failed) { + fprintf(stderr, "%s%d ok",(first?"":", "),suite->nb_units - suite->unit_failed); + first = 0; + } + if (suite->unit_failed) { + fprintf(stderr, "%s%d failed",(first?"":", "),suite->unit_failed); + first = 0; + } + if (suite->unit_ignore) { + fprintf(stderr, "%s%d ignored",(first?"":", "),suite->unit_ignore); + first = 0; + } + fprintf(stderr,")\n Tests: %.0f%% ok (%d tests: ", + suite->nb_tests?((1-(double)suite->test_failed/(double)suite->nb_tests)*100.0):100.0, + suite->nb_tests); + + first=1; + if (suite->nb_tests != suite->test_failed) { + fprintf(stderr, "%s%d ok",(first?"":", "),suite->nb_tests - suite->test_failed); + first = 0; + } + if (suite->test_failed) { + fprintf(stderr, "%s%d failed",(first?"":", "),suite->test_failed); + first = 0; + } + if (suite->test_ignore) { + fprintf(stderr, "%s%d ignored",(first?"":"; "),suite->test_ignore); + first = 0; + } + if (suite->test_expect) { + fprintf(stderr, "%s%d expected to fail",(first?"":"; "),suite->test_expect); + first = 0; + } + fprintf(stderr,")\n"); + + return suite->unit_failed; +} + +int xbt_test_run(void) { + + if (_xbt_test_suites) { + int it_suite; + xbt_test_suite_t suite; + int first=1; + + /* Run all the suites */ + xbt_dynar_foreach(_xbt_test_suites,it_suite,suite) + xbt_test_suite_run(suite); + + /* Display some more statistics */ + fprintf(stderr,"\n\n TOTAL: Suites: %.0f%% ok (%d suites: ", + _xbt_test_nb_suites + ? ((1-(double)_xbt_test_suite_failed/(double)_xbt_test_nb_suites)*100.0) + : 100.0, + _xbt_test_nb_suites); + if (_xbt_test_nb_suites != _xbt_test_suite_failed) { + fprintf(stderr, "%d ok",_xbt_test_nb_suites - _xbt_test_suite_failed); + first = 0; + } + if (_xbt_test_suite_failed) { + fprintf(stderr, "%s%d failed",(first?"":", "),_xbt_test_suite_failed); + first = 0; + } + + if (_xbt_test_suite_ignore) { + fprintf(stderr, "%s%d ignored",(first?"":", "),_xbt_test_suite_ignore); + first = 0; + } + fprintf(stderr,")\n Units: %.0f%% ok (%d units: ", + _xbt_test_nb_units?((1-(double)_xbt_test_unit_failed/(double)_xbt_test_nb_units)*100.0):100.0, + _xbt_test_nb_units); + first=1; + if (_xbt_test_nb_units != _xbt_test_unit_failed) { + fprintf(stderr, "%s%d ok",(first?"":", "),_xbt_test_nb_units - _xbt_test_unit_failed); + first = 0; + } + if (_xbt_test_unit_failed) { + fprintf(stderr, "%s%d failed",(first?"":", "),_xbt_test_unit_failed); + first = 0; + } + if (_xbt_test_unit_ignore) { + fprintf(stderr, "%s%d ignored",(first?"":", "),_xbt_test_unit_ignore); + first = 0; + } + fprintf(stderr,")\n Tests: %.0f%% ok (%d tests: ", + _xbt_test_nb_tests?((1-(double)_xbt_test_test_failed/(double)_xbt_test_nb_tests)*100.0):100.0, + _xbt_test_nb_tests); + first=1; + if (_xbt_test_nb_tests != _xbt_test_test_failed) { + fprintf(stderr, "%s%d ok",(first?"":", "),_xbt_test_nb_tests - _xbt_test_test_failed); + first = 0; + } + if (_xbt_test_test_failed) { + fprintf(stderr, "%s%d failed",(first?"":", "),_xbt_test_test_failed); + first = 0; + } + if (_xbt_test_test_ignore) { + fprintf(stderr, "%s%d ignored",(first?"":", "),_xbt_test_test_ignore); + first = 0; + } + if (_xbt_test_test_expect) { + fprintf(stderr, "%s%d expected to fail",(first?"":", "),_xbt_test_test_expect); + } + + fprintf(stderr,")\n"); + } else { + fprintf(stderr,"No unit to run!\n"); + _xbt_test_unit_failed++; + } + return _xbt_test_unit_failed; +} + + +/* annotate test case with test */ +void _xbt_test(xbt_test_unit_t unit, const char*file,int line, const char *fmt, ...) { + xbt_test_test_t test; + va_list ap; + + xbt_assert(unit); + xbt_assert(fmt); + + test = xbt_new(struct s_xbt_test_test,1); + va_start(ap, fmt); + vasprintf(&test->title, fmt, ap); + va_end(ap); + test->failed = 0; + test->expected_failure = 0; + test->ignored = 0; + test->file = file; + test->line = line; + test->logs = xbt_dynar_new(sizeof(xbt_test_log_t),NULL); + xbt_dynar_push(unit->tests,&test); + return; +} + +/* annotate test case with log message and failure */ +void _xbt_test_fail(xbt_test_unit_t unit, const char*file,int line,const char *fmt, ...) { + xbt_test_test_t test; + xbt_test_log_t log; + va_list ap; + + xbt_assert(unit); + xbt_assert(fmt); + + log = xbt_new(struct s_xbt_test_log,1); + va_start(ap, fmt); + vasprintf(&log->text,fmt, ap); + va_end(ap); + log->file = file; + log->line = line; + + test = xbt_dynar_getlast_as(unit->tests, xbt_test_test_t); + xbt_dynar_push(test->logs, &log); + + test->failed = 1; +} + +void _xbt_test_expect_failure(xbt_test_unit_t unit) { + xbt_test_test_t test = xbt_dynar_getlast_as(unit->tests,xbt_test_test_t); + test->expected_failure = 1; +} +void _xbt_test_skip(xbt_test_unit_t unit) { + xbt_test_test_t test = xbt_dynar_getlast_as(unit->tests,xbt_test_test_t); + test->ignored = 1; +} + +/* annotate test case with log message only */ +void _xbt_test_log(xbt_test_unit_t unit, const char*file,int line,const char *fmt, ...) { + xbt_test_test_t test; + xbt_test_log_t log; + va_list ap; + + xbt_assert(unit); + xbt_assert(fmt); + + log = xbt_new(struct s_xbt_test_log,1); + va_start(ap, fmt); + vasprintf(&log->text, fmt, ap); + va_end(ap); + log->file = file; + log->line = line; + + test = xbt_dynar_getlast_as(unit->tests,xbt_test_test_t); + xbt_dynar_push(test->logs, &log); +} + diff --git a/src/xbt/testsuite.c b/src/xbt/testsuite.c deleted file mode 100644 index bc872ba9dd..0000000000 --- a/src/xbt/testsuite.c +++ /dev/null @@ -1,468 +0,0 @@ -/* -** OSSP ts - Test Suite Library -** Copyright (c) 2001-2004 Ralf S. Engelschall -** Copyright (c) 2001-2004 The OSSP Project -** Copyright (c) 2001-2004 Cable & Wireless -** -** This file is part of OSSP ts, a small test suite library which -** can be found at http://www.ossp.org/pkg/lib/ts/. -** -** Permission to use, copy, modify, and distribute this software for -** any purpose with or without fee is hereby granted, provided that -** the above copyright notice and this permission notice appear in all -** copies. -** -** THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED -** WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -** IN NO EVENT SHALL THE AUTHORS AND COPYRIGHT HOLDERS AND THEIR -** CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF -** USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -** ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -** OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT -** OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -** SUCH DAMAGE. -** -** ts.c: test suite library -*/ - -#include -#include -#include -#include -#include "gras_config.h" - -#include "xbt/testsuite.h" - -/* embedded ring data structure library */ -#define RING_ENTRY(elem) \ - struct { elem *next; elem *prev; } -#define RING_HEAD(elem) \ - struct { elem *next; elem *prev; } -#define RING_SENTINEL(hp, elem, link) \ - (elem *)((char *)(hp) - ((size_t)(&((elem *)0)->link))) -#define RING_FIRST(hp) \ - (hp)->next -#define RING_LAST(hp) \ - (hp)->prev -#define RING_NEXT(ep, link) \ - (ep)->link.next -#define RING_PREV(ep, link) \ - (ep)->link.prev -#define RING_INIT(hp, elem, link) \ - do { RING_FIRST((hp)) = RING_SENTINEL((hp), elem, link); \ - RING_LAST((hp)) = RING_SENTINEL((hp), elem, link); } while (0) -#define RING_EMPTY(hp, elem, link) \ - (RING_FIRST((hp)) == RING_SENTINEL((hp), elem, link)) -#define RING_ELEM_INIT(ep, link) \ - do { RING_NEXT((ep), link) = (ep); \ - RING_PREV((ep), link) = (ep); } while (0) -#define RING_SPLICE_BEFORE(lep, ep1, epN, link) \ - do { RING_NEXT((epN), link) = (lep); \ - RING_PREV((ep1), link) = RING_PREV((lep), link); \ - RING_NEXT(RING_PREV((lep), link), link) = (ep1); \ - RING_PREV((lep), link) = (epN); } while (0) -#define RING_SPLICE_TAIL(hp, ep1, epN, elem, link) \ - RING_SPLICE_BEFORE(RING_SENTINEL((hp), elem, link), (ep1), (epN), link) -#define RING_INSERT_TAIL(hp, nep, elem, link) \ - RING_SPLICE_TAIL((hp), (nep), (nep), elem, link) -#define RING_FOREACH(ep, hp, elem, link) \ - for ((ep) = RING_FIRST((hp)); \ - (ep) != RING_SENTINEL((hp), elem, link); \ - (ep) = RING_NEXT((ep), link)) -#define RING_FOREACH_LA(ep, epT, hp, elem, link) \ - for ((ep) = RING_FIRST((hp)), (epT) = RING_NEXT((ep), link); \ - (ep) != RING_SENTINEL((hp), elem, link); \ - (ep) = (epT), (epT) = RING_NEXT((epT), link)) - -/* test suite test log */ -struct tstl_st; -typedef struct tstl_st tstl_t; -struct tstl_st { - RING_ENTRY(tstl_t) next; - char *text; - const char *file; - int line; -}; - -/* test suite test check */ -struct tstc_st; -typedef struct tstc_st tstc_t; -struct tstc_st { - RING_ENTRY(tstc_t) next; - char *title; - int failed; - const char *file; - int line; - RING_HEAD(tstl_t) logs; -}; - -/* test suite test */ -struct ts_test_st { - RING_ENTRY(ts_test_t) next; - char *title; - ts_test_cb_t func; - const char *file; - int line; - RING_HEAD(tstc_t) checks; -}; - -/* test suite */ -struct ts_suite_st { - char *title; - RING_HEAD(ts_test_t) tests; -}; - -/* minimal output-independent vprintf(3) variant which supports %{c,s,d,%} only */ -static int ts_suite_mvxprintf(char *buffer, size_t bufsize, const char *format, va_list ap) -{ - /* sufficient integer buffer: x log_10(2) + safety */ - char ibuf[((sizeof(int)*8)/3)+10]; - char *cp; - char c; - int d; - int n; - int bytes; - - if (format == NULL) - return -1; - bytes = 0; - while (*format != '\0') { - if (*format == '%') { - c = *(format+1); - if (c == '%') { - /* expand "%%" */ - cp = &c; - n = sizeof(char); - } - else if (c == 'c') { - /* expand "%c" */ - c = (char)va_arg(ap, int); - cp = &c; - n = sizeof(char); - } - else if (c == 's') { - /* expand "%s" */ - if ((cp = (char *)va_arg(ap, char *)) == NULL) - cp = (char*)"(null)"; - n = strlen(cp); - } - else if (c == 'd') { - /* expand "%d" */ - d = (int)va_arg(ap, int); -#ifdef HAVE_SNPRINTF - snprintf(ibuf, sizeof(ibuf), "%d", d); /* explicitly secure */ -#else - sprintf(ibuf, "%d", d); /* implicitly secure */ -#endif - cp = ibuf; - n = strlen(cp); - } - else { - /* any other "%X" */ - cp = (char *)format; - n = 2; - } - format += 2; - } - else { - /* plain text */ - cp = (char *)format; - if ((format = strchr(cp, '%')) == NULL) - format = strchr(cp, '\0'); - n = format - cp; - } - /* perform output operation */ - if (buffer != NULL) { - if (n > bufsize) - return -1; - memcpy(buffer, cp, n); - buffer += n; - bufsize -= n; - } - bytes += n; - } - /* nul-terminate output */ - if (buffer != NULL) { - if (bufsize == 0) - return -1; - *buffer = '\0'; - } - return bytes; -} - -/* minimal vasprintf(3) variant which supports %{c,s,d} only */ -static char *ts_suite_mvasprintf(const char *format, va_list ap) -{ - char *buffer; - int n; - va_list ap2; - - if (format == NULL) - return NULL; - va_copy(ap2, ap); - if ((n = ts_suite_mvxprintf(NULL, 0, format, ap)) == -1) - return NULL; - if ((buffer = (char *)malloc(n+1)) == NULL) - return NULL; - ts_suite_mvxprintf(buffer, n+1, format, ap2); - return buffer; -} - -/* minimal asprintf(3) variant which supports %{c,s,d} only */ -static char *ts_suite_masprintf(const char *format, ...) -{ - va_list ap; - char *cp; - - va_start(ap, format); - cp = ts_suite_mvasprintf(format, ap); - va_end(ap); - return cp; -} - -/* create test suite */ -ts_suite_t *ts_suite_new(const char *fmt, ...) -{ - ts_suite_t *ts; - va_list ap; - - if ((ts = (ts_suite_t *)malloc(sizeof(ts_suite_t))) == NULL) - return NULL; - va_start(ap, fmt); - ts->title = ts_suite_mvasprintf(fmt, ap); - RING_INIT(&ts->tests, ts_test_t, next); - va_end(ap); - return ts; -} - -/* add test case to test suite */ -void ts_suite_test(ts_suite_t *ts, ts_test_cb_t func, const char *fmt, ...) -{ - ts_test_t *tst; - va_list ap; - - if (ts == NULL || func == NULL || fmt == NULL) - return; - if ((tst = (ts_test_t *)malloc(sizeof(ts_test_t))) == NULL) - return; - RING_ELEM_INIT(tst, next); - va_start(ap, fmt); - tst->title = ts_suite_mvasprintf(fmt, ap); - va_end(ap); - tst->func = func; - tst->file = NULL; - tst->line = 0; - RING_INIT(&tst->checks, tstc_t, next); - RING_INSERT_TAIL(&ts->tests, tst, ts_test_t, next); - return; -} - -/* run test suite */ -int ts_suite_run(ts_suite_t *ts) -{ - ts_test_t *tst; - tstc_t *tstc; - tstl_t *tstl; - int total_tests, total_tests_suite_failed; - int total_checks, total_checks_failed; - int test_checks, test_checks_failed; - const char *file; - int line; - char *cp; - - if (ts == NULL) - return 0; - - /* init total counters */ - total_tests = 0; - total_tests_suite_failed = 0; - total_checks = 0; - total_checks_failed = 0; - - fprintf(stdout, "\n"); - fprintf(stdout, " Test Suite: %s\n", ts->title); - fprintf(stdout, " __________________________________________________________________\n"); - fprintf(stdout, "\n"); - fflush(stdout); - - /* iterate through all test cases */ - RING_FOREACH(tst, &ts->tests, ts_test_t, next) { - cp = ts_suite_masprintf(" Test: %s ........................................" - "........................................", tst->title); - cp[60] = '\0'; - fprintf(stdout, "%s", cp); - free(cp); - fflush(stdout); - - /* init test case counters */ - test_checks = 0; - test_checks_failed = 0; - - /* run the test case function */ - tst->func(tst); - - /* iterate through all performed checks to determine status */ - RING_FOREACH(tstc, &tst->checks, tstc_t, next) { - test_checks++; - if (tstc->failed) - test_checks_failed++; - } - - if (test_checks_failed > 0) { - /* some checks failed, so do detailed reporting of test case */ - fprintf(stdout, " FAILED\n"); - fprintf(stdout, " Ops, %d/%d checks failed! Detailed report follows:\n", - test_checks_failed, test_checks); - RING_FOREACH(tstc, &tst->checks, tstc_t, next) { - file = (tstc->file != NULL ? tstc->file : tst->file); - line = (tstc->line != 0 ? tstc->line : tst->line); - if (file != NULL) - fprintf(stdout, " Check: %s [%s:%d]\n", tstc->title, file, line); - else - fprintf(stdout, " Check: %s\n", tstc->title); - RING_FOREACH(tstl, &tstc->logs, tstl_t, next) { - file = (tstl->file != NULL ? tstl->file : file); - line = (tstl->line != 0 ? tstl->line : line); - if (file != NULL) - fprintf(stdout, " Log: %s [%s:%d]\n", tstl->text, file, line); - else - fprintf(stdout, " Log: %s\n", tstl->text); - } - } - } - else { - /* test case ran successfully */ - fprintf(stdout, ".... OK\n"); - } - fflush(stdout); - - /* accumulate counters */ - total_checks += test_checks; - total_tests++; - if (test_checks_failed > 0) { - total_checks_failed += test_checks_failed; - total_tests_suite_failed++; - } - } - - /* print test suite summary */ - fprintf(stdout, " __________________________________________________________________\n"); - fprintf(stdout, "\n"); - fprintf(stdout, " Test Summary: %d tests (%d ok, %d failed), %d checks (%d ok, %d failed)\n", - total_tests, (total_tests - total_tests_suite_failed), total_tests_suite_failed, - total_checks, (total_checks - total_checks_failed), total_checks_failed); - if (total_tests_suite_failed > 0) - fprintf(stdout, " Test Suite: FAILED\n"); - else - fprintf(stdout, " Test Suite: OK\n"); - fprintf(stdout, "\n"); - fflush(stdout); - - return total_checks_failed; -} - -/* destroy test suite */ -void ts_suite_free(ts_suite_t *ts) -{ - ts_test_t *tst, *tstT; - tstc_t *tstc, *tstcT; - tstl_t *tstl, *tstlT; - - if (ts == NULL) - return; - RING_FOREACH_LA(tst, tstT, &ts->tests, ts_test_t, next) { - RING_FOREACH_LA(tstc, tstcT, &tst->checks, tstc_t, next) { - RING_FOREACH_LA(tstl, tstlT, &tstc->logs, tstl_t, next) { - free(tstl->text); - } - free(tstc->title); - free(tstc); - } - free(tst->title); - free(tst); - } - free(ts->title); - free(ts); - return; -} - -/* annotate test case with file name and line number */ -ts_test_t *ts_test_ctx(ts_test_t *tst, const char *file, int line) -{ - if (tst != NULL && file != NULL) { - tst->file = file; - tst->line = line; - } - return tst; -} - -/* annotate test case with check */ -void ts_test_check(ts_test_t *tst, const char *fmt, ...) -{ - tstc_t *tstc; - va_list ap; - - if (tst == NULL || fmt == NULL) - return; - if ((tstc = (tstc_t *)malloc(sizeof(tstc_t))) == NULL) - return; - va_start(ap, fmt); - RING_ELEM_INIT(tstc, next); - tstc->title = ts_suite_mvasprintf(fmt, ap); - tstc->failed = 0; - tstc->file = tst->file; - tstc->line = tst->line; - RING_INIT(&tstc->logs, tstl_t, next); - RING_INSERT_TAIL(&tst->checks, tstc, tstc_t, next); - va_end(ap); - return; -} - -/* annotate test case with log message and failure */ -void ts_test_fail(ts_test_t *tst, const char *fmt, ...) -{ - tstc_t *tstc; - tstl_t *tstl; - va_list ap; - - if (tst == NULL || fmt == NULL) - return; - if ((tstl = (tstl_t *)malloc(sizeof(tstl_t))) == NULL) - return; - va_start(ap, fmt); - tstl->text = ts_suite_mvasprintf(fmt, ap); - tstl->file = tst->file; - tstl->line = tst->line; - RING_ELEM_INIT(tstl, next); - tstc = RING_LAST(&tst->checks); - RING_INSERT_TAIL(&tstc->logs, tstl, tstl_t, next); - tstc->failed = 1; - va_end(ap); - return; -} - -/* annotate test case with log message only */ -void ts_test_log(ts_test_t *tst, const char *fmt, ...) -{ - tstc_t *tstc; - tstl_t *tstl; - va_list ap; - - if (tst == NULL || fmt == NULL) - return; - if ((tstl = (tstl_t *)malloc(sizeof(tstl_t))) == NULL) - return; - va_start(ap, fmt); - tstl->text = ts_suite_mvasprintf(fmt, ap); - tstl->file = tst->file; - tstl->line = tst->line; - RING_ELEM_INIT(tstl, next); - tstc = RING_LAST(&tst->checks); - RING_INSERT_TAIL(&tstc->logs, tstl, tstl_t, next); - va_end(ap); - return; -} - diff --git a/testsuite/xbt/ex_test.c b/testsuite/xbt/ex_test.c index 5bb4c92d66..21dbd8973a 100644 --- a/testsuite/xbt/ex_test.c +++ b/testsuite/xbt/ex_test.c @@ -33,66 +33,73 @@ #include #include -#include "xbt/testsuite.h" +#include "xbt/cunit.h" #include "xbt/ex.h" #include "xbt/log.h" XBT_LOG_NEW_CATEGORY(test,"This test"); -TS_TEST(test_controlflow) -{ +XBT_TEST_UNIT(test_expected_failure) { + xbt_test0("Skipped test"); + xbt_test_skip(); + + xbt_test0("EXPECTED FAILURE"); + xbt_test_expect_failure(); + xbt_test_log2("%s %s","Test","log"); + xbt_test_fail0("EXPECTED FAILURE"); +} + +XBT_TEST_UNIT(test_controlflow) { xbt_ex_t ex; - volatile int n; + volatile int n=1; + + xbt_test0("basic nested control flow"); - ts_test_check(TS_CTX, "basic nested control flow"); - n = 1; TRY { if (n != 1) - ts_test_fail(TS_CTX, "M1: n=%d (!= 1)", n); + xbt_test_fail1("M1: n=%d (!= 1)", n); n++; TRY { if (n != 2) - ts_test_fail(TS_CTX, "M2: n=%d (!= 2)", n); + xbt_test_fail1("M2: n=%d (!= 2)", n); n++; THROW0(unknown_error,0,"something"); } CATCH (ex) { if (n != 3) - ts_test_fail(TS_CTX, "M3: n=%d (!= 1)", n); + xbt_test_fail1("M3: n=%d (!= 1)", n); n++; RETHROW; } - ts_test_fail(TS_CTX, "MX: n=%d (expected: not reached)", n); + xbt_test_fail1("MX: n=%d (shouldn't reach this point)", n); } CATCH(ex) { if (n != 4) - ts_test_fail(TS_CTX, "M4: n=%d (!= 4)", n); + xbt_test_fail1("M4: n=%d (!= 4)", n); n++; xbt_ex_free(ex); } if (n != 5) - ts_test_fail(TS_CTX, "M5: n=%d (!= 5)", n); + xbt_test_fail1("M5: n=%d (!= 5)", n); } -TS_TEST(test_value) -{ +XBT_TEST_UNIT(test_value) { xbt_ex_t ex; TRY { THROW0(unknown_error, 2, "toto"); } CATCH(ex) { - ts_test_check(TS_CTX, "exception value passing"); + xbt_test0("exception value passing"); if (ex.category != unknown_error) - ts_test_fail(TS_CTX, "category=%d (!= 1)", ex.category); + xbt_test_fail1("category=%d (!= 1)", ex.category); if (ex.value != 2) - ts_test_fail(TS_CTX, "value=%d (!= 2)", ex.value); + xbt_test_fail1("value=%d (!= 2)", ex.value); if (strcmp(ex.msg,"toto")) - ts_test_fail(TS_CTX, "message=%s (!= toto)", ex.msg); + xbt_test_fail1("message=%s (!= toto)", ex.msg); xbt_ex_free(ex); } } -TS_TEST(test_variables) -{ +XBT_TEST_UNIT(test_variables) { xbt_ex_t ex; int r1, r2; volatile int v1, v2; @@ -103,25 +110,24 @@ TS_TEST(test_variables) v2 = 5678; THROW0(unknown_error, 0, "toto"); } CATCH(ex) { - ts_test_check(TS_CTX, "variable preservation"); + xbt_test0("variable preservation"); if (r1 != 1234) - ts_test_fail(TS_CTX, "r1=%d (!= 1234)", r1); + xbt_test_fail1("r1=%d (!= 1234)", r1); if (v1 != 1234) - ts_test_fail(TS_CTX, "v1=%d (!= 1234)", v1); + xbt_test_fail1("v1=%d (!= 1234)", v1); /* r2 is allowed to be destroyed because not volatile */ if (v2 != 5678) - ts_test_fail(TS_CTX, "v2=%d (!= 5678)", v2); + xbt_test_fail1("v2=%d (!= 5678)", v2); xbt_ex_free(ex); } } -TS_TEST(test_cleanup) -{ +XBT_TEST_UNIT(test_cleanup) { xbt_ex_t ex; volatile int v1; int c; - ts_test_check(TS_CTX, "cleanup handling"); + xbt_test0("cleanup handling"); v1 = 1234; c = 0; @@ -130,32 +136,32 @@ TS_TEST(test_cleanup) THROW0(1, 2, "blah"); } CLEANUP { if (v1 != 5678) - ts_test_fail(TS_CTX, "v1 = %d (!= 5678)", v1); + xbt_test_fail1("v1 = %d (!= 5678)", v1); c = 1; } CATCH(ex) { if (v1 != 5678) - ts_test_fail(TS_CTX, "v1 = %d (!= 5678)", v1); + xbt_test_fail1("v1 = %d (!= 5678)", v1); if (!(ex.category == 1 && ex.value == 2 && !strcmp(ex.msg,"blah"))) - ts_test_fail(TS_CTX, "unexpected exception contents"); + xbt_test_fail0("unexpected exception contents"); xbt_ex_free(ex); } if (!c) - ts_test_fail(TS_CTX, "ex_cleanup not executed"); + xbt_test_fail0("xbt_ex_free not executed"); } -int main(int argc, char *argv[]) -{ - ts_suite_t *ts; - int n; - - ts = ts_suite_new("OSSP ex (Exception Handling)"); - ts_suite_test(ts, test_controlflow, "basic nested control flow"); - ts_suite_test(ts, test_value, "exception value passing"); - ts_suite_test(ts, test_variables, "variable value preservation"); - ts_suite_test(ts, test_cleanup, "cleanup handling"); - n = ts_suite_run(ts); - ts_suite_free(ts); - return n; +int main(int argc, char *argv[]) { + xbt_test_suite_t suite; + + suite = xbt_test_suite_new("Testsuite Autotest"); + xbt_test_suite_push(suite, test_expected_failure, "expected failures"); + + suite = xbt_test_suite_new("Exception Handling"); + xbt_test_suite_push(suite, test_controlflow, "basic nested control flow"); + xbt_test_suite_push(suite, test_value, "exception value passing"); + xbt_test_suite_push(suite, test_variables, "variable value preservation"); + xbt_test_suite_push(suite, test_cleanup, "cleanup handling"); + + return xbt_test_run(); }