Added skipping and fatal to testing.h.

This commit is contained in:
Pietro Gagliardi 2018-03-03 14:08:17 -05:00
parent d0db6f9594
commit b5570040b0
2 changed files with 42 additions and 11 deletions

View File

@ -29,12 +29,14 @@ extern "C" {
#define testingprivMkScaffold(name) \ #define testingprivMkScaffold(name) \
static inline void testingprivScaffold ## name(testingT *t) \ static inline void testingprivScaffold ## name(testingT *t) \
{ \ { \
bool failedNow = false; \ bool failedNow = false, skippedNow = false; \
try { name(t); } \ try { name(t); } \
catch (testingprivFailNowException e) { failedNow = true; } \ catch (testingprivFailNowException e) { failedNow = true; } \
catch (testingprivSkipNowException e) { skippedNow = true; } \
/* TODO see if we should catch other exceptions too */ \ /* 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 (failedNow) testingprivTDoFailNow(t); \
if (skippedNow) testingprivTDoSkipNow(t); \
} }
#else #else
#define testingprivMkScaffold(name) \ #define testingprivMkScaffold(name) \
@ -68,24 +70,34 @@ extern "C" {
extern int testingMain(void); extern int testingMain(void);
typedef struct testingT testingT; typedef struct testingT testingT;
#define testingTErrorf(t, ...) testingprivTErrorfFull(t, __FILE__, __LINE__, __VA_ARGS__) #define testingTLogf(t, ...) (testingprivTLogfFull(t, __FILE__, __LINE__, __VA_ARGS__))
#define testingTErrorvf(t, format, ap) testingprivTErrorvfFull(t, __FILE__, __LINE__, format, ap) #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 #ifdef __cplusplus
#define testingTFailNow(t) (throw testingprivFailNowException()) #define testingTFailNow(t) (throw testingprivFailNowException())
#define testingTSkipNow(t) (throw testingprivSkipNowException())
#else #else
#define testingTFailNow(t) testingprivTDoFailNow(t) #define testingTFailNow(t) (testingprivTDoFailNow(t))
#define testingTSkipNow(t) (testingprivTDoSkipNow(t))
#endif #endif
// TODO should __LINE__ arguments use intmax_t or uintmax_t instead of int? // TODO should __LINE__ arguments use intmax_t or uintmax_t instead of int?
extern void testingprivRegisterTest(const char *, void (*)(testingT *)); 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 testingprivTErrorfFull(testingT *, const char *, int, const char *, ...);
extern void testingprivTErrorvfFull(testingT *, const char *, int, const char *, va_list); extern void testingprivTErrorvfFull(testingT *, const char *, int, const char *, va_list);
extern void testingprivTDoFailNow(testingT *); extern void testingprivTDoFailNow(testingT *);
extern void testingprivTDoSkipNow(testingT *);
#ifdef __cplusplus #ifdef __cplusplus
} }
namespace { namespace {
class testingprivFailNowException {}; class testingprivFailNowException {};
class testingprivSkipNowException {};
class testingprivRegisterTestClass { class testingprivRegisterTestClass {
public: public:
testingprivRegisterTestClass(const char *name, void (*f)(testingT *)) { testingprivRegisterTest(name, f); } testingprivRegisterTestClass(const char *name, void (*f)(testingT *)) { testingprivRegisterTest(name, f); }

View File

@ -10,7 +10,8 @@ struct testingT {
const char *name; const char *name;
void (*f)(testingT *); void (*f)(testingT *);
int failed; int failed;
jmp_buf failNowBuf; int skipped;
jmp_buf returnNowBuf;
testingT *next; testingT *next;
}; };
@ -34,6 +35,7 @@ int testingMain(void)
int anyFailed; int anyFailed;
const char *status; const char *status;
// TODO see if this should run if all tests are skipped
if (tests == NULL) { if (tests == NULL) {
fprintf(stderr, "warning: no tests to run\n"); fprintf(stderr, "warning: no tests to run\n");
// imitate Go here (TODO confirm this) // imitate Go here (TODO confirm this)
@ -43,13 +45,15 @@ int testingMain(void)
anyFailed = 0; anyFailed = 0;
for (t = tests; t != NULL; t = t->next) { for (t = tests; t != NULL; t = t->next) {
printf("=== RUN %s\n", t->name); printf("=== RUN %s\n", t->name);
if (setjmp(t->failNowBuf) == 0) if (setjmp(t->returnNowBuf) == 0)
(*(t->f))(t); (*(t->f))(t);
status = "PASS"; status = "PASS";
if (t->failed) { if (t->failed) {
status = "FAIL"; status = "FAIL";
anyFailed = 1; anyFailed = 1;
} } else if (t->skipped)
// note that failed overrides skipped
status = "SKIP";
printf("--- %s: %s (%s)\n", status, t->name, "TODO"); printf("--- %s: %s (%s)\n", status, t->name, "TODO");
} }
@ -61,7 +65,16 @@ int testingMain(void)
return 0; 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 // TODO extract filename from file
printf("\t%s:%d: ", file, line); 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) 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; t->failed = 1;
} }
void testingprivTDoFailNow(testingT *t) void testingprivTDoFailNow(testingT *t)
{ {
t->failed = 1; t->failed = 1;
longjmp(t->failNowBuf, 1); longjmp(t->returnNowBuf, 1);
}
void testingprivTDoSkipNow(testingT *t)
{
t->skipped = 1;
longjmp(t->returnNowBuf, 1);
} }