From 1721dc813a1b7f2b1a2313924d78fa12c7db311e Mon Sep 17 00:00:00 2001 From: Jonathan Hoffstadt Date: Fri, 27 Sep 2024 18:45:09 -0500 Subject: [PATCH] feat: pl_test.h 1.0 --- pl_test.h | 298 ++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 201 insertions(+), 97 deletions(-) diff --git a/pl_test.h b/pl_test.h index 30d70a3..d58e2eb 100644 --- a/pl_test.h +++ b/pl_test.h @@ -1,5 +1,5 @@ /* - pl_test + pl_test.h Do this: #define PL_TEST_IMPLEMENTATION before you include this file in *one* C or C++ file to create the implementation. @@ -9,17 +9,22 @@ #include ... #define PL_TEST_IMPLEMENTATION #include "pl_test.h" + Notes: + * for console color output on windows, define "PL_TEST_WIN32_COLOR" before + including the implementation */ -// library version -#define PL_TEST_VERSION "0.1.0" -#define PL_TEST_VERSION_NUM 00100 +// library version (format XYYZZ) +#define PL_TEST_VERSION "1.0.0" +#define PL_TEST_VERSION_NUM 10000 /* Index of this file: // [SECTION] header mess // [SECTION] includes // [SECTION] public api +// [SECTION] structs +// [SECTION] private // [SECTION] c file */ @@ -34,8 +39,8 @@ Index of this file: // [SECTION] includes //----------------------------------------------------------------------------- -#include -#include +#include // bool +#include // uint32_t //----------------------------------------------------------------------------- // [SECTION] forward declarations & basic types @@ -43,6 +48,7 @@ Index of this file: // forward declarations typedef struct _plTestContext plTestContext; +typedef struct _plTestOptions plTestOptions; typedef void (*PL_TEST_FUNCTION)(void*); @@ -52,26 +58,29 @@ typedef void (*PL_TEST_FUNCTION)(void*); #define pl_test_register_test(TEST, DATA) pl__test_register_test((TEST), (DATA), #TEST) - //----------------------------------------------------------------------------- // [SECTION] public api //----------------------------------------------------------------------------- -plTestContext* pl_create_test_context(void); +plTestContext* pl_create_test_context(plTestOptions); // tests -void pl__test_register_test(PL_TEST_FUNCTION tTest, void* pData, const char* pcName); -bool pl_test_run(void); +void pl_test_run_suite(const char* pcSuiteName); +bool pl_test_finish(void); // booleans bool pl_test_expect_true (bool bValue, const char* pcMsg); bool pl_test_expect_false(bool bValue, const char* pcMsg); -// numbers -bool pl_test_expect_int_equal (int iValue0, int iValue1, const char* pcMsg); -bool pl_test_expect_int_not_equal (int iValue0, int iValue1, const char* pcMsg); -bool pl_test_expect_unsigned_equal (uint32_t uValue0, uint32_t uValue1, const char* pcMsg); -bool pl_test_expect_unsigned_not_equal (uint32_t uValue0, uint32_t uValue1, const char* pcMsg); +// integers +bool pl_test_expect_int_equal (int iValue0, int iValue1, const char* pcMsg); +bool pl_test_expect_int_not_equal (int iValue0, int iValue1, const char* pcMsg); +bool pl_test_expect_uint32_equal (uint32_t uValue0, uint32_t uValue1, const char* pcMsg); +bool pl_test_expect_uint32_not_equal(uint32_t uValue0, uint32_t uValue1, const char* pcMsg); +bool pl_test_expect_uint64_equal (uint64_t uValue0, uint64_t uValue1, const char* pcMsg); +bool pl_test_expect_uint64_not_equal(uint64_t uValue0, uint64_t uValue1, const char* pcMsg); + +// floating point bool pl_test_expect_float_near_equal (float fValue0, float fValue1, float fError, const char* pcMsg); bool pl_test_expect_float_near_not_equal (float fValue0, float fValue1, float fError, const char* pcMsg); bool pl_test_expect_double_near_equal (double dValue0, double dValue1, double dError, const char* pcMsg); @@ -81,6 +90,23 @@ bool pl_test_expect_double_near_not_equal(double dValue0, double dValue1, double bool pl_test_expect_string_equal (const char* pcValue0, const char* pcValue1, const char* pcMsg); bool pl_test_expect_string_not_equal(const char* pcValue0, const char* pcValue1, const char* pcMsg); +//----------------------------------------------------------------------------- +// [SECTION] structs +//----------------------------------------------------------------------------- + +typedef struct _plTestOptions +{ + bool bPrintSuiteResults; + bool bPrintAllPassedChecks; + bool bPrintColor; +} plTestOptions; + +//----------------------------------------------------------------------------- +// [SECTION] private +//----------------------------------------------------------------------------- + +void pl__test_register_test(PL_TEST_FUNCTION tTest, void* pData, const char* pcName); + #endif // PL_TEST_H //----------------------------------------------------------------------------- @@ -100,6 +126,13 @@ Index of this file: #ifdef PL_TEST_IMPLEMENTATION +#if defined(PL_TEST_WIN32_COLOR) || defined(_WIN32) + #define WIN32_LEAN_AND_MEAN + #include + static DWORD gtOriginalMode = 0; + static HANDLE gtStdOutHandle = 0; +#endif + //----------------------------------------------------------------------------- // [SECTION] includes //----------------------------------------------------------------------------- @@ -130,12 +163,15 @@ typedef struct _plTest typedef struct _plTestContext { - plTest* atTests; - plTest* ptCurrentTest; - uint32_t uTestSize; - uint32_t uTestCapacity; - uint32_t uFailedTest; - bool bPrintPasses; + plTest* atTests; + plTest* ptCurrentTest; + uint32_t uTestSize; + uint32_t uTestCapacity; + uint32_t uFailedTest; + plTestOptions tOptions; + + uint32_t uTotalPassedTests; + uint32_t uTotalFailedTests; } plTestContext; //----------------------------------------------------------------------------- @@ -149,12 +185,26 @@ plTestContext* gptTestContext = NULL; //----------------------------------------------------------------------------- plTestContext* -pl_create_test_context(void) +pl_create_test_context(plTestOptions tOptions) { + + #if defined(PL_TEST_WIN32_COLOR) || defined(_WIN32) + DWORD tCurrentMode = 0; + gtStdOutHandle = GetStdHandle(STD_OUTPUT_HANDLE); + if(gtStdOutHandle == INVALID_HANDLE_VALUE) + exit(GetLastError()); + if(!GetConsoleMode(gtStdOutHandle, &tCurrentMode)) + exit(GetLastError()); + gtOriginalMode = tCurrentMode; + tCurrentMode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING; // enable ANSI escape codes + if(!SetConsoleMode(gtStdOutHandle, tCurrentMode)) + exit(GetLastError()); + #endif + gptTestContext = (plTestContext*)malloc(sizeof(plTestContext)); memset(gptTestContext, 0, sizeof(plTestContext)); gptTestContext->uTestCapacity = 64; - gptTestContext->bPrintPasses = false; + gptTestContext->tOptions = tOptions; gptTestContext->atTests = (plTest*)malloc(gptTestContext->uTestCapacity * sizeof(plTest)); memset(gptTestContext->atTests, 0, sizeof(gptTestContext->uTestCapacity * sizeof(plTest))); return gptTestContext; @@ -179,30 +229,67 @@ pl__test_register_test(PL_TEST_FUNCTION tTest, void* pData, const char* pcName) gptTestContext->atTests[gptTestContext->uTestSize - 1].pData = pData; } -bool -pl_test_run(void) +void +pl_test_run_suite(const char* pcSuiteName) { + printf("\n------%s suite------\n\n", pcSuiteName); + for(uint32_t i = 0; i < gptTestContext->uTestSize; i++) { gptTestContext->ptCurrentTest = &gptTestContext->atTests[i]; gptTestContext->ptCurrentTest->bFailureOccured = false; - printf("-----------------------------------\n"); - printf("\"%s\" running...\n\n", gptTestContext->ptCurrentTest->pcName); + printf("running -> \"%s\"\n", gptTestContext->ptCurrentTest->pcName); gptTestContext->ptCurrentTest->tTest(gptTestContext->ptCurrentTest->pData); if(gptTestContext->ptCurrentTest->bFailureOccured) { - pl__test_print_red("\n\n\"%s\" failed", NULL, gptTestContext->ptCurrentTest->pcName); + pl__test_print_red("%s", NULL, " -> failed"); gptTestContext->uFailedTest++; } else - printf("\n\n\"%s\" passed\n\n", gptTestContext->ptCurrentTest->pcName); - printf("-----------------------------------\n"); + pl__test_print_green("%s", NULL, " passed"); } - return gptTestContext->uFailedTest == 0; + if(gptTestContext->tOptions.bPrintSuiteResults) + { + printf("\nPassed: "); + pl__test_print_green("%u", NULL, gptTestContext->uTestSize - gptTestContext->uFailedTest); + + printf("Failed: "); + pl__test_print_red("%u", NULL, gptTestContext->uFailedTest); + } + + // printf("\n------End tests------\n\n"); + + // reset context + gptTestContext->uTotalPassedTests += gptTestContext->uTestSize - gptTestContext->uFailedTest; + gptTestContext->uTotalFailedTests += gptTestContext->uFailedTest; + gptTestContext->uTestSize = 0; + gptTestContext->uFailedTest = 0; + gptTestContext->ptCurrentTest = NULL; + memset(gptTestContext->atTests, 0, sizeof(plTest) * gptTestContext->uTestCapacity); +} + +bool +pl_test_finish(void) +{ + + printf("\n------Results------\n"); + + printf("\nTests passed: "); + pl__test_print_green("%u", NULL, gptTestContext->uTotalPassedTests); + + printf("Tests failed: "); + pl__test_print_red("%u", NULL, gptTestContext->uTotalFailedTests); + + #if defined(PL_TEST_WIN32_COLOR) || defined(_WIN32) + if(!SetConsoleMode(gtStdOutHandle, gtOriginalMode)) + exit(GetLastError()); + #endif + + return gptTestContext->uTotalFailedTests == 0; } bool @@ -210,7 +297,8 @@ pl_test_expect_true(bool bValue, const char* pcMsg) { if(bValue) { - pl__test_print_green("Value: true | Expected Value: true", pcMsg); + if(gptTestContext->tOptions.bPrintAllPassedChecks) + pl__test_print_green("Value: true | Expected Value: true", pcMsg); return true; } @@ -229,64 +317,67 @@ pl_test_expect_false(bool bValue, const char* pcMsg) return false; } - pl__test_print_green("Value: false | Expected Value: false", pcMsg); + if(gptTestContext->tOptions.bPrintAllPassedChecks) + pl__test_print_green("Value: false | Expected Value: false", pcMsg); return true; } +#define pl__test_expect_equal(value0, value1, pcMsg, format) \ + if((value0) == (value1)) \ + { \ + if(gptTestContext->tOptions.bPrintAllPassedChecks) \ + pl__test_print_green(format " equals " format " | Equality Expected", (pcMsg), (value0), (value1)); \ + return true; \ + } \ + pl__test_print_red(format " does not equal " format " | Equality Expected", (pcMsg), (value0), (value1)); \ + gptTestContext->ptCurrentTest->bFailureOccured = true; \ + return false; + +#define pl__test_expect_not_equal(value0, value1, pcMsg, format) \ + if((value0) == (value1)) \ + { \ + pl__test_print_red(format " equals " format " | Equality Not Expected", (pcMsg), (value0), (value1)); \ + gptTestContext->ptCurrentTest->bFailureOccured = true; \ + return false; \ + } \ + if(gptTestContext->tOptions.bPrintAllPassedChecks) \ + pl__test_print_green(format " does not equal " format " | Equality Expected", (pcMsg), (value0), (value1)); \ + return true; + bool pl_test_expect_int_equal(int iValue0, int iValue1, const char* pcMsg) { - if(iValue0 == iValue1) - { - pl__test_print_green("%i equals %i | Equality Expected", pcMsg, iValue0, iValue1); - return true; - } - - pl__test_print_red("%i does not equal %i | Equality Expected", pcMsg, iValue0, iValue1); - gptTestContext->ptCurrentTest->bFailureOccured = true; - return false; + pl__test_expect_equal(iValue0, iValue1, pcMsg, "%i"); } bool pl_test_expect_int_not_equal(int iValue0, int iValue1, const char* pcMsg) { - if(iValue0 == iValue1) - { - pl__test_print_red("%i equals %i | Equality Not Expected", pcMsg, iValue0, iValue1); - gptTestContext->ptCurrentTest->bFailureOccured = true; - return false; - } - - pl__test_print_green("%i does not equal %i | Equality Not Expected", pcMsg, iValue0, iValue1); - return true; + pl__test_expect_not_equal(iValue0, iValue1, pcMsg, "%i"); } bool -pl_test_expect_unsigned_equal(uint32_t uValue0, uint32_t uValue1, const char* pcMsg) +pl_test_expect_uint64_equal(uint64_t uValue0, uint64_t uValue1, const char* pcMsg) { - if(uValue0 == uValue1) - { - pl__test_print_green("%u equals %u | Equality Expected", pcMsg, uValue0, uValue1); - return true; - } - - pl__test_print_red("%u does not equal %u | Equality Expected", pcMsg, uValue0, uValue1); - gptTestContext->ptCurrentTest->bFailureOccured = true; - return false; + pl__test_expect_equal(uValue0, uValue1, pcMsg, "%llu"); } bool -pl_test_expect_unsigned_not_equal(uint32_t uValue0, uint32_t uValue1, const char* pcMsg) +pl_test_expect_uint64_not_equal(uint64_t uValue0, uint64_t uValue1, const char* pcMsg) { - if(uValue0 == uValue1) - { - pl__test_print_red("%u equals %u | Equality Not Expected", pcMsg, uValue0, uValue1); - gptTestContext->ptCurrentTest->bFailureOccured = true; - return false; - } + pl__test_expect_not_equal(uValue0, uValue1, pcMsg, "%llu"); +} - pl__test_print_green("%u does not equal %u | Equality Not Expected", pcMsg, uValue0, uValue1); - return true; +bool +pl_test_expect_uint32_equal(uint32_t uValue0, uint32_t uValue1, const char* pcMsg) +{ + pl__test_expect_equal(uValue0, uValue1, pcMsg, "%u"); +} + +bool +pl_test_expect_uint32_not_equal(uint32_t uValue0, uint32_t uValue1, const char* pcMsg) +{ + pl__test_expect_not_equal(uValue0, uValue1, pcMsg, "%u"); } bool @@ -306,7 +397,8 @@ pl_test_expect_double_near_equal(double dValue0, double dValue1, double dError, { if(dValue0 >= dValue1 - dError && dValue0 <= dValue1 + dError) { - pl__test_print_green("%0.6f equals %0.6f | Equality Expected within %0.6f", pcMsg, dValue0, dValue1, dError); + if(gptTestContext->tOptions.bPrintAllPassedChecks) + pl__test_print_green("%0.6f equals %0.6f | Equality Expected within %0.6f", pcMsg, dValue0, dValue1, dError); return true; } @@ -325,7 +417,8 @@ pl_test_expect_double_near_not_equal(double dValue0, double dValue1, double dErr return false; } - pl__test_print_green("%0.6f does not equal %0.6f | Equality Not Expected within %0.6f", pcMsg, dValue0, dValue1, dError); + if(gptTestContext->tOptions.bPrintAllPassedChecks) + pl__test_print_green("%0.6f does not equal %0.6f | Equality Not Expected within %0.6f", pcMsg, dValue0, dValue1, dError); return true; } @@ -334,7 +427,8 @@ pl_test_expect_string_equal(const char* pcValue0, const char* pcValue1, const ch { if(strcmp(pcValue0, pcValue1) == 0) { - pl__test_print_green("\"%s\" equals \"%s\" | Equality Expected", pcMsg, pcValue0, pcValue1); + if(gptTestContext->tOptions.bPrintAllPassedChecks) + pl__test_print_green("\"%s\" equals \"%s\" | Equality Expected", pcMsg, pcValue0, pcValue1); return true; } @@ -348,7 +442,8 @@ pl_test_expect_string_not_equal(const char* pcValue0, const char* pcValue1, cons { if(strcmp(pcValue0, pcValue1) == 0) { - pl__test_print_green("\"%s\" equals \"%s\" | Equality Not Expected", pcMsg, pcValue0, pcValue1); + if(gptTestContext->tOptions.bPrintAllPassedChecks) + pl__test_print_green("\"%s\" equals \"%s\" | Equality Not Expected", pcMsg, pcValue0, pcValue1); gptTestContext->ptCurrentTest->bFailureOccured = true; return false; } @@ -374,11 +469,14 @@ pl__test_print_va(const char* cPFormat, va_list args) void static pl__test_print_red(const char* cPFormat, const char* pcMsg, ...) { - #ifdef _WIN32 - printf(""); - #else - printf("\033[91m"); - #endif + if(gptTestContext->tOptions.bPrintColor) + { + #ifdef _WIN32 + printf(""); + #else + printf("\033[91m"); + #endif + } va_list argptr; va_start(argptr, pcMsg); @@ -390,24 +488,27 @@ pl__test_print_red(const char* cPFormat, const char* pcMsg, ...) else printf("\n"); - #ifdef _WIN32 - printf(""); - #else - printf("\033[0m"); - #endif + if(gptTestContext->tOptions.bPrintColor) + { + #ifdef _WIN32 + printf(""); + #else + printf("\033[0m"); + #endif + } } static void pl__test_print_green(const char* cPFormat, const char* pcMsg, ...) { - if(!gptTestContext->bPrintPasses) - return; - - #ifdef _WIN32 - printf(""); - #else - printf("\033[92m"); - #endif + if(gptTestContext->tOptions.bPrintColor) + { + #ifdef _WIN32 + printf(""); + #else + printf("\033[92m"); + #endif + } va_list argptr; va_start(argptr, pcMsg); @@ -419,11 +520,14 @@ pl__test_print_green(const char* cPFormat, const char* pcMsg, ...) else printf("\n"); - #ifdef _WIN32 - printf(""); - #else - printf("\033[0m"); - #endif + if(gptTestContext->tOptions.bPrintColor) + { + #ifdef _WIN32 + printf(""); + #else + printf("\033[0m"); + #endif + } } #endif // PL_TEST_IMPLEMENTATION \ No newline at end of file