diff options
| author | pepper <peppersclothescult@gmail.com> | 2015-01-10 21:32:32 -0800 |
|---|---|---|
| committer | pepper <peppersclothescult@gmail.com> | 2015-01-10 21:32:32 -0800 |
| commit | d53fa8a169832563c62262078b8d2ffe5cab8473 (patch) | |
| tree | b911d06d357d009c976709780f10e92ce915228a /test/unit/TestRunner.h | |
first
Diffstat (limited to 'test/unit/TestRunner.h')
| -rw-r--r-- | test/unit/TestRunner.h | 173 |
1 files changed, 173 insertions, 0 deletions
diff --git a/test/unit/TestRunner.h b/test/unit/TestRunner.h new file mode 100644 index 0000000..597a80a --- /dev/null +++ b/test/unit/TestRunner.h @@ -0,0 +1,173 @@ +#ifndef MrsWatsonTest_TestRunner_h +#define MrsWatsonTest_TestRunner_h + +#include <stdio.h> +#include <string.h> +#include <math.h> + +#include "base/CharString.h" +#include "base/File.h" +#include "logging/LogPrinter.h" + +#if UNIX +#include <unistd.h> +#endif + +#ifndef __func__ +#define __func__ __FUNCTION__ +#endif + +typedef enum { + kTestLogEventSection, + kTestLogEventPass, + kTestLogEventFail, + kTestLogEventSkip, + kTestLogEventReset, + kTestLogEventInvalid +} TestLogEventType; +const LogColor getLogColor(TestLogEventType eventType); + +typedef int (*TestCaseExecFunc)(void); +typedef void (*TestCaseSetupFunc)(void); +typedef void (*TestCaseTeardownFunc)(void); + +typedef struct { + char *name; + char *filename; + int lineNumber; + TestCaseExecFunc testCaseFunc; +} TestCaseMembers; +typedef TestCaseMembers *TestCase; + +typedef struct { + char *name; + int numSuccess; + int numFail; + int numSkips; + LinkedList testCases; + TestCaseSetupFunc setup; + TestCaseTeardownFunc teardown; + boolByte onlyPrintFailing; + boolByte keepFiles; +} TestSuiteMembers; +typedef TestSuiteMembers *TestSuite; + +void addTestToTestSuite(TestSuite testSuite, TestCase testCase); +void runTestSuite(void *testSuitePtr, void *extraData); +void runTestCase(void *item, void *extraData); +void printTestName(const char *testName); +void printTestSuccess(void); +void printTestFail(void); + +TestSuite newTestSuite(char *name, TestCaseSetupFunc setup, TestCaseTeardownFunc teardown); +TestCase newTestCase(char *name, char *filename, int lineNumber, TestCaseExecFunc testCaseFunc); + +void freeTestCase(TestCase self); +void freeTestSuite(TestSuite self); + +static const char *_getFileBasename(const char *filename) +{ + const char *lastDelimiter; + + if (filename == NULL) { + return NULL; + } + + lastDelimiter = strrchr(filename, PATH_DELIMITER); + + if (lastDelimiter == NULL) { + return (char *)filename; + } else { + return lastDelimiter + 1; + } +} + +#define addTest(testSuite, name, testCaseFunc) { \ + addTestToTestSuite(testSuite, newTestCase(name, __FILE__, __LINE__, testCaseFunc)); \ + } + +#define assert(_result) { \ + if(!(_result)) { \ + fprintf(stderr, "\nAssertion failed at %s:%d. ", _getFileBasename(__FILE__), __LINE__); \ + return 1; \ + } \ + } + +#define assertFalse(_result) assert((_result) == false) +#define assertIsNull(_result) assert((_result) == NULL) +#define assertNotNull(_result) assert((_result) != NULL) + +#define assertIntEquals(expected, _result) { \ + int _resultInt = _result; \ + if(_resultInt != expected) { \ + fprintf(stderr, "Assertion failed at %s:%d. Expected %d, got %d. ", _getFileBasename(__FILE__), __LINE__, expected, _resultInt); \ + return 1; \ + } \ + } + +#define assertLongEquals(expected, _result) { \ + long _resultLong = _result; \ + if(_resultLong != expected) { \ + fprintf(stderr, "Assertion failed at %s:%d. Expected %lu, got %lu. ", _getFileBasename(__FILE__), __LINE__, expected, _resultLong); \ + return 1; \ + } \ + } + +#define ZERO_UNSIGNED_LONG (unsigned long)0 +#define assertUnsignedLongEquals(expected, _result) { \ + unsigned long _resultULong = _result; \ + if(_resultULong != expected) { \ + fprintf(stderr, "Assertion failed at %s:%d. Expected %ld, got %ld. ", _getFileBasename(__FILE__), __LINE__, expected, _resultULong); \ + return 1; \ + } \ + } + +#define assertSizeEquals(expected, _result) { \ + size_t _resultSize = _result; \ + if(_result != expected) { \ + fprintf(stderr, "Assertion failed at %s:%d. Expected %zu, got %zu. ", _getFileBasename(__FILE__), __LINE__, expected, _resultSize); \ + return 1; \ + } \ + } + +#define TEST_DEFAULT_TOLERANCE 0.01 +#define TEST_EXACT_TOLERANCE 0.0 + +#define assertDoubleEquals(expected, _result, tolerance) { \ + double resultRounded = floor(_result * 100.0) / 100.0; \ + double expectedRounded = floor(expected * 100.0) / 100.0; \ + double _resultDiff = fabs(resultRounded - expectedRounded); \ + if(_resultDiff > tolerance) { \ + fprintf(stderr, "Assertion failed at %s:%d. Expected %g, got %g. ", _getFileBasename(__FILE__), __LINE__, expectedRounded, resultRounded); \ + return 1; \ + } \ + } + + // Timing assertions fail all the time in debug mode, because the binary is + // running in the debugger, is not optimized, is being profiled, etc. So for + // debug builds, we should not return early here, or else that will cause + // valgrind to go crazy and report a bunch of leaks. +#define assertTimeEquals(expected, _result, tolerance) { \ + double resultRounded = floor(_result * 100.0) / 100.0; \ + double expectedRounded = floor(expected * 100.0) / 100.0; \ + double _resultDiff = fabs(resultRounded - expectedRounded); \ + if(_resultDiff > tolerance) { \ + fprintf(stderr, "Warning: timing assertion failed at %s:%d. Expected %gms, got %gms. ", _getFileBasename(__FILE__), __LINE__, expectedRounded, resultRounded); \ + } \ + } + +#define assertCharStringEquals(expected, _result) { \ + if(!charStringIsEqualToCString(_result, expected, false)) { \ + fprintf(stderr, "Assertion failed at %s:%d. Expected '%s', got '%s'. ", _getFileBasename(__FILE__), __LINE__, expected, _result->data); \ + return 1; \ + } \ + } + +#define assertCharStringContains(expected, _result) { \ + if(strstr(_result->data, expected) == NULL) { \ + fprintf(stderr, "Assertion failed at %s:%d. Expected '%s' to contain '%s'. ", _getFileBasename(__FILE__), __LINE__, _result->data, expected); \ + return 1; \ + } \ + } + +#endif |
