diff --git a/common/testing.h b/common/testing.h index 10403c33..6a20a0a7 100644 --- a/common/testing.h +++ b/common/testing.h @@ -29,12 +29,14 @@ extern "C" { #define testingprivMkScaffold(name) \ static inline void testingprivScaffold ## name(testingT *t) \ { \ - bool failedNow = false; \ + bool failedNow = false, skippedNow = false; \ try { name(t); } \ catch (testingprivFailNowException e) { failedNow = true; } \ + catch (testingprivSkipNowException e) { skippedNow = true; } \ /* TODO see if we should catch other exceptions too */ \ - /* don't call this in the catch block as it calls longjmp() */ \ + /* don't call these in the catch blocks as they call longjmp() */ \ if (failedNow) testingprivTDoFailNow(t); \ + if (skippedNow) testingprivTDoSkipNow(t); \ } #else #define testingprivMkScaffold(name) \ @@ -68,24 +70,34 @@ extern "C" { extern int testingMain(void); typedef struct testingT testingT; -#define testingTErrorf(t, ...) testingprivTErrorfFull(t, __FILE__, __LINE__, __VA_ARGS__) -#define testingTErrorvf(t, format, ap) testingprivTErrorvfFull(t, __FILE__, __LINE__, format, ap) +#define testingTLogf(t, ...) (testingprivTLogfFull(t, __FILE__, __LINE__, __VA_ARGS__)) +#define testingTLogvf(t, format, ap) (testingprivTLogvfFull(t, __FILE__, __LINE__, format, ap)) +#define testingTErrorf(t, ...) (testingprivTErrorfFull(t, __FILE__, __LINE__, __VA_ARGS__)) +#define testingTErrorvf(t, format, ap) (testingprivTErrorvfFull(t, __FILE__, __LINE__, format, ap)) +#define testingTFatalf(t, ...) ((testingprivTErrorfFull(t, __FILE__, __LINE__, __VA_ARGS__)), (testingTFailNow(t))) +#define testingTFatalvf(t, format, ap) ((testingprivTErrorvfFull(t, __FILE__, __LINE__, format, ap)), (testingTFailNow(t))) #ifdef __cplusplus #define testingTFailNow(t) (throw testingprivFailNowException()) +#define testingTSkipNow(t) (throw testingprivSkipNowException()) #else -#define testingTFailNow(t) testingprivTDoFailNow(t) +#define testingTFailNow(t) (testingprivTDoFailNow(t)) +#define testingTSkipNow(t) (testingprivTDoSkipNow(t)) #endif // TODO should __LINE__ arguments use intmax_t or uintmax_t instead of int? extern void testingprivRegisterTest(const char *, void (*)(testingT *)); +extern void testingprivTLogfFull(testingT *, const char *, int, const char *, ...); +extern void testingprivTLogvfFull(testingT *, const char *, int, const char *, va_list); extern void testingprivTErrorfFull(testingT *, const char *, int, const char *, ...); extern void testingprivTErrorvfFull(testingT *, const char *, int, const char *, va_list); extern void testingprivTDoFailNow(testingT *); +extern void testingprivTDoSkipNow(testingT *); #ifdef __cplusplus } namespace { class testingprivFailNowException {}; + class testingprivSkipNowException {}; class testingprivRegisterTestClass { public: testingprivRegisterTestClass(const char *name, void (*f)(testingT *)) { testingprivRegisterTest(name, f); } diff --git a/common/testing_testing.c b/common/testing_testing.c index 33e19bbe..24d22b0b 100644 --- a/common/testing_testing.c +++ b/common/testing_testing.c @@ -10,7 +10,8 @@ struct testingT { const char *name; void (*f)(testingT *); int failed; - jmp_buf failNowBuf; + int skipped; + jmp_buf returnNowBuf; testingT *next; }; @@ -34,6 +35,7 @@ int testingMain(void) int anyFailed; const char *status; + // TODO see if this should run if all tests are skipped if (tests == NULL) { fprintf(stderr, "warning: no tests to run\n"); // imitate Go here (TODO confirm this) @@ -43,13 +45,15 @@ int testingMain(void) anyFailed = 0; for (t = tests; t != NULL; t = t->next) { printf("=== RUN %s\n", t->name); - if (setjmp(t->failNowBuf) == 0) + if (setjmp(t->returnNowBuf) == 0) (*(t->f))(t); status = "PASS"; if (t->failed) { status = "FAIL"; anyFailed = 1; - } + } else if (t->skipped) + // note that failed overrides skipped + status = "SKIP"; printf("--- %s: %s (%s)\n", status, t->name, "TODO"); } @@ -61,7 +65,16 @@ int testingMain(void) return 0; } -static void testingprivTDoLog(testingT *t, const char *file, int line, const char *format, va_list ap) +void testingprivTLogfFull(testingT *t, const char *file, int line, const char *format, ...) +{ + va_list ap; + + va_start(ap, format); + testingprivTLogvfFull(t, file, line, format, ap); + va_end(ap); +} + +void testingprivTLogvfFull(testingT *t, const char *file, int line, const char *format, va_list ap) { // TODO extract filename from file printf("\t%s:%d: ", file, line); @@ -81,12 +94,18 @@ void testingprivTErrorfFull(testingT *t, const char *file, int line, const char void testingprivTErrorvfFull(testingT *t, const char *file, int line, const char *format, va_list ap) { - testingprivTDoLog(t, file, line, format, ap); + testingprivTLogvfFull(t, file, line, format, ap); t->failed = 1; } void testingprivTDoFailNow(testingT *t) { t->failed = 1; - longjmp(t->failNowBuf, 1); + longjmp(t->returnNowBuf, 1); +} + +void testingprivTDoSkipNow(testingT *t) +{ + t->skipped = 1; + longjmp(t->returnNowBuf, 1); }