Started restructuring things slightly so as to allow the new test functions to be safely called from subroutines.

This commit is contained in:
Pietro Gagliardi 2020-01-23 10:52:41 -05:00
parent cd2d64c228
commit 042da74cc9
2 changed files with 45 additions and 30 deletions

View File

@ -5,14 +5,14 @@
struct test { struct test {
const char *name; const char *name;
int (*f)(void); void (*f)(void);
}; };
static struct test *tests = NULL; static struct test *tests = NULL;
static size_t lenTests = 0; static size_t lenTests = 0;
static size_t capTests = 0; static size_t capTests = 0;
void testingprivRegisterTest(const char *name, int (*f)(void)) void testingprivRegisterTest(const char *name, void (*f)(void))
{ {
if (lenTests == capTests) { if (lenTests == capTests) {
struct test *newtests; struct test *newtests;
@ -38,6 +38,24 @@ static int testcmp(const void *aa, const void *bb)
return strcmp(a->name, b->name); return strcmp(a->name, b->name);
} }
static int testingprivRet = 0;
void TestFail(void)
{
testingprivRet = 1;
}
void TestFailNow(void)
{
exit(1);
}
void TestSkipNow(void)
{
// see https://mesonbuild.com/Unit-tests.html#skipped-tests-and-hard-errors
exit(77);
}
static const char *basename(const char *file) static const char *basename(const char *file)
{ {
const char *p; const char *p;
@ -51,7 +69,7 @@ static const char *basename(const char *file)
return file; return file;
} }
void testingprivLogf(FILE *f, const char *filename, long line, const char *fmt, ...) void testingprivLogfFullThen(FILE *f, void (*then)(void), const char *filename, long line, const char *fmt, ...)
{ {
va_list ap; va_list ap;
@ -60,6 +78,8 @@ void testingprivLogf(FILE *f, const char *filename, long line, const char *fmt,
vfprintf(f, fmt, ap); vfprintf(f, fmt, ap);
fprintf(f, "\n"); fprintf(f, "\n");
va_end(ap); va_end(ap);
if (then != NULL)
(*then)();
} }
int main(int argc, char *argv[]) int main(int argc, char *argv[])
@ -78,5 +98,7 @@ int main(int argc, char *argv[])
fprintf(stderr, "%s: no such test\n", argv[1]); fprintf(stderr, "%s: no such test\n", argv[1]);
return 1; return 1;
} }
return (*(t->f))(); testingprivRet = 0;
(*(t->f))();
return testingprivRet;
} }

View File

@ -41,56 +41,49 @@ extern "C" {
#endif #endif
#define Test(Name) \ #define Test(Name) \
void testingprivImplName(Test ## Name)(int *testingprivRet); \ void testingprivImplName(Test ## Name)(void); \
static int testingprivScaffoldName(Test ## Name)(void) \ static void testingprivScaffoldName(Test ## Name)(void) \
{ \ { \
int ret = 0; \
uiInitError err; \ uiInitError err; \
memset(&err, 0, sizeof (uiInitError)); \ memset(&err, 0, sizeof (uiInitError)); \
err.Size = sizeof (uiInitError); \ err.Size = sizeof (uiInitError); \
if (!uiInit(NULL, &err)) { \ if (!uiInit(NULL, &err)) { \
fprintf(stderr, "error initializing libui for Test" #Name ": %s\n", err.Message); \ fprintf(stderr, "error initializing libui for Test" #Name ": %s\n", err.Message); \
return 1; \ TestFailNow(); \
} \ } \
testingprivImplName(Test ## Name)(&ret); \ testingprivImplName(Test ## Name)(); \
return ret; \
} \ } \
testingprivMkCtor(Test ## Name) \ testingprivMkCtor(Test ## Name) \
void testingprivImplName(Test ## Name)(int *testingprivRet) void testingprivImplName(Test ## Name)(void)
#define TestNoInit(Name) \ #define TestNoInit(Name) \
void testingprivImplName(Test ## Name)(int *testingprivRet); \ void testingprivImplName(Test ## Name)(void); \
static int testingprivScaffoldName(Test ## Name)(void) \ static void testingprivScaffoldName(Test ## Name)(void) \
{ \ { \
int ret = 0; \ testingprivImplName(Test ## Name)(); \
testingprivImplName(Test ## Name)(&ret); \
return ret; \
} \ } \
testingprivMkCtor(Test ## Name) \ testingprivMkCtor(Test ## Name) \
void testingprivImplName(Test ## Name)(int *testingprivRet) void testingprivImplName(Test ## Name)(void)
// These can only be called directly from the Test functions. extern void TestFail(void);
// TODO make it otherwise extern void TestFailNow(void);
#define TestFail() (*testingprivRet = 1) extern void TestSkipNow(void);
#define TestFailNow() {TestFail(); return;}
// see https://mesonbuild.com/Unit-tests.html#skipped-tests-and-hard-errors
#define TestSkipNow() {*testingprivRet = 77; return;}
#define TestLogf(...) \ #define TestLogf(...) \
(testingprivLogf(stdout, __FILE__, __LINE__, __VA_ARGS__)) (testingprivLogfFullThen(stdout, NULL, __FILE__, __LINE__, __VA_ARGS__))
#define TestErrorf(...) \ #define TestErrorf(...) \
{testingprivLogf(stderr, __FILE__, __LINE__, __VA_ARGS__); TestFail();} (testingprivLogfFullThen(stderr, TestFail, __FILE__, __LINE__, __VA_ARGS__))
#define TestFatalf(...) \ #define TestFatalf(...) \
{testingprivLogf(stderr, __FILE__, __LINE__, __VA_ARGS__); TestFailNow();} (testingprivLogfFullThen(stderr, TestFailNow, __FILE__, __LINE__, __VA_ARGS__))
// TODO remember if this needs to go to stdout or to stderr // TODO remember if this needs to go to stdout or to stderr
#define TestSkipf(...) \ #define TestSkipf(...) \
{testingprivLogf(stderr, __FILE__, __LINE__, __VA_ARGS__); TestSkipNow();} (testingprivLogfFullThen(stderr, TestSkipNow, __FILE__, __LINE__, __VA_ARGS__))
extern void testingprivRegisterTest(const char *name, int (*f)(void)); extern void testingprivRegisterTest(const char *name, void (*f)(void));
#include "../sharedbits/printfwarn_header.h" #include "../sharedbits/printfwarn_header.h"
sharedbitsPrintfFunc( sharedbitsPrintfFunc(
extern void testingprivLogf(FILE *f, const char *filename, long line, const char *fmt, ...), extern void testingprivLogfFullThen(FILE *f, void (*then)(void), const char *filename, long line, const char *fmt, ...),
4, 5); 5, 6);
#undef sharedbitsPrintfFunc #undef sharedbitsPrintfFunc
// end of test framework definitions // end of test framework definitions