mirror of
https://github.com/ennorehling/cutest.git
synced 2024-12-23 00:02:20 +00:00
Add setup and teardown hooks per test suite
This commit is contained in:
parent
0fe17b4c0f
commit
02898b90c3
@ -4,6 +4,7 @@
|
||||
|
||||
CuSuite* CuGetSuite(void);
|
||||
CuSuite* CuStringGetSuite(void);
|
||||
CuSuite* CuSuiteFrameGetSuite(void);
|
||||
|
||||
int RunAllTests(void)
|
||||
{
|
||||
@ -12,6 +13,7 @@ int RunAllTests(void)
|
||||
|
||||
CuSuiteAddSuite(suite, CuGetSuite());
|
||||
CuSuiteAddSuite(suite, CuStringGetSuite());
|
||||
CuSuiteAddSuite(suite, CuSuiteFrameGetSuite());
|
||||
|
||||
CuSuiteRun(suite);
|
||||
CuSuiteSummary(suite, output);
|
||||
|
51
CuTest.c
51
CuTest.c
@ -134,18 +134,22 @@ void CuTestDelete(CuTest *t)
|
||||
free(t);
|
||||
}
|
||||
|
||||
void CuTestRun(CuTest* tc)
|
||||
{
|
||||
static void TestFunctionRun(CuTest *tc, TestFunction function) {
|
||||
jmp_buf buf;
|
||||
tc->jumpBuf = &buf;
|
||||
if (setjmp(buf) == 0)
|
||||
{
|
||||
tc->ran = 1;
|
||||
(tc->function)(tc);
|
||||
function(tc);
|
||||
}
|
||||
tc->jumpBuf = 0;
|
||||
}
|
||||
|
||||
void CuTestRun(CuTest* tc)
|
||||
{
|
||||
TestFunctionRun(tc, tc->function);
|
||||
}
|
||||
|
||||
static void CuFailInternal(CuTest* tc, const char* file, int line, CuString* string)
|
||||
{
|
||||
char buf[HUGE_STRING_LEN];
|
||||
@ -233,22 +237,52 @@ void CuAssertPtrEquals_LineMsg(CuTest* tc, const char* file, int line, const cha
|
||||
CuFail_Line(tc, file, line, message, buf);
|
||||
}
|
||||
|
||||
void *CuTestContextGet(CuTest *tc) {
|
||||
return tc->context;
|
||||
}
|
||||
|
||||
void CuTestContextSet(CuTest *tc, void *context) {
|
||||
tc->context = context;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*
|
||||
* CuSuite
|
||||
*-------------------------------------------------------------------------*/
|
||||
static void EmptySetup(CuTest *tc) {
|
||||
(void)tc;
|
||||
}
|
||||
|
||||
static void EmptyTeardown(CuTest *tc) {
|
||||
(void)tc;
|
||||
}
|
||||
|
||||
static const CuTestFrame EmptyFrame = {
|
||||
.setup = EmptySetup,
|
||||
.teardown = EmptyTeardown,
|
||||
};
|
||||
|
||||
void CuSuiteInit(CuSuite* testSuite)
|
||||
{
|
||||
CuSuiteInitWithFrame(testSuite, &EmptyFrame, NULL);
|
||||
}
|
||||
|
||||
void CuSuiteInitWithFrame(CuSuite* testSuite, const CuTestFrame *frame, void *frameContext)
|
||||
{
|
||||
testSuite->count = 0;
|
||||
testSuite->failCount = 0;
|
||||
memset(testSuite->list, 0, sizeof(testSuite->list));
|
||||
testSuite->frame = frame;
|
||||
testSuite->frameContext = frameContext;
|
||||
}
|
||||
|
||||
CuSuite* CuSuiteNew(void)
|
||||
{
|
||||
return CuSuiteNewWithFrame(&EmptyFrame, NULL);
|
||||
}
|
||||
|
||||
CuSuite* CuSuiteNewWithFrame(const CuTestFrame *frame, void *frameContext) {
|
||||
CuSuite* testSuite = CU_ALLOC(CuSuite);
|
||||
CuSuiteInit(testSuite);
|
||||
CuSuiteInitWithFrame(testSuite, frame, frameContext);
|
||||
return testSuite;
|
||||
}
|
||||
|
||||
@ -285,11 +319,20 @@ void CuSuiteAddSuite(CuSuite* testSuite, CuSuite* testSuite2)
|
||||
|
||||
void CuSuiteRun(CuSuite* testSuite)
|
||||
{
|
||||
const CuTestFrame * const frame = testSuite->frame;
|
||||
int i;
|
||||
|
||||
for (i = 0 ; i < testSuite->count ; ++i)
|
||||
{
|
||||
CuTest* testCase = testSuite->list[i];
|
||||
testCase->context = testSuite->frameContext;
|
||||
|
||||
TestFunctionRun(testCase, frame->setup);
|
||||
if (!testCase->failed) {
|
||||
CuTestRun(testCase);
|
||||
TestFunctionRun(testCase, frame->teardown);
|
||||
}
|
||||
testSuite->frameContext = testCase->context;
|
||||
if (testCase->failed) { testSuite->failCount += 1; }
|
||||
}
|
||||
}
|
||||
|
13
CuTest.h
13
CuTest.h
@ -48,12 +48,15 @@ struct CuTest
|
||||
int ran;
|
||||
CuString *message;
|
||||
jmp_buf *jumpBuf;
|
||||
void *context;
|
||||
};
|
||||
|
||||
void CuTestInit(CuTest* t, const char* name, TestFunction function);
|
||||
CuTest* CuTestNew(const char* name, TestFunction function);
|
||||
void CuTestRun(CuTest* tc);
|
||||
void CuTestDelete(CuTest *t);
|
||||
void *CuTestContextGet(CuTest *tc);
|
||||
void CuTestContextSet(CuTest *tc, void *context);
|
||||
|
||||
/* Internal versions of assert functions -- use the public versions */
|
||||
void CuFail_Line(CuTest* tc, const char* file, int line, const char* message2, const char* message);
|
||||
@ -95,17 +98,25 @@ void CuAssertPtrEquals_LineMsg(CuTest* tc,
|
||||
|
||||
#define SUITE_ADD_TEST(SUITE,TEST) CuSuiteAdd(SUITE, CuTestNew(#TEST, TEST))
|
||||
|
||||
typedef struct CuTestFrame {
|
||||
void (*setup)(CuTest *tc);
|
||||
void (*teardown)(CuTest *tc);
|
||||
}CuTestFrame;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int count;
|
||||
CuTest* list[MAX_TEST_CASES];
|
||||
int failCount;
|
||||
|
||||
const CuTestFrame *frame;
|
||||
void *frameContext;
|
||||
} CuSuite;
|
||||
|
||||
|
||||
void CuSuiteInit(CuSuite* testSuite);
|
||||
void CuSuiteInitWithFrame(CuSuite* testSuite, const CuTestFrame *frame, void *frameContext);
|
||||
CuSuite* CuSuiteNew(void);
|
||||
CuSuite* CuSuiteNewWithFrame(const CuTestFrame *frame, void *frameContext);
|
||||
void CuSuiteDelete(CuSuite *testSuite);
|
||||
void CuSuiteAdd(CuSuite* testSuite, CuTest *testCase);
|
||||
void CuSuiteAddSuite(CuSuite* testSuite, CuSuite* testSuite2);
|
||||
|
279
CuTestTest.c
279
CuTestTest.c
@ -3,6 +3,7 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "CuTest.h"
|
||||
|
||||
@ -707,3 +708,281 @@ CuSuite* CuGetSuite(void)
|
||||
|
||||
return suite;
|
||||
}
|
||||
|
||||
typedef enum TestPhase {
|
||||
UNKNOWN = 0,
|
||||
SETUP,
|
||||
TEST,
|
||||
TEARDOWN
|
||||
}TestPhase;
|
||||
|
||||
#define TEST_PHASE_RECORDER_LEN 50
|
||||
|
||||
typedef struct TestPhaseRecorder {
|
||||
TestPhase TestSequence[TEST_PHASE_RECORDER_LEN];
|
||||
size_t pos;
|
||||
}TestPhaseTracker;
|
||||
|
||||
static void TestPhaseRecord(TestPhaseTracker *tracker, TestPhase phase) {
|
||||
if (tracker->pos < TEST_PHASE_RECORDER_LEN) {
|
||||
tracker->TestSequence[tracker->pos++] = phase;
|
||||
}
|
||||
}
|
||||
|
||||
static void TestPhaseNoMoreEventsFrom(CuTest *tc, TestPhaseTracker *tracker, size_t pos) {
|
||||
for (size_t i = pos;i < TEST_PHASE_RECORDER_LEN;i++) {
|
||||
CuAssertIntEquals(tc, UNKNOWN, tracker->TestSequence[i]);
|
||||
}
|
||||
}
|
||||
|
||||
static struct TestMockData {
|
||||
TestPhaseTracker tracker;
|
||||
|
||||
void *ContextPassed;
|
||||
|
||||
bool setupShallFail;
|
||||
bool teardownShallFail;
|
||||
bool testShallFail;
|
||||
|
||||
bool setupContinuedAfterAssert;
|
||||
bool testContinuedAfterAssert;
|
||||
bool teardownContinuedAfterAssert;
|
||||
}TestMockData;
|
||||
|
||||
static void TestMockDataInit(void) {
|
||||
memset(&TestMockData, 0, sizeof(TestMockData));
|
||||
}
|
||||
|
||||
static void FrameMockSetup(CuTest *tc) {
|
||||
bool fail = TestMockData.setupShallFail;
|
||||
TestMockData.setupShallFail = false;
|
||||
|
||||
TestPhaseRecord(&TestMockData.tracker, SETUP);
|
||||
|
||||
CuAssert(tc, "Have to fail", !fail);
|
||||
TestMockData.setupContinuedAfterAssert = true;
|
||||
}
|
||||
|
||||
static void FrameMockTest(CuTest *tc) {
|
||||
bool fail = TestMockData.testShallFail;
|
||||
TestMockData.testShallFail = false;
|
||||
|
||||
TestPhaseRecord(&TestMockData.tracker, TEST);
|
||||
TestMockData.ContextPassed = CuTestContextGet(tc);
|
||||
|
||||
CuAssert(tc, "Have to fail", !fail);
|
||||
TestMockData.testContinuedAfterAssert = true;
|
||||
}
|
||||
|
||||
static void FrameMockTearDown(CuTest *tc) {
|
||||
bool fail = TestMockData.teardownShallFail;
|
||||
TestMockData.teardownShallFail = false;
|
||||
|
||||
TestPhaseRecord(&TestMockData.tracker, TEARDOWN);
|
||||
|
||||
CuAssert(tc, "Have to fail", !fail);
|
||||
TestMockData.teardownContinuedAfterAssert = true;
|
||||
}
|
||||
|
||||
static const CuTestFrame FrameMock = {
|
||||
.setup = FrameMockSetup,
|
||||
.teardown = FrameMockTearDown,
|
||||
};
|
||||
|
||||
static void TestSuiteWithFrameInit(CuTest *tc) {
|
||||
CuSuite ts;
|
||||
int context = 0;
|
||||
CuSuiteInitWithFrame(&ts, &FrameMock, &context);
|
||||
CuAssertPtrEquals(tc, (void *)&FrameMock, (void *)ts.frame);
|
||||
CuAssertPtrEquals(tc, &context, ts.frameContext);
|
||||
}
|
||||
|
||||
static void TestSuiteWithFrameNew(CuTest *tc) {
|
||||
int context = 0;
|
||||
CuSuite* ts = CuSuiteNewWithFrame(&FrameMock, &context);
|
||||
CuAssertPtrEquals(tc, (void *)&FrameMock, (void *)ts->frame);
|
||||
CuAssertPtrEquals(tc, &context, ts->frameContext);
|
||||
}
|
||||
|
||||
static void TestSuiteRunsSetupTestTeardown(CuTest *tc) {
|
||||
int context = 0;
|
||||
TestMockDataInit();
|
||||
CuSuite* uut = CuSuiteNewWithFrame(&FrameMock, &context);
|
||||
|
||||
SUITE_ADD_TEST(uut, FrameMockTest);
|
||||
|
||||
CuSuiteRun(uut);
|
||||
|
||||
TestPhaseTracker *tracker = &TestMockData.tracker;
|
||||
CuAssertIntEquals(tc, SETUP, tracker->TestSequence[0]);
|
||||
CuAssertIntEquals(tc, TEST, tracker->TestSequence[1]);
|
||||
CuAssertIntEquals(tc, TEARDOWN, tracker->TestSequence[2]);
|
||||
TestPhaseNoMoreEventsFrom(tc, tracker, 3);
|
||||
}
|
||||
|
||||
static void TestSuiteTestFailsIfSetupFails(CuTest *tc) {
|
||||
int context = 0;
|
||||
TestMockDataInit();
|
||||
CuSuite* uut = CuSuiteNewWithFrame(&FrameMock, &context);
|
||||
|
||||
SUITE_ADD_TEST(uut, FrameMockTest);
|
||||
SUITE_ADD_TEST(uut, TestPasses);
|
||||
|
||||
TestMockData.setupShallFail = true;
|
||||
|
||||
CuSuiteRun(uut);
|
||||
|
||||
CuAssertIntEquals(tc, 2, uut->count);
|
||||
CuAssertIntEquals(tc, 1, uut->failCount);
|
||||
|
||||
TestPhaseTracker *tracker = &TestMockData.tracker;
|
||||
CuAssertIntEquals(tc, SETUP, tracker->TestSequence[0]);
|
||||
CuAssertIntEquals(tc, SETUP, tracker->TestSequence[1]);
|
||||
CuAssertIntEquals(tc, TEARDOWN, tracker->TestSequence[2]);
|
||||
TestPhaseNoMoreEventsFrom(tc, tracker, 3);
|
||||
}
|
||||
|
||||
static void TestSuiteTestFailsIfTeardownFails(CuTest *tc) {
|
||||
int context = 0;
|
||||
TestMockDataInit();
|
||||
CuSuite* uut = CuSuiteNewWithFrame(&FrameMock, &context);
|
||||
|
||||
SUITE_ADD_TEST(uut, FrameMockTest);
|
||||
|
||||
TestMockData.teardownShallFail = true;
|
||||
|
||||
CuSuiteRun(uut);
|
||||
|
||||
CuAssertIntEquals(tc, 1, uut->count);
|
||||
CuAssertIntEquals(tc, 1, uut->failCount);
|
||||
}
|
||||
|
||||
static void TestSuiteTeardownIsExecutedIfTestFails(CuTest *tc) {
|
||||
int context = 0;
|
||||
TestMockDataInit();
|
||||
CuSuite* uut = CuSuiteNewWithFrame(&FrameMock, &context);
|
||||
|
||||
SUITE_ADD_TEST(uut, FrameMockTest);
|
||||
|
||||
TestMockData.testShallFail = true;
|
||||
|
||||
CuSuiteRun(uut);
|
||||
|
||||
CuAssertIntEquals(tc, 1, uut->count);
|
||||
CuAssertIntEquals(tc, 1, uut->failCount);
|
||||
|
||||
TestPhaseTracker *tracker = &TestMockData.tracker;
|
||||
CuAssertIntEquals(tc, SETUP, tracker->TestSequence[0]);
|
||||
CuAssertIntEquals(tc, TEST, tracker->TestSequence[1]);
|
||||
CuAssertIntEquals(tc, TEARDOWN, tracker->TestSequence[2]);
|
||||
TestPhaseNoMoreEventsFrom(tc, tracker, 3);
|
||||
}
|
||||
|
||||
static void TestSuiteContextPassedToCuTest(CuTest *tc) {
|
||||
int context = 0;
|
||||
TestMockDataInit();
|
||||
CuSuite* uut = CuSuiteNewWithFrame(&FrameMock, &context);
|
||||
|
||||
SUITE_ADD_TEST(uut, FrameMockTest);
|
||||
|
||||
CuSuiteRun(uut);
|
||||
|
||||
CuAssertPtrEquals(tc, &context, TestMockData.ContextPassed);
|
||||
}
|
||||
|
||||
static void TestSuiteSetupInterruptsUponFailedAssert(CuTest *tc) {
|
||||
int context = 0;
|
||||
TestMockDataInit();
|
||||
CuSuite* uut = CuSuiteNewWithFrame(&FrameMock, &context);
|
||||
TestMockData.setupShallFail = true;
|
||||
SUITE_ADD_TEST(uut, FrameMockTest);
|
||||
|
||||
CuSuiteRun(uut);
|
||||
|
||||
CuAssert(tc, "Setup did continue", !TestMockData.setupContinuedAfterAssert);
|
||||
}
|
||||
|
||||
static void TestSuiteTestInterruptsUponFailedAssert(CuTest *tc) {
|
||||
int context = 0;
|
||||
TestMockDataInit();
|
||||
CuSuite* uut = CuSuiteNewWithFrame(&FrameMock, &context);
|
||||
TestMockData.testShallFail = true;
|
||||
SUITE_ADD_TEST(uut, FrameMockTest);
|
||||
|
||||
CuSuiteRun(uut);
|
||||
|
||||
CuAssert(tc, "Test did continue", !TestMockData.testContinuedAfterAssert);
|
||||
}
|
||||
|
||||
static void TestSuiteTeardownInterruptsUponFailedAssert(CuTest *tc) {
|
||||
int context = 0;
|
||||
TestMockDataInit();
|
||||
CuSuite* uut = CuSuiteNewWithFrame(&FrameMock, &context);
|
||||
TestMockData.teardownShallFail = true;
|
||||
SUITE_ADD_TEST(uut, FrameMockTest);
|
||||
|
||||
CuSuiteRun(uut);
|
||||
|
||||
CuAssert(tc, "Teardown did continue", !TestMockData.teardownContinuedAfterAssert);
|
||||
}
|
||||
|
||||
static void *TheSetupContext;
|
||||
static void *TheTestContext;
|
||||
static void *TheTeardownContext;
|
||||
|
||||
static void FrameContextSetup(CuTest *tc) {
|
||||
TheSetupContext = CuTestContextGet(tc);
|
||||
CuTestContextSet(tc, &TheSetupContext);
|
||||
}
|
||||
|
||||
static void FrameContextTest(CuTest *tc) {
|
||||
TheTestContext = CuTestContextGet(tc);
|
||||
CuTestContextSet(tc, &TheTestContext);
|
||||
}
|
||||
|
||||
static void FrameContextTearDown(CuTest *tc) {
|
||||
TheTeardownContext = CuTestContextGet(tc);
|
||||
CuTestContextSet(tc, &TheTeardownContext);
|
||||
}
|
||||
|
||||
static const CuTestFrame FrameContextMock = {
|
||||
.setup = FrameContextSetup,
|
||||
.teardown = FrameContextTearDown,
|
||||
};
|
||||
|
||||
static void TestSuiteSetupTestTeardownWithContext(CuTest *tc) {
|
||||
int context = 0;
|
||||
|
||||
TheSetupContext = NULL;
|
||||
TheTestContext = NULL;
|
||||
TheTeardownContext = NULL;
|
||||
|
||||
CuSuite* uut = CuSuiteNewWithFrame(&FrameContextMock, &context);
|
||||
|
||||
SUITE_ADD_TEST(uut, FrameContextTest);
|
||||
|
||||
CuSuiteRun(uut);
|
||||
|
||||
CuAssertPtrEquals(tc, &context, TheSetupContext);
|
||||
CuAssertPtrEquals(tc, &TheSetupContext, TheTestContext);
|
||||
CuAssertPtrEquals(tc, &TheTestContext, TheTeardownContext);
|
||||
CuAssertPtrEquals(tc, &TheTeardownContext, uut->frameContext);
|
||||
}
|
||||
|
||||
CuSuite* CuSuiteFrameGetSuite(void) {
|
||||
CuSuite* suite = CuSuiteNew();
|
||||
|
||||
SUITE_ADD_TEST(suite, TestSuiteWithFrameInit);
|
||||
SUITE_ADD_TEST(suite, TestSuiteWithFrameNew);
|
||||
SUITE_ADD_TEST(suite, TestSuiteRunsSetupTestTeardown);
|
||||
SUITE_ADD_TEST(suite, TestSuiteTestFailsIfSetupFails);
|
||||
SUITE_ADD_TEST(suite, TestSuiteTestFailsIfTeardownFails);
|
||||
SUITE_ADD_TEST(suite, TestSuiteTeardownIsExecutedIfTestFails);
|
||||
SUITE_ADD_TEST(suite, TestSuiteContextPassedToCuTest);
|
||||
SUITE_ADD_TEST(suite, TestSuiteSetupInterruptsUponFailedAssert);
|
||||
SUITE_ADD_TEST(suite, TestSuiteTestInterruptsUponFailedAssert);
|
||||
SUITE_ADD_TEST(suite, TestSuiteTeardownInterruptsUponFailedAssert);
|
||||
SUITE_ADD_TEST(suite, TestSuiteSetupTestTeardownWithContext);
|
||||
|
||||
return suite;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user