in src/ctest.c [28:284]
size_t RunTests(const TEST_FUNCTION_DATA* testListHead, const char* testSuiteName, bool useLeakCheckRetries)
{
#ifdef USE_VLD
VLD_UINT initial_leak_count = VLDGetLeaksCount();
#endif
size_t totalTestCount = 0;
size_t failedTestCount = 0;
const TEST_FUNCTION_DATA* currentTestFunction = (const TEST_FUNCTION_DATA*)testListHead->NextTestFunctionData;
const TEST_FUNCTION_DATA* testSuiteInitialize = NULL;
const TEST_FUNCTION_DATA* testSuiteCleanup = NULL;
const TEST_FUNCTION_DATA* testFunctionInitialize = NULL;
const TEST_FUNCTION_DATA* testFunctionCleanup = NULL;
int testSuiteInitializeFailed = 0;
#if defined _MSC_VER && !defined(WINCE)
_set_abort_behavior(_CALL_REPORTFAULT, _WRITE_ABORT_MSG | _CALL_REPORTFAULT);
// Set output mode to handle virtual terminal sequences
HANDLE std_out_handle = GetStdHandle(STD_OUTPUT_HANDLE);
bool SetConsoleMode_succeeded = false;
DWORD console_mode_initial = 0;
if (std_out_handle == INVALID_HANDLE_VALUE)
{
LogWarning("Error getting console handle, no coloring available. GetLastError()=%" PRIx32 "", (uint32_t)GetLastError());
}
else
{
if (!GetConsoleMode(std_out_handle, &console_mode_initial))
{
LogWarning("Error getting console mode, no coloring available. GetLastError()=%" PRIx32 "", (uint32_t)GetLastError());
}
else
{
if (!SetConsoleMode(std_out_handle, console_mode_initial | ENABLE_VIRTUAL_TERMINAL_PROCESSING))
{
LogWarning("Error setting console mode, no coloring available. GetLastError()=%" PRIx32 "", (uint32_t)GetLastError());
}
else
{
SetConsoleMode_succeeded = true;
}
}
}
#endif
g_CurrentTestFunction = NULL;
LogInfo(" === Executing test suite %s ===", testSuiteName);
while (currentTestFunction->TestFunction != NULL)
{
if (currentTestFunction->FunctionType == CTEST_TEST_FUNCTION_INITIALIZE)
{
testFunctionInitialize = currentTestFunction;
}
if (currentTestFunction->FunctionType == CTEST_TEST_FUNCTION_CLEANUP)
{
testFunctionCleanup = currentTestFunction;
}
if (currentTestFunction->FunctionType == CTEST_TEST_SUITE_INITIALIZE)
{
testSuiteInitialize = currentTestFunction;
}
if (currentTestFunction->FunctionType == CTEST_TEST_SUITE_CLEANUP)
{
testSuiteCleanup = currentTestFunction;
}
currentTestFunction = (TEST_FUNCTION_DATA*)currentTestFunction->NextTestFunctionData;
}
if (testSuiteInitialize != NULL)
{
if (setjmp(g_ExceptionJump) == 0)
{
testSuiteInitialize->TestFunction();
}
else
{
testSuiteInitializeFailed = 1;
LogInfo("TEST_SUITE_INITIALIZE failed - suite ending");
}
}
if (testSuiteInitializeFailed == 1)
{
/* print results */
LogInfo(CTEST_ANSI_COLOR_RED "0 tests ran, ALL failed, NONE succeeded." CTEST_ANSI_COLOR_RESET);
failedTestCount = 1;
}
else
{
unsigned int is_test_runner_ok = 1;
currentTestFunction = (const TEST_FUNCTION_DATA*)testListHead->NextTestFunctionData;
while (currentTestFunction->TestFunction != NULL)
{
if (currentTestFunction->FunctionType == CTEST_TEST_FUNCTION)
{
if (is_test_runner_ok == 1)
{
int testFunctionInitializeFailed = 0;
if (testFunctionInitialize != NULL)
{
if (setjmp(g_ExceptionJump) == 0)
{
testFunctionInitialize->TestFunction();
}
else
{
testFunctionInitializeFailed = 1;
LogInfo(CTEST_ANSI_COLOR_RED "TEST_FUNCTION_INITIALIZE failed - next TEST_FUNCTION will fail" CTEST_ANSI_COLOR_RESET);
}
}
if (testFunctionInitializeFailed)
{
*currentTestFunction->TestResult = TEST_FAILED;
LogInfo(CTEST_ANSI_COLOR_YELLOW "Not executing test %s ..." CTEST_ANSI_COLOR_RESET, currentTestFunction->TestFunctionName);
}
else
{
LogInfo("Executing test %s ...", currentTestFunction->TestFunctionName);
g_CurrentTestFunction = currentTestFunction;
if (setjmp(g_ExceptionJump) == 0)
{
currentTestFunction->TestFunction();
}
else
{
/*can only get here if there was a longjmp called while executing currentTestFunction->TestFunction();*/
/*we don't do anything*/
}
g_CurrentTestFunction = NULL;/*g_CurrentTestFunction is limited to actually executing a TEST_FUNCTION, otherwise it should be NULL*/
/*in the case when the cleanup can assert... have to prepare the long jump*/
if (setjmp(g_ExceptionJump) == 0)
{
if (testFunctionCleanup != NULL)
{
testFunctionCleanup->TestFunction();
}
}
else
{
/* this is a fatal error, if we got a fail in cleanup we can't do much */
*currentTestFunction->TestResult = TEST_FAILED;
is_test_runner_ok = 0;
}
}
}
else
{
*currentTestFunction->TestResult = TEST_NOT_EXECUTED;
}
if (*currentTestFunction->TestResult == TEST_FAILED)
{
failedTestCount++;
LogInfo(CTEST_ANSI_COLOR_RED "Test %s result = !!! FAILED !!!" CTEST_ANSI_COLOR_RESET, currentTestFunction->TestFunctionName);
}
else if (*currentTestFunction->TestResult == TEST_NOT_EXECUTED)
{
failedTestCount++;
LogInfo(CTEST_ANSI_COLOR_YELLOW "Test %s ... SKIPPED due to a failure in test function cleanup. " CTEST_ANSI_COLOR_RESET, currentTestFunction->TestFunctionName);
}
else
{
LogInfo(CTEST_ANSI_COLOR_GREEN "Test %s result = Succeeded." CTEST_ANSI_COLOR_RESET, currentTestFunction->TestFunctionName);
}
totalTestCount++;
}
currentTestFunction = (TEST_FUNCTION_DATA*)currentTestFunction->NextTestFunctionData;
}
if (setjmp(g_ExceptionJump) == 0)
{
if (testSuiteCleanup != NULL)
{
testSuiteCleanup->TestFunction();
}
}
else
{
/*only get here when testSuiteCleanup did asserted*/
/*should fail the tests*/
LogInfo(CTEST_ANSI_COLOR_RED "TEST_SUITE_CLEANUP failed - all tests are marked as failed" CTEST_ANSI_COLOR_RESET);
failedTestCount = (totalTestCount > 0) ? totalTestCount : SIZE_MAX;
}
/* print results */
LogInfo("%s%d tests ran, %d failed, %d succeeded." CTEST_ANSI_COLOR_RESET, (failedTestCount > 0) ? (CTEST_ANSI_COLOR_RED) : (CTEST_ANSI_COLOR_GREEN), (int)totalTestCount, (int)failedTestCount, (int)(totalTestCount - failedTestCount));
}
#if defined _MSC_VER && !defined(WINCE)
if (std_out_handle != INVALID_HANDLE_VALUE)
{
if (SetConsoleMode_succeeded)
{
/*revert console to initial state*/
if (!SetConsoleMode(std_out_handle, console_mode_initial))
{
LogWarning("Error resetting console mode to initial value of %" PRIx32 ". GetLastError()=%" PRIx32 "", console_mode_initial, GetLastError());
}
}
}
#endif
#ifdef USE_VLD
if (useLeakCheckRetries)
{
if (failedTestCount == 0)
{
VLD_UINT leaks_count = VLDGetLeaksCount();
do
{
if (leaks_count - initial_leak_count > 0)
{
LogWarning("Leaks count is %u (initial count %u)", leaks_count, initial_leak_count);
Sleep(5000);
VLD_UINT new_leaks_count = VLDGetLeaksCount();
if (new_leaks_count == leaks_count)
{
// Leaks are stable so there must be real leaks
LogWarning("Leaks count has not changed...");
break;
}
else
{
// Leaks have gone down, try again
leaks_count = new_leaks_count;
}
}
else
{
// No leaks, we are done
break;
}
} while (1);
}
}
failedTestCount = (failedTestCount > 0) ? failedTestCount : (size_t)(-(int)(VLDGetLeaksCount() - initial_leak_count));
#else
(void)useLeakCheckRetries;
#endif
return failedTestCount;
}