Added early termination mechanics to the testing framework.
This commit is contained in:
parent
8d92003426
commit
d0db6f9594
|
@ -25,23 +25,43 @@
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(__GNUC__)
|
#ifdef __cplusplus
|
||||||
|
#define testingprivMkScaffold(name) \
|
||||||
|
static inline void testingprivScaffold ## name(testingT *t) \
|
||||||
|
{ \
|
||||||
|
bool failedNow = false; \
|
||||||
|
try { name(t); } \
|
||||||
|
catch (testingprivFailNowException e) { failedNow = true; } \
|
||||||
|
/* TODO see if we should catch other exceptions too */ \
|
||||||
|
/* don't call this in the catch block as it calls longjmp() */ \
|
||||||
|
if (failedNow) testingprivTDoFailNow(t); \
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
#define testingprivMkScaffold(name) \
|
||||||
|
static inline void testingprivScaffold ## name(testingT *t) { name(t); }
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(__cplusplus)
|
||||||
#define testingprivMkCtor(name, reg) \
|
#define testingprivMkCtor(name, reg) \
|
||||||
__attribute__((constructor)) static void testingprivCtor ## name(void) { reg(#name, name); }
|
static reg ## Class testingprivCtor ## name(#name, testingprivScaffold ## name);
|
||||||
|
#elif defined(__GNUC__)
|
||||||
|
#define testingprivMkCtor(name, reg) \
|
||||||
|
__attribute__((constructor)) static void testingprivCtor ## name(void) { reg(#name, testingprivScaffold ## name); }
|
||||||
#elif defined(_MSC_VER)
|
#elif defined(_MSC_VER)
|
||||||
#define testingprivMkCtorPrototype(name, reg) \
|
#define testingprivMkCtorPrototype(name, reg) \
|
||||||
static int name(void) testingprivCtor ## name(void) { reg(#name, name); return 0; } \
|
static int name(void) testingprivCtor ## name(void) { reg(#name, testingprivScaffold ## name); return 0; } \
|
||||||
__pragma(section(".CRT$XCU",read)) \
|
__pragma(section(".CRT$XCU",read)) \
|
||||||
__declspec(allocate(".CRT$XCU")) static int (*testingprivCtorPtr ## name)(void) = testingprivCtor ## name;
|
__declspec(allocate(".CRT$XCU")) static int (*testingprivCtorPtr ## name)(void) = testingprivCtor ## name;
|
||||||
#elif defined(__SUNPRO_C)
|
#elif defined(__SUNPRO_C)
|
||||||
#define testingprivMkCtor(name, reg) \
|
#define testingprivMkCtor(name, reg) \
|
||||||
_Pragma("init(testingprivCtor" #name ")") static void testingprivCtor ## name(void) { reg(#name, name); }
|
_Pragma("init(testingprivCtor" #name ")") static void testingprivCtor ## name(void) { reg(#name, testingprivScaffold ## name); }
|
||||||
#else
|
#else
|
||||||
#error unknown compiler; cannot continue
|
#error unknown compiler for making constructors in C; cannot continue
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define testingTest(Name) \
|
#define testingTest(Name) \
|
||||||
void Test ## Name(testingT *t); \
|
void Test ## Name(testingT *t); \
|
||||||
|
testingprivMkScaffold(Test ## Name) \
|
||||||
testingprivMkCtor(Test ## Name, testingprivRegisterTest) \
|
testingprivMkCtor(Test ## Name, testingprivRegisterTest) \
|
||||||
void Test ## Name(testingT *t)
|
void Test ## Name(testingT *t)
|
||||||
|
|
||||||
|
@ -50,14 +70,27 @@ extern int testingMain(void);
|
||||||
typedef struct testingT testingT;
|
typedef struct testingT testingT;
|
||||||
#define testingTErrorf(t, ...) testingprivTErrorfFull(t, __FILE__, __LINE__, __VA_ARGS__)
|
#define testingTErrorf(t, ...) testingprivTErrorfFull(t, __FILE__, __LINE__, __VA_ARGS__)
|
||||||
#define testingTErrorvf(t, format, ap) testingprivTErrorvfFull(t, __FILE__, __LINE__, format, ap)
|
#define testingTErrorvf(t, format, ap) testingprivTErrorvfFull(t, __FILE__, __LINE__, format, ap)
|
||||||
|
#ifdef __cplusplus
|
||||||
|
#define testingTFailNow(t) (throw testingprivFailNowException())
|
||||||
|
#else
|
||||||
|
#define testingTFailNow(t) testingprivTDoFailNow(t)
|
||||||
|
#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 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 *);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
namespace {
|
||||||
|
class testingprivFailNowException {};
|
||||||
|
class testingprivRegisterTestClass {
|
||||||
|
public:
|
||||||
|
testingprivRegisterTestClass(const char *name, void (*f)(testingT *)) { testingprivRegisterTest(name, f); }
|
||||||
|
};
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
// 27 february 2018
|
// 27 february 2018
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <setjmp.h>
|
||||||
#include "testing.h"
|
#include "testing.h"
|
||||||
|
|
||||||
#define testingprivNew(T) ((T *) malloc(sizeof (T)))
|
#define testingprivNew(T) ((T *) malloc(sizeof (T)))
|
||||||
|
@ -9,6 +10,7 @@ struct testingT {
|
||||||
const char *name;
|
const char *name;
|
||||||
void (*f)(testingT *);
|
void (*f)(testingT *);
|
||||||
int failed;
|
int failed;
|
||||||
|
jmp_buf failNowBuf;
|
||||||
testingT *next;
|
testingT *next;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -41,6 +43,7 @@ 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)
|
||||||
(*(t->f))(t);
|
(*(t->f))(t);
|
||||||
status = "PASS";
|
status = "PASS";
|
||||||
if (t->failed) {
|
if (t->failed) {
|
||||||
|
@ -81,3 +84,9 @@ void testingprivTErrorvfFull(testingT *t, const char *file, int line, const char
|
||||||
testingprivTDoLog(t, file, line, format, ap);
|
testingprivTDoLog(t, file, line, format, ap);
|
||||||
t->failed = 1;
|
t->failed = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void testingprivTDoFailNow(testingT *t)
|
||||||
|
{
|
||||||
|
t->failed = 1;
|
||||||
|
longjmp(t->failNowBuf, 1);
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue