diff --git a/common/opentype_test.c b/common/opentype_test.c index 589353e8..c374154e 100644 --- a/common/opentype_test.c +++ b/common/opentype_test.c @@ -19,25 +19,23 @@ typedef uiForEach (*uiOpenTypeFeaturesForEachFunc)(const uiOpenTypeFeatures *otf #define uiprivFree free #include "opentype.c" +static void freeOpenType(void *otf) +{ + uiFreeOpenTypeFeatures((uiOpenTypeFeatures *) otf); +} + testingTest(OpenTypeFeaturesAddGet) { uiOpenTypeFeatures *otf; - char a, b, c, d; uint32_t value; otf = uiNewOpenTypeFeatures(); + testingTDefer(t, freeOpenType, otf); uiOpenTypeFeaturesAdd(otf, 'a', 'b', 'c', 'd', 12345); - if (!uiOpenTypeFeaturesGet(otf, 'a', 'b', 'c', 'd', &value)) { - testingTErrorf(t, "uiOpenTypeFeaturesGet() failed to get feature we added"); - goto out; - } - if (value != 12345) { - testingTErrorf(t, "feature abcd: got %" PRIu32 ", want 12345", value); - goto out; - } - -out: - uiFreeOpenTypeFeatures(otf); + if (!uiOpenTypeFeaturesGet(otf, 'a', 'b', 'c', 'd', &value)) + testingTFatalf(t, "uiOpenTypeFeaturesGet() failed to get feature we added"); + if (value != 12345) + testingTFatalf(t, "feature abcd: got %" PRIu32 ", want 12345", value); } int main(void) diff --git a/common/testing.h b/common/testing.h index fe63197b..15ea2629 100644 --- a/common/testing.h +++ b/common/testing.h @@ -94,6 +94,8 @@ extern void testingTFail(testingT *t); #define testingTFailNow(t) (testingprivTDoFailNow(t)) #define testingTSkipNow(t) (testingprivTDoSkipNow(t)) #endif +// TODO should the defered function also have t passed to it? +extern void testingTDefer(testingT *t, void (*f)(void *data), void *data); // TODO should __LINE__ arguments use intmax_t or uintmax_t instead of int? extern void testingprivRegisterTest(const char *, void (*)(testingT *)); diff --git a/common/testing_testing.c b/common/testing_testing.c index 934daa5f..6139ef75 100644 --- a/common/testing_testing.c +++ b/common/testing_testing.c @@ -6,12 +6,20 @@ #define testingprivNew(T) ((T *) malloc(sizeof (T))) +struct defer { + void (*f)(void *); + void *data; + struct defer *next; +}; + struct testingT { const char *name; void (*f)(testingT *); int failed; int skipped; jmp_buf returnNowBuf; + struct defer *defers; + int defersRun; testingT *next; }; @@ -26,10 +34,23 @@ void testingprivRegisterTest(const char *name, void (*f)(testingT *)) t->f = f; t->failed = 0; t->skipped = 0; + t->defers = NULL; + t->defersRun = 0; t->next = tests; tests = t; } +static void runDefers(testingT *t) +{ + struct defer *d; + + if (t->defersRun) + return; + t->defersRun = 1; + for (d = t->defers; d != NULL; d = d->next) + (*(d->f))(d->data); +} + int testingMain(void) { testingT *t; @@ -48,6 +69,7 @@ int testingMain(void) printf("=== RUN %s\n", t->name); if (setjmp(t->returnNowBuf) == 0) (*(t->f))(t); + runDefers(t); status = "PASS"; if (t->failed) { status = "FAIL"; @@ -89,14 +111,32 @@ void testingTFail(testingT *t) t->failed = 1; } +static void returnNow(testingT *t) +{ + // run defers before calling longjmp() just to be safe + runDefers(t); + longjmp(t->returnNowBuf, 1); +} + void testingprivTDoFailNow(testingT *t) { testingTFail(t); - longjmp(t->returnNowBuf, 1); + returnNow(t); } void testingprivTDoSkipNow(testingT *t) { t->skipped = 1; - longjmp(t->returnNowBuf, 1); + returnNow(t); +} + +void testingTDefer(testingT *t, void (*f)(void *data), void *data) +{ + struct defer *d; + + d = testingprivNew(struct defer); + d->f = f; + d->data = data; + d->next = t->defers; + t->defers = d; }