// 8 june 2019 #include "test.h" struct counts { unsigned long countInit; unsigned long countFree; unsigned long countEventOnFree; }; static void checkCountsFull(testingT *t, const char *file, long line, const struct counts *got, const struct counts *want) { #define check(method) \ if (got->count ## method != want->count ## method) \ testingTErrorfFull(t, file, line, "wrong number of calls to " #method "():" diff("%lu"), \ got->count ## method, want->count ## method) check(Init); check(Free); #undef check #define check(event) \ if (got->countEvent ## event != want->countEvent ## event) \ testingTErrorfFull(t, file, line, "wrong number of fires of uiControl" #event "():" diff("%lu"), \ got->countEvent ## event, want->countEvent ## event) check(OnFree); #undef check } #define checkCounts(t, got, want) checkCountsFull(t, __FILE__, __LINE__, got, want) struct testImplData { struct counts *counts; }; static struct counts failInit; void *testControlFailInit = &failInit; // TODO document that impl data is zero-initialized before this is called // TODO we'll also have to eventually deal with the fact that NULL is not required to be 0... or at least confirm that static bool testVtableInit(uiControl *c, void *implData, void *initData) { struct testImplData *d = (struct testImplData *) implData; struct counts *counts = (struct counts *) initData; if (initData == testControlFailInit) return false; if (initData == NULL) return true; if (d->counts == NULL) d->counts = counts; d->counts->countInit++; return true; } static void testVtableFree(uiControl *c, void *implData) { struct testImplData *d = (struct testImplData *) implData; if (d->counts != NULL) d->counts->countFree++; } static const uiControlVtable vtable = { .Size = sizeof (uiControlVtable), .Init = testVtableInit, .Free = testVtableFree, }; const uiControlVtable *testVtable(void) { return &vtable; } size_t testImplDataSize(void) { return sizeof (struct testImplData); } // TODO explicitly make/document 0 as always invalid uint32_t testControlType = 0; uint32_t testControlType2 = 0; static void eventFreeHandler(void *sender, void *args, void *data) { struct counts *counts = (struct counts *) data; counts->countEventOnFree++; } testingTest(ControlMethodsCalled) { uiControl *c; struct counts counts; struct counts want; int handler; testingTLogf(t, "*** uiNewControl()"); memset(&counts, 0, sizeof (struct counts)); c = uiNewControl(testControlType, &counts); memset(&want, 0, sizeof (struct counts)); want.countInit = 1; checkCounts(t, &counts, &want); testingTLogf(t, "*** uiControlFree()"); memset(&counts, 0, sizeof (struct counts)); handler = uiEventAddHandler(uiControlOnFree(), eventFreeHandler, c, &counts); uiControlFree(c); uiEventDeleteHandler(uiControlOnFree(), handler); memset(&want, 0, sizeof (struct counts)); want.countFree = 1; want.countEventOnFree = 1; checkCounts(t, &counts, &want); }