diff --git a/test/main.c b/test/main.c index 8017f791..a2582414 100644 --- a/test/main.c +++ b/test/main.c @@ -1,17 +1,56 @@ // 19 january 2020 -#include -#include +#include "test.h" + +struct test { + const char *name; + int (*f)(void); +}; + +static struct test *tests = NULL; +static size_t lenTests = 0; +static size_t capTests = 0; + +void testingprivRegisterTest(const char *name, int (*f)(void)) +{ + if (lenTests == capTests) { + struct test *newtests; + + capTests += 32; + newtests = (struct test *) realloc(tests, capTests * sizeof (struct test)); + if (newtests == NULL) { + fprintf(stderr, "memory exhausted registering test %s\n", name); + exit(1); + } + tests = newtests; + } + tests[lenTests].name = name; + tests[lenTests].f = f; + lenTests++; +} + +static int testcmp(const void *aa, const void *bb) +{ + const struct test *a = (const struct test *) aa; + const struct test *b = (const struct test *) bb; + + return strcmp(a->name, b->name); +} int main(int argc, char *argv[]) { + struct test *t; + struct test want; + if (argc != 2) { - fprintf(stderr, "usage: %s [-list|TestName]\n", argv[0]); + fprintf(stderr, "usage: %s TestName\n", argv[0]); return 1; } - if (strcmp(argv[1], "-list") == 0) { - // TODO - return 0; + qsort(tests, lenTests, sizeof (struct test), testcmp); + want.name = argv[1]; + t = (struct test *) bsearch(&want, tests, lenTests, sizeof (struct test), testcmp); + if (t == NULL) { + fprintf(stderr, "%s: no such test\n", argv[1]); + return 1; } - // TODO - return 0; + return (*(t->f))(); } diff --git a/test/test.h b/test/test.h new file mode 100644 index 00000000..f8b4343c --- /dev/null +++ b/test/test.h @@ -0,0 +1,60 @@ +// 27 february 2018 + +#include +#include +#include +#include +#include +#include +#include "../ui.h" +#ifdef testingprivOSHeader +#include testingprivOSHeader +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#define testingprivImplName(basename) testingprivImpl ## basename + +// references: +// - https://gitlab.gnome.org/GNOME/glib/blob/master/glib/gconstructor.h +// - https://gitlab.gnome.org/GNOME/glib/blob/master/gio/glib-compile-resources.c +// - https://msdn.microsoft.com/en-us/library/bb918180.aspx +#define testingprivCtorName(basename) testingprivCtor ## basename +#define testingprivCtorPtrName(basename) testingprivCtorPtr ## basename +#if defined(__GNUC__) +#define testingprivMkCtor(basename) \ + __attribute__((constructor)) static void testingprivCtorName(basename)(void) { testingprivRegisterTest(#basename, testingprivImplName(basename)); } +#elif defined(_MSC_VER) +#define testingprivMkCtor(basename) \ + static int testingprivCtorName(basename)(void) { testingprivRegisterTest(#basename, testingprivImplName(basename)); return 0; } \ + __pragma(section(".CRT$XCU",read)) \ + __declspec(allocate(".CRT$XCU")) static int (*testingprivCtorPtrName(basename))(void) = testingprivCtorName(basename); +#elif defined(__SUNPRO_C) +#define testingprivMkCtor(basename) \ + static void testingprivCtorName(basename)(void) { testingprivRegisterTest(#basename, testingprivImplName(basename)); } \ + _Pragma(init(testingprivCtorName(basename))) +#else +#error unknown compiler for making constructors in C; cannot continue +#endif + +#define Test(basename) \ + int testingprivImplName(basename)(void); \ + testingprivMkCtor(basename) \ + int testingprivImplName(basename)(void) + +#define Test(Name) \ + testingprivMk(Test ## Name) + +// These can only be called directly from the Test functions. +// TODO make it otherwise +#define TestFailNow() return 1 +// see https://mesonbuild.com/Unit-tests.html#skipped-tests-and-hard-errors +#define TestSkipNow() return 77 + +extern void testingprivRegisterTest(const char *name, int (*f)(void)); + +#ifdef __cplusplus +} +#endif diff --git a/test/testing.h b/test/testing.h deleted file mode 100644 index ea5f4070..00000000 --- a/test/testing.h +++ /dev/null @@ -1,111 +0,0 @@ -// 27 february 2018 - -#include -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -#define testingprivImplName(basename) testingprivImpl ## basename - -// references: -// - https://gitlab.gnome.org/GNOME/glib/blob/master/glib/gconstructor.h -// - https://gitlab.gnome.org/GNOME/glib/blob/master/gio/glib-compile-resources.c -// - https://msdn.microsoft.com/en-us/library/bb918180.aspx -#define testingprivCtorName(basename) testingprivCtor ## basename -#define testingprivCtorPtrName(basename) testingprivCtorPtr ## basename -#if defined(__GNUC__) -#define testingprivMkCtor(basename) \ - __attribute__((constructor)) static void testingprivCtorName(basename)(void) { testingprivRegisterTest(#basename, testingprivImplName(basename), __FILE__, __LINE__); } -#elif defined(_MSC_VER) -#define testingprivMkCtor(basename) \ - static int testingprivCtorName(basename)(void) { testingprivRegisterTest(#basename, testingprivImplName(basename), __FILE__, __LINE__); return 0; } \ - __pragma(section(".CRT$XCU",read)) \ - __declspec(allocate(".CRT$XCU")) static int (*testingprivCtorPtrName(basename))(void) = testingprivCtorName(basename); -#elif defined(__SUNPRO_C) -#define testingprivMkCtor(basename) \ - static void testingprivCtorName(basename)(void) { testingprivRegisterTest(#basename, testingprivImplName(basename), __FILE__, __LINE__); } \ - _Pragma(init(testingprivCtorName(basename))) -#else -#error unknown compiler for making constructors in C; cannot continue -#endif - -#define testingprivMk(basename, argtype, argname) \ - void testingprivImplName(basename)(argtype *argname); \ - testingprivMkCtor(basename) \ - void testingprivImplName(basename)(argtype *argname) - -#define Test(Name) \ - testingprivMk(Test ## Name, testingT, t) - -typedef struct testingSet testingSet; -typedef struct testingOptions testingOptions; - -struct testingOptions { - bool Verbose; -}; - -extern void testingSetRun(testingSet *set, const struct testingOptions *options, bool *anyRun, bool *anyFailed); - -typedef struct testingT testingT; - -#define testingTLogf(t, ...) \ - testingprivTLogfFullThen(t, NULL, __FILE__, __LINE__, __VA_ARGS__) -#define testingTLogvf(t, format, ap) \ - testingprivTLogvfFullThen(t, NULL, __FILE__, __LINE__, format, ap) -#define testingTLogfFull(t, file, line, ...) \ - testingprivTLogfFullThen(t, NULL, file, line, __VA_ARGS__) -#define testingTLogvfFull(t, file, line, format, ap) \ - testingprivTLogvfFullThen(t, NULL, file, line, format, ap) - -#define testingTErrorf(t, ...) \ - testingprivTLogfFullThen(t, testingTFail, __FILE__, __LINE__, __VA_ARGS__) -#define testingTErrorvf(t, format, ap) \ - testingprivTLogvfFullThen(t, testingTFail, __FILE__, __LINE__, format, ap) -#define testingTErrorfFull(t, file, line, ...) \ - testingprivTLogfFullThen(t, testingTFail, file, line, __VA_ARGS__) -#define testingTErrorvfFull(t, file, line, format, ap) \ - testingprivTLogvfFullThen(t, testingTFail, file, line, format, ap) - -#define testingTFatalf(t, ...) \ - testingprivTLogfFullThen(t, testingTFailNow, __FILE__, __LINE__, __VA_ARGS__) -#define testingTFatalvf(t, format, ap) \ - testingprivTLogvfFullThen(t, testingTFailNow, __FILE__, __LINE__, format, ap) -#define testingTFatalfFull(t, file, line, ...) \ - testingprivTLogfFullThen(t, testingTFailNow, file, line, __VA_ARGS__) -#define testingTFatalvfFull(t, file, line, format, ap) \ - testingprivTLogvfFullThen(t, testingTFailNow, file, line, format, ap) - -#define testingTSkipf(t, ...) \ - testingprivTLogfFullThen(t, testingTSkipNow, __FILE__, __LINE__, __VA_ARGS__) -#define testingTSkipvf(t, format, ap) \ - testingprivTLogvfFullThen(t, testingTSkipNow, __FILE__, __LINE__, format, ap) -#define testingTSkipfFull(t, file, line, ...) \ - testingprivTLogfFullThen(t, testingTSkipNow, file, line, __VA_ARGS__) -#define testingTSkipvfFull(t, file, line, format, ap) \ - testingprivTLogvfFullThen(t, testingTSkipNow, file, line, format, ap) - -extern void testingTFail(testingT *t); -extern void testingTFailNow(testingT *t); -extern void testingTSkipNow(testingT *t); - -extern void testingTDefer(testingT *t, void (*f)(testingT *t, void *data), void *data); -extern void testingTRun(testingT *t, const char *subname, void (*subfunc)(testingT *t, void *data), void *data); - -extern void testingprivSetRegisterTest(testingSet **pset, const char *, void (*)(testingT *, void *), void *, const char *, long); -#include "../../sharedbits/printfwarn_header.h" -sharedbitsPrintfFunc( - extern void testingprivTLogfFullThen(testingT *, void (*)(testingT *), const char *, long, const char *, ...), - 5, 6); -#undef sharedbitsPrintfFunc -extern void testingprivTLogvfFullThen(testingT *, void (*)(testingT *), const char *, long, const char *, va_list); - -// Utility functions, provided here to avoid mucking up the sharedbits functions. -extern char *testingUtilStrdup(const char *s); -extern void testingUtilFreeStrdup(char *s); - -#ifdef __cplusplus -} -#endif