src/test/SDL_test_harness.c
author Andreas Schiffler
Sat, 18 May 2013 09:35:09 -0700
changeset 7189 414be1d64060
parent 6885 700f1b25f77f
child 7191 75360622e65f
permissions -rw-r--r--
Update test harness to handle test return codes; fix comment format in harness; update Main test suite to handle globally disabled features
aschiffler@6717
     1
/*
aschiffler@6763
     2
Simple DirectMedia Layer
slouken@6885
     3
Copyright (C) 1997-2013 Sam Lantinga <slouken@libsdl.org>
aschiffler@6717
     4
aschiffler@6763
     5
This software is provided 'as-is', without any express or implied
aschiffler@6763
     6
warranty.  In no event will the authors be held liable for any damages
aschiffler@6763
     7
arising from the use of this software.
aschiffler@6717
     8
aschiffler@6763
     9
Permission is granted to anyone to use this software for any purpose,
aschiffler@6763
    10
including commercial applications, and to alter it and redistribute it
aschiffler@6763
    11
freely, subject to the following restrictions:
aschiffler@6717
    12
aschiffler@6763
    13
1. The origin of this software must not be misrepresented; you must not
aschiffler@6763
    14
claim that you wrote the original software. If you use this software
aschiffler@6763
    15
in a product, an acknowledgment in the product documentation would be
aschiffler@6763
    16
appreciated but is not required.
aschiffler@6763
    17
2. Altered source versions must be plainly marked as such, and must not be
aschiffler@6763
    18
misrepresented as being the original software.
aschiffler@6763
    19
3. This notice may not be removed or altered from any source distribution.
aschiffler@6717
    20
*/
aschiffler@6717
    21
aschiffler@6717
    22
#include "SDL_config.h"
aschiffler@6717
    23
aschiffler@6717
    24
#include "SDL_test.h"
aschiffler@6717
    25
aschiffler@6721
    26
#include <stdio.h>
aschiffler@6721
    27
#include <stdlib.h>
aschiffler@6718
    28
#include <string.h>
aschiffler@6721
    29
#include <time.h>
aschiffler@6718
    30
aschiffler@6756
    31
/* Invalid test name/description message format */
aschiffler@6756
    32
const char *SDLTest_InvalidNameFormat = "(Invalid)";
aschiffler@6721
    33
aschiffler@6756
    34
/* Log summary message format */
aschiffler@6756
    35
const char *SDLTest_LogSummaryFormat = "%s Summary: Total=%d Passed=%d Failed=%d Skipped=%d";
aschiffler@6756
    36
aschiffler@6756
    37
/* Final result message format */
aschiffler@6756
    38
const char *SDLTest_FinalResultFormat = ">>> %s '%s': %s\n";
aschiffler@6721
    39
aschiffler@6721
    40
/*! \brief Timeout for single test case execution */
aschiffler@6721
    41
static Uint32 SDLTest_TestCaseTimeout = 3600;
aschiffler@6717
    42
aschiffler@6717
    43
/**
aschiffler@6763
    44
* Generates a random run seed string for the harness. The generated seed
aschiffler@6763
    45
* will contain alphanumeric characters (0-9A-Z).
aschiffler@6763
    46
*
aschiffler@6763
    47
* Note: The returned string needs to be deallocated by the caller.
aschiffler@6763
    48
*
aschiffler@6763
    49
* \param length The length of the seed string to generate
aschiffler@6763
    50
*
aschiffler@6763
    51
* \returns The generated seed string
aschiffler@6763
    52
*/
aschiffler@6717
    53
char *
aschiffler@6772
    54
SDLTest_GenerateRunSeed(const int length)
aschiffler@6717
    55
{
aschiffler@6717
    56
	char *seed = NULL;
aschiffler@6717
    57
	SDLTest_RandomContext randomContext;
aschiffler@6717
    58
	int counter;
aschiffler@6717
    59
aschiffler@7189
    60
	/* Sanity check input */
aschiffler@6717
    61
	if (length <= 0) {
aschiffler@6717
    62
		SDLTest_LogError("The length of the harness seed must be >0.");
aschiffler@6717
    63
		return NULL;
aschiffler@6717
    64
	}
aschiffler@6717
    65
aschiffler@7189
    66
	/* Allocate output buffer */
aschiffler@6717
    67
	seed = (char *)SDL_malloc((length + 1) * sizeof(char));
aschiffler@6717
    68
	if (seed == NULL) {
aschiffler@6717
    69
		SDLTest_LogError("SDL_malloc for run seed output buffer failed.");
aschiffler@6717
    70
		return NULL;
aschiffler@6717
    71
	}
aschiffler@6717
    72
aschiffler@7189
    73
	/* Generate a random string of alphanumeric characters */
aschiffler@6717
    74
	SDLTest_RandomInitTime(&randomContext);
aschiffler@6717
    75
	for (counter = 0; counter < length - 1; ++counter) {
aschiffler@6717
    76
		unsigned int number = SDLTest_Random(&randomContext);
aschiffler@6717
    77
		char ch = (char) (number % (91 - 48)) + 48;
aschiffler@6717
    78
		if (ch >= 58 && ch <= 64) {
aschiffler@6717
    79
			ch = 65;
aschiffler@6717
    80
		}
aschiffler@6717
    81
		seed[counter] = ch;
aschiffler@6717
    82
	}
aschiffler@6717
    83
	seed[counter] = '\0';
aschiffler@6717
    84
aschiffler@6717
    85
	return seed;
aschiffler@6717
    86
}
aschiffler@6717
    87
aschiffler@6717
    88
/**
aschiffler@6763
    89
* Generates an execution key for the fuzzer.
aschiffler@6763
    90
*
aschiffler@6763
    91
* \param runSeed		The run seed to use
aschiffler@6763
    92
* \param suiteName		The name of the test suite
aschiffler@6763
    93
* \param testName		The name of the test
aschiffler@6763
    94
* \param iteration		The iteration count
aschiffler@6763
    95
*
aschiffler@6763
    96
* \returns The generated execution key to initialize the fuzzer with.
aschiffler@6763
    97
*
aschiffler@6763
    98
*/
aschiffler@6717
    99
Uint64
aschiffler@6772
   100
SDLTest_GenerateExecKey(char *runSeed, char *suiteName, char *testName, int iteration)
aschiffler@6717
   101
{
aschiffler@6717
   102
	SDLTest_Md5Context md5Context;
aschiffler@6717
   103
	Uint64 *keys;
aschiffler@6717
   104
	char iterationString[16];
aschiffler@6717
   105
	Uint32 runSeedLength;
aschiffler@6717
   106
	Uint32 suiteNameLength;
aschiffler@6717
   107
	Uint32 testNameLength;
aschiffler@6717
   108
	Uint32 iterationStringLength;
aschiffler@6717
   109
	Uint32 entireStringLength;
aschiffler@6717
   110
	char *buffer;
aschiffler@6717
   111
aschiffler@6772
   112
	if (runSeed == NULL || SDL_strlen(runSeed)==0) {
aschiffler@6717
   113
		SDLTest_LogError("Invalid runSeed string.");
aschiffler@6717
   114
		return -1;
aschiffler@6717
   115
	}
aschiffler@6717
   116
aschiffler@6772
   117
	if (suiteName == NULL || SDL_strlen(suiteName)==0) {
aschiffler@6717
   118
		SDLTest_LogError("Invalid suiteName string.");
aschiffler@6717
   119
		return -1;
aschiffler@6717
   120
	}
aschiffler@6717
   121
aschiffler@6772
   122
	if (testName == NULL || SDL_strlen(testName)==0) {
aschiffler@6717
   123
		SDLTest_LogError("Invalid testName string.");
aschiffler@6717
   124
		return -1;
aschiffler@6717
   125
	}
aschiffler@6717
   126
aschiffler@6717
   127
	if (iteration <= 0) {
aschiffler@6717
   128
		SDLTest_LogError("Invalid iteration count.");
aschiffler@6717
   129
		return -1;
aschiffler@6717
   130
	}
aschiffler@6717
   131
aschiffler@7189
   132
	/* Convert iteration number into a string */
aschiffler@6772
   133
	SDL_memset(iterationString, 0, sizeof(iterationString));
aschiffler@6717
   134
	SDL_snprintf(iterationString, sizeof(iterationString) - 1, "%d", iteration);
aschiffler@6717
   135
aschiffler@7189
   136
	/* Combine the parameters into single string */
aschiffler@6772
   137
	runSeedLength = SDL_strlen(runSeed);
aschiffler@6772
   138
	suiteNameLength = SDL_strlen(suiteName);
aschiffler@6772
   139
	testNameLength = SDL_strlen(testName);
aschiffler@6772
   140
	iterationStringLength = SDL_strlen(iterationString);
aschiffler@6717
   141
	entireStringLength  = runSeedLength + suiteNameLength + testNameLength + iterationStringLength + 1;
aschiffler@6717
   142
	buffer = (char *)SDL_malloc(entireStringLength);
aschiffler@6717
   143
	if (buffer == NULL) {
aschiffler@6717
   144
		SDLTest_LogError("SDL_malloc failed to allocate buffer for execKey generation.");
aschiffler@6717
   145
		return 0;
aschiffler@6717
   146
	}
aschiffler@6717
   147
	SDL_snprintf(buffer, entireStringLength, "%s%s%s%d", runSeed, suiteName, testName, iteration);
aschiffler@6717
   148
aschiffler@7189
   149
	/* Hash string and use half of the digest as 64bit exec key */
aschiffler@6717
   150
	SDLTest_Md5Init(&md5Context);
aschiffler@6717
   151
	SDLTest_Md5Update(&md5Context, (unsigned char *)buffer, entireStringLength);
aschiffler@6717
   152
	SDLTest_Md5Final(&md5Context);
aschiffler@6717
   153
	SDL_free(buffer);
aschiffler@6717
   154
	keys = (Uint64 *)md5Context.digest;
aschiffler@6717
   155
aschiffler@6717
   156
	return keys[0];
aschiffler@6717
   157
}
aschiffler@6718
   158
aschiffler@6718
   159
/**
aschiffler@6763
   160
* \brief Set timeout handler for test.
aschiffler@6763
   161
*
aschiffler@6763
   162
* Note: SDL_Init(SDL_INIT_TIMER) will be called if it wasn't done so before.
aschiffler@6763
   163
*
aschiffler@6763
   164
* \param timeout Timeout interval in seconds.
aschiffler@6763
   165
* \param callback Function that will be called after timeout has elapsed.
aschiffler@6763
   166
* 
aschiffler@6763
   167
* \return Timer id or -1 on failure.
aschiffler@6763
   168
*/
aschiffler@6718
   169
SDL_TimerID
aschiffler@6772
   170
SDLTest_SetTestTimeout(int timeout, void (*callback)())
aschiffler@6718
   171
{
aschiffler@6718
   172
	Uint32 timeoutInMilliseconds;
aschiffler@6718
   173
	SDL_TimerID timerID;
aschiffler@6718
   174
aschiffler@6718
   175
	if (callback == NULL) {
aschiffler@6718
   176
		SDLTest_LogError("Timeout callback can't be NULL");
aschiffler@6718
   177
		return -1;
aschiffler@6718
   178
	}
aschiffler@6718
   179
aschiffler@6718
   180
	if (timeout < 0) {
aschiffler@6718
   181
		SDLTest_LogError("Timeout value must be bigger than zero.");
aschiffler@6718
   182
		return -1;
aschiffler@6718
   183
	}
aschiffler@6718
   184
aschiffler@6718
   185
	/* Init SDL timer if not initialized before */
aschiffler@6718
   186
	if (SDL_WasInit(SDL_INIT_TIMER) == 0) {
aschiffler@6718
   187
		if (SDL_InitSubSystem(SDL_INIT_TIMER)) {
aschiffler@6718
   188
			SDLTest_LogError("Failed to init timer subsystem: %s", SDL_GetError());
aschiffler@6718
   189
			return -1;
aschiffler@6718
   190
		}
aschiffler@6718
   191
	}
aschiffler@6718
   192
aschiffler@6718
   193
	/* Set timer */
aschiffler@6718
   194
	timeoutInMilliseconds = timeout * 1000;
aschiffler@6718
   195
	timerID = SDL_AddTimer(timeoutInMilliseconds, (SDL_TimerCallback)callback, 0x0);
aschiffler@6718
   196
	if (timerID == 0) {
aschiffler@6718
   197
		SDLTest_LogError("Creation of SDL timer failed: %s", SDL_GetError());
aschiffler@6718
   198
		return -1;
aschiffler@6718
   199
	}
aschiffler@6718
   200
aschiffler@6718
   201
	return timerID;
aschiffler@6718
   202
}
aschiffler@6721
   203
aschiffler@6763
   204
/**
aschiffler@6763
   205
* \brief Timeout handler. Aborts test run and exits harness process.
aschiffler@6763
   206
*/
aschiffler@6721
   207
void
aschiffler@6763
   208
	SDLTest_BailOut()
aschiffler@6721
   209
{
aschiffler@6721
   210
	SDLTest_LogError("TestCaseTimeout timer expired. Aborting test run.");
aschiffler@7189
   211
	exit(TEST_ABORTED); /* bail out from the test */
aschiffler@6721
   212
}
aschiffler@6721
   213
aschiffler@6721
   214
/**
aschiffler@6763
   215
* \brief Execute a test using the given execution key.
aschiffler@6763
   216
*
aschiffler@6763
   217
* \param testSuite Suite containing the test case.
aschiffler@6763
   218
* \param testCase Case to execute.
aschiffler@6763
   219
* \param execKey Execution key for the fuzzer.
aschiffler@6763
   220
*
aschiffler@6763
   221
* \returns Test case result.
aschiffler@6763
   222
*/
aschiffler@6721
   223
int
aschiffler@6830
   224
SDLTest_RunTest(SDLTest_TestSuiteReference *testSuite, SDLTest_TestCaseReference *testCase, Uint64 execKey)
aschiffler@6721
   225
{
aschiffler@6721
   226
	SDL_TimerID timer = 0;
aschiffler@7189
   227
	int testCaseResult = 0;
aschiffler@6727
   228
	int testResult = 0;
aschiffler@6757
   229
	int fuzzerCount;
aschiffler@6721
   230
aschiffler@6721
   231
	if (testSuite==NULL || testCase==NULL || testSuite->name==NULL || testCase->name==NULL)
aschiffler@6721
   232
	{
aschiffler@6721
   233
		SDLTest_LogError("Setup failure: testSuite or testCase references NULL");
aschiffler@6721
   234
		return TEST_RESULT_SETUP_FAILURE;
aschiffler@6721
   235
	}
aschiffler@6721
   236
aschiffler@6721
   237
	if (!testCase->enabled)
aschiffler@6721
   238
	{
aschiffler@6763
   239
		SDLTest_Log((char *)SDLTest_FinalResultFormat, "Test", testCase->name, "Skipped (Disabled)");
aschiffler@6721
   240
		return TEST_RESULT_SKIPPED;
aschiffler@6721
   241
	}
aschiffler@6721
   242
aschiffler@6763
   243
aschiffler@7189
   244
	/* Initialize fuzzer */
aschiffler@6721
   245
	SDLTest_FuzzerInit(execKey);
aschiffler@6721
   246
aschiffler@7189
   247
	/* Reset assert tracker */
aschiffler@6721
   248
	SDLTest_ResetAssertSummary();
aschiffler@6721
   249
aschiffler@7189
   250
	/* Set timeout timer */
aschiffler@6721
   251
	timer = SDLTest_SetTestTimeout(SDLTest_TestCaseTimeout, SDLTest_BailOut);
aschiffler@6721
   252
aschiffler@7189
   253
	/* Maybe run suite initalizer function */
aschiffler@6721
   254
	if (testSuite->testSetUp) {
aschiffler@6721
   255
		testSuite->testSetUp(0x0);
aschiffler@6727
   256
		if (SDLTest_AssertSummaryToTestResult() == TEST_RESULT_FAILED) {
aschiffler@6756
   257
			SDLTest_LogError((char *)SDLTest_FinalResultFormat, "Suite Setup", testSuite->name, "Failed");
aschiffler@6721
   258
			return TEST_RESULT_SETUP_FAILURE;
aschiffler@6721
   259
		}
aschiffler@6721
   260
	}
aschiffler@6721
   261
aschiffler@7189
   262
	/* Run test case function */
aschiffler@7189
   263
	testCaseResult = testCase->testCase(0x0);
aschiffler@7189
   264
	
aschiffler@7189
   265
	/* Convert test execution result into harness result */
aschiffler@7189
   266
	if (testCaseResult == TEST_SKIPPED) {
aschiffler@7189
   267
		/* Test was programatically skipped */
aschiffler@7189
   268
		testResult = TEST_RESULT_SKIPPED;
aschiffler@7189
   269
	} else if (testCaseResult == TEST_STARTED) {
aschiffler@7189
   270
		/* Test did not return a TEST_COMPLETED value; assume it failed */
aschiffler@7189
   271
		testResult = TEST_RESULT_FAILED;
aschiffler@7189
   272
	} else if (testCaseResult == TEST_ABORTED) {
aschiffler@7189
   273
		/* Test was aborted early; assume it failed */
aschiffler@7189
   274
		testResult = TEST_RESULT_FAILED;
aschiffler@7189
   275
	} else {
aschiffler@7189
   276
		/* Perform failure analysis based on asserts */
aschiffler@7189
   277
		testResult = SDLTest_AssertSummaryToTestResult();
aschiffler@7189
   278
	}
aschiffler@6721
   279
aschiffler@7189
   280
	/* Maybe run suite cleanup function (ignore failed asserts) */
aschiffler@6721
   281
	if (testSuite->testTearDown) {
aschiffler@6721
   282
		testSuite->testTearDown(0x0);
aschiffler@6721
   283
	}
aschiffler@6721
   284
aschiffler@7189
   285
	/* Cancel timeout timer */
aschiffler@6721
   286
	if (timer) {
aschiffler@6721
   287
		SDL_RemoveTimer(timer);
aschiffler@6721
   288
	}
aschiffler@6721
   289
aschiffler@7189
   290
	/* Report on asserts and fuzzer usage */
aschiffler@6757
   291
	fuzzerCount = SDLTest_GetFuzzerInvocationCount();
aschiffler@6757
   292
	if (fuzzerCount > 0) {
aschiffler@6757
   293
		SDLTest_Log("Fuzzer invocations: %d", fuzzerCount);
aschiffler@6757
   294
	}
aschiffler@7189
   295
aschiffler@7189
   296
	/* Final log based on test execution result */
aschiffler@7189
   297
	if (testCaseResult == TEST_SKIPPED) {
aschiffler@7189
   298
		/* Test was programatically skipped */
aschiffler@7189
   299
		SDLTest_Log((char *)SDLTest_FinalResultFormat, "Test", testCase->name, "Skipped (Programmatically)");
aschiffler@7189
   300
	} else if (testCaseResult == TEST_STARTED) {
aschiffler@7189
   301
		/* Test did not return a TEST_COMPLETED value; assume it failed */
aschiffler@7189
   302
		SDLTest_LogError((char *)SDLTest_FinalResultFormat, "Test", testCase->name, "Failed (test started, but did not return TEST_COMPLETED)");
aschiffler@7189
   303
	} else if (testCaseResult == TEST_ABORTED) {
aschiffler@7189
   304
		/* Test was aborted early; assume it failed */
aschiffler@7189
   305
		SDLTest_LogError((char *)SDLTest_FinalResultFormat, "Test", testCase->name, "Failed (Aborted)");
aschiffler@7189
   306
	} else {
aschiffler@7189
   307
		SDLTest_LogAssertSummary();
aschiffler@7189
   308
	}
aschiffler@6721
   309
aschiffler@6727
   310
	return testResult;
aschiffler@6721
   311
}
aschiffler@6721
   312
aschiffler@6721
   313
/* Prints summary of all suites/tests contained in the given reference */
aschiffler@6721
   314
void SDLTest_LogTestSuiteSummary(SDLTest_TestSuiteReference *testSuites)
aschiffler@6721
   315
{
aschiffler@6721
   316
	int suiteCounter;
aschiffler@6721
   317
	int testCounter;
aschiffler@6721
   318
	SDLTest_TestSuiteReference *testSuite;
aschiffler@6721
   319
	SDLTest_TestCaseReference *testCase;
aschiffler@6721
   320
aschiffler@7189
   321
	/* Loop over all suites */
aschiffler@6721
   322
	suiteCounter = 0;
aschiffler@6721
   323
	while(&testSuites[suiteCounter]) {
aschiffler@6721
   324
		testSuite=&testSuites[suiteCounter];
aschiffler@6721
   325
		suiteCounter++;
aschiffler@6721
   326
		SDLTest_Log("Test Suite %i - %s\n", suiteCounter, 
aschiffler@6756
   327
			(testSuite->name) ? testSuite->name : SDLTest_InvalidNameFormat);
aschiffler@6721
   328
aschiffler@7189
   329
		/* Loop over all test cases */
aschiffler@6721
   330
		testCounter = 0;
aschiffler@6721
   331
		while(testSuite->testCases[testCounter])
aschiffler@6721
   332
		{
aschiffler@6721
   333
			testCase=(SDLTest_TestCaseReference *)testSuite->testCases[testCounter];
aschiffler@6721
   334
			testCounter++;
aschiffler@6721
   335
			SDLTest_Log("  Test Case %i - %s: %s", testCounter, 
aschiffler@6756
   336
				(testCase->name) ? testCase->name : SDLTest_InvalidNameFormat, 
aschiffler@6756
   337
				(testCase->description) ? testCase->description : SDLTest_InvalidNameFormat);
aschiffler@6721
   338
		}
aschiffler@6721
   339
	}
aschiffler@6721
   340
}
aschiffler@6721
   341
aschiffler@6756
   342
/* Gets a timer value in seconds */
aschiffler@6756
   343
float GetClock()
aschiffler@6756
   344
{
aschiffler@6756
   345
	float currentClock = (float)clock();
aschiffler@6756
   346
	return currentClock / (float)CLOCKS_PER_SEC;
aschiffler@6756
   347
}
aschiffler@6721
   348
aschiffler@6721
   349
/**
aschiffler@6763
   350
* \brief Execute a test suite using the given run seend and execution key.
aschiffler@6763
   351
*
aschiffler@6763
   352
* The filter string is matched to the suite name (full comparison) to select a single suite,
aschiffler@6763
   353
* or if no suite matches, it is matched to the test names (full comparison) to select a single test.
aschiffler@6763
   354
*
aschiffler@6763
   355
* \param testSuites Suites containing the test case.
aschiffler@6763
   356
* \param userRunSeed Custom run seed provided by user, or NULL to autogenerate one.
aschiffler@6763
   357
* \param userExecKey Custom execution key provided by user, or 0 to autogenerate one.
aschiffler@6763
   358
* \param filter Filter specification. NULL disables. Case sensitive.
aschiffler@6763
   359
* \param testIterations Number of iterations to run each test case.
aschiffler@6763
   360
*
aschiffler@6763
   361
* \returns Test run result; 0 when all tests passed, 1 if any tests failed.
aschiffler@6763
   362
*/
slouken@6768
   363
int SDLTest_RunSuites(SDLTest_TestSuiteReference *testSuites[], const char *userRunSeed, Uint64 userExecKey, const char *filter, int testIterations)
aschiffler@6721
   364
{
aschiffler@6721
   365
	int suiteCounter;
aschiffler@6721
   366
	int testCounter;
aschiffler@6721
   367
	int iterationCounter;
aschiffler@6721
   368
	SDLTest_TestSuiteReference *testSuite;
aschiffler@6721
   369
	SDLTest_TestCaseReference *testCase;
slouken@6768
   370
	const char *runSeed = NULL;
aschiffler@6756
   371
	char *currentSuiteName;
aschiffler@6756
   372
	char *currentTestName;
aschiffler@6721
   373
	Uint64 execKey;
aschiffler@6756
   374
	float runStartSeconds;
aschiffler@6756
   375
	float suiteStartSeconds;
aschiffler@6756
   376
	float testStartSeconds;
aschiffler@6756
   377
	float runEndSeconds;
aschiffler@6756
   378
	float suiteEndSeconds;
aschiffler@6756
   379
	float testEndSeconds;
aschiffler@6760
   380
	float runtime;
aschiffler@6763
   381
	int suiteFilter = 0;
aschiffler@6763
   382
	char *suiteFilterName = NULL;
aschiffler@6763
   383
	int testFilter = 0;
aschiffler@6763
   384
	char *testFilterName = NULL;
aschiffler@6756
   385
	int testResult = 0;
aschiffler@6756
   386
	int runResult = 0;
aschiffler@6756
   387
	Uint32 totalTestFailedCount = 0;
aschiffler@6756
   388
	Uint32 totalTestPassedCount = 0;
aschiffler@6756
   389
	Uint32 totalTestSkippedCount = 0;
aschiffler@6756
   390
	Uint32 testFailedCount = 0;
aschiffler@6756
   391
	Uint32 testPassedCount = 0;
aschiffler@6756
   392
	Uint32 testSkippedCount = 0;
aschiffler@6756
   393
	Uint32 countSum = 0;
aschiffler@6756
   394
	char *logFormat = (char *)SDLTest_LogSummaryFormat;
aschiffler@6721
   395
aschiffler@7189
   396
	/* Sanitize test iterations */
aschiffler@6721
   397
	if (testIterations < 1) {
aschiffler@6721
   398
		testIterations = 1;
aschiffler@6721
   399
	}
aschiffler@6721
   400
aschiffler@7189
   401
	/* Generate run see if we don't have one already */
aschiffler@6772
   402
	if (userRunSeed == NULL || SDL_strlen(userRunSeed) == 0) {
aschiffler@6721
   403
		runSeed = SDLTest_GenerateRunSeed(16);
aschiffler@6721
   404
		if (runSeed == NULL) {
aschiffler@6756
   405
			SDLTest_LogError("Generating a random seed failed");
aschiffler@6721
   406
			return 2;
aschiffler@6721
   407
		}
aschiffler@6757
   408
	} else {
aschiffler@6757
   409
		runSeed = userRunSeed;
aschiffler@6721
   410
	}
aschiffler@6721
   411
aschiffler@6763
   412
aschiffler@7189
   413
	/* Reset per-run counters */
aschiffler@6756
   414
	totalTestFailedCount = 0;
aschiffler@6756
   415
	totalTestPassedCount = 0;
aschiffler@6756
   416
	totalTestSkippedCount = 0;
aschiffler@6721
   417
aschiffler@7189
   418
	/* Take time - run start */
aschiffler@6756
   419
	runStartSeconds = GetClock();
aschiffler@6721
   420
aschiffler@7189
   421
	/* Log run with fuzzer parameters */
aschiffler@6757
   422
	SDLTest_Log("::::: Test Run /w seed '%s' started\n", runSeed);
aschiffler@6721
   423
aschiffler@7189
   424
	/* Initialize filtering */
aschiffler@6763
   425
	if (filter != NULL && SDL_strlen(filter) > 0) {
aschiffler@6763
   426
		/* Loop over all suites to check if we have a filter match */
aschiffler@6763
   427
		suiteCounter = 0;
aschiffler@6763
   428
		while (testSuites[suiteCounter] && suiteFilter == 0) {
aschiffler@6763
   429
			testSuite=(SDLTest_TestSuiteReference *)testSuites[suiteCounter];
aschiffler@6763
   430
			suiteCounter++;
aschiffler@6763
   431
			if (testSuite->name != NULL && SDL_strcmp(filter, testSuite->name) == 0) {
aschiffler@6763
   432
				/* Matched a suite name */
aschiffler@6763
   433
				suiteFilter = 1;
aschiffler@6763
   434
				suiteFilterName = testSuite->name;
aschiffler@6763
   435
				SDLTest_Log("Filtering: running only suite '%s'", suiteFilterName);
aschiffler@6763
   436
				break;
aschiffler@6763
   437
			}
aschiffler@6763
   438
aschiffler@6763
   439
			/* Within each suite, loop over all test cases to check if we have a filter match */
aschiffler@6763
   440
			testCounter = 0;
aschiffler@6763
   441
			while (testSuite->testCases[testCounter] && testFilter == 0)
aschiffler@6763
   442
			{
aschiffler@6763
   443
				testCase=(SDLTest_TestCaseReference *)testSuite->testCases[testCounter];
aschiffler@6763
   444
				testCounter++;
aschiffler@6763
   445
				if (testCase->name != NULL && SDL_strcmp(filter, testCase->name) == 0) {
aschiffler@6763
   446
					/* Matched a test name */
aschiffler@6763
   447
					suiteFilter = 1;
aschiffler@6763
   448
					suiteFilterName = testSuite->name;
aschiffler@6763
   449
					testFilter = 1;
aschiffler@6763
   450
					testFilterName = testCase->name;
aschiffler@6763
   451
					SDLTest_Log("Filtering: running only test '%s' in suite '%s'", testFilterName, suiteFilterName);					
aschiffler@6763
   452
					break;
aschiffler@6763
   453
				}
aschiffler@6763
   454
			}						
aschiffler@6763
   455
		}
aschiffler@6763
   456
		
aschiffler@6763
   457
		if (suiteFilter == 0 && testFilter == 0) {
aschiffler@6763
   458
			SDLTest_LogError("Filter '%s' did not match any test suite/case.", filter);
aschiffler@6763
   459
			SDLTest_Log("Exit code: 2");	
aschiffler@6763
   460
			return 2;
aschiffler@6763
   461
		}		
aschiffler@6763
   462
	}
aschiffler@6763
   463
aschiffler@7189
   464
	/* Loop over all suites */
aschiffler@6721
   465
	suiteCounter = 0;
aschiffler@6756
   466
	while(testSuites[suiteCounter]) {
aschiffler@6756
   467
		testSuite=(SDLTest_TestSuiteReference *)testSuites[suiteCounter];
aschiffler@6763
   468
		currentSuiteName = (char *)((testSuite->name) ? testSuite->name : SDLTest_InvalidNameFormat);
aschiffler@6721
   469
		suiteCounter++;
aschiffler@6721
   470
aschiffler@7189
   471
		/* Filter suite if flag set and we have a name */
aschiffler@6763
   472
		if (suiteFilter == 1 && suiteFilterName != NULL && testSuite->name != NULL &&
aschiffler@6763
   473
			SDL_strcmp(suiteFilterName, testSuite->name) != 0) {
aschiffler@7189
   474
				/* Skip suite */
aschiffler@6763
   475
				SDLTest_Log("===== Test Suite %i: '%s' skipped\n", 
aschiffler@6763
   476
					suiteCounter, 
aschiffler@6763
   477
					currentSuiteName);
aschiffler@6763
   478
		} else {
aschiffler@6721
   479
aschiffler@7189
   480
			/* Reset per-suite counters */
aschiffler@6763
   481
			testFailedCount = 0;
aschiffler@6763
   482
			testPassedCount = 0;
aschiffler@6763
   483
			testSkippedCount = 0;
aschiffler@6763
   484
aschiffler@7189
   485
			/* Take time - suite start */
aschiffler@6763
   486
			suiteStartSeconds = GetClock();
aschiffler@6763
   487
aschiffler@7189
   488
			/* Log suite started */
aschiffler@6763
   489
			SDLTest_Log("===== Test Suite %i: '%s' started\n", 
aschiffler@6763
   490
				suiteCounter, 
aschiffler@6763
   491
				currentSuiteName);
aschiffler@6721
   492
aschiffler@7189
   493
			/* Loop over all test cases */
aschiffler@6763
   494
			testCounter = 0;
aschiffler@6763
   495
			while(testSuite->testCases[testCounter])
aschiffler@6763
   496
			{
aschiffler@6763
   497
				testCase=(SDLTest_TestCaseReference *)testSuite->testCases[testCounter];
aschiffler@6763
   498
				currentTestName = (char *)((testCase->name) ? testCase->name : SDLTest_InvalidNameFormat);
aschiffler@6763
   499
				testCounter++;
aschiffler@6721
   500
aschiffler@7189
   501
				/* Filter tests if flag set and we have a name */
aschiffler@6763
   502
				if (testFilter == 1 && testFilterName != NULL && testCase->name != NULL &&
aschiffler@6763
   503
					SDL_strcmp(testFilterName, testCase->name) != 0) {
aschiffler@7189
   504
						/* Skip test */
aschiffler@6763
   505
						SDLTest_Log("===== Test Case %i.%i: '%s' skipped\n", 
aschiffler@6763
   506
							suiteCounter,
aschiffler@6763
   507
							testCounter,
aschiffler@6763
   508
							currentTestName);
aschiffler@6763
   509
				} else {
aschiffler@7189
   510
					/* Override 'disabled' flag if we specified a test filter (i.e. force run for debugging) */
aschiffler@6830
   511
					if (testFilter == 1 && !testCase->enabled) {
aschiffler@6830
   512
						SDLTest_Log("Force run of disabled test since test filter was set");
aschiffler@6830
   513
						testCase->enabled = 1;
aschiffler@6830
   514
					}
aschiffler@6763
   515
aschiffler@7189
   516
					/* Take time - test start */
aschiffler@6763
   517
					testStartSeconds = GetClock();
aschiffler@6763
   518
aschiffler@7189
   519
					/* Log test started */
aschiffler@6763
   520
					SDLTest_Log("----- Test Case %i.%i: '%s' started",
aschiffler@6763
   521
						suiteCounter,
aschiffler@6763
   522
						testCounter, 
aschiffler@6763
   523
						currentTestName);
aschiffler@6772
   524
					if (testCase->description != NULL && SDL_strlen(testCase->description)>0) {
aschiffler@6763
   525
						SDLTest_Log("Test Description: '%s'", 
aschiffler@6763
   526
							(testCase->description) ? testCase->description : SDLTest_InvalidNameFormat);
aschiffler@6763
   527
					}
aschiffler@6721
   528
aschiffler@7189
   529
					/* Loop over all iterations */
aschiffler@6763
   530
					iterationCounter = 0;
aschiffler@6763
   531
					while(iterationCounter < testIterations)
aschiffler@6763
   532
					{
aschiffler@6763
   533
						iterationCounter++;
aschiffler@6763
   534
aschiffler@6763
   535
						if (userExecKey != 0) {
aschiffler@6763
   536
							execKey = userExecKey;
aschiffler@6763
   537
						} else {
aschiffler@6771
   538
							execKey = SDLTest_GenerateExecKey((char *)runSeed, testSuite->name, testCase->name, iterationCounter);
aschiffler@6763
   539
						}
aschiffler@6763
   540
aschiffler@6763
   541
						SDLTest_Log("Test Iteration %i: execKey %llu", iterationCounter, execKey);
aschiffler@6763
   542
						testResult = SDLTest_RunTest(testSuite, testCase, execKey);
aschiffler@6763
   543
aschiffler@6763
   544
						if (testResult == TEST_RESULT_PASSED) {
aschiffler@6763
   545
							testPassedCount++;
aschiffler@6763
   546
							totalTestPassedCount++;
aschiffler@6763
   547
						} else if (testResult == TEST_RESULT_SKIPPED) {
aschiffler@6763
   548
							testSkippedCount++;
aschiffler@6763
   549
							totalTestSkippedCount++;
aschiffler@6763
   550
						} else {
aschiffler@6763
   551
							testFailedCount++;
aschiffler@6763
   552
							totalTestFailedCount++;
aschiffler@6763
   553
						}
aschiffler@6763
   554
					}
aschiffler@6721
   555
aschiffler@7189
   556
					/* Take time - test end */
aschiffler@6763
   557
					testEndSeconds = GetClock();
aschiffler@6763
   558
					runtime = testEndSeconds - testStartSeconds;
aschiffler@6763
   559
					if (runtime < 0.0f) runtime = 0.0f;
aschiffler@6721
   560
aschiffler@6763
   561
					if (testIterations > 1) {
aschiffler@7189
   562
						/* Log test runtime */
aschiffler@6763
   563
						SDLTest_Log("Runtime of %i iterations: %.1f sec", testIterations, runtime);
aschiffler@6763
   564
						SDLTest_Log("Average Test runtime: %.5f sec", runtime / (float)testIterations);
aschiffler@6763
   565
					} else {
aschiffler@7189
   566
						/* Log test runtime */
aschiffler@6763
   567
						SDLTest_Log("Total Test runtime: %.1f sec", runtime);
aschiffler@6763
   568
					}
aschiffler@6721
   569
aschiffler@7189
   570
					/* Log final test result */
aschiffler@6763
   571
					switch (testResult) {
aschiffler@6763
   572
					case TEST_RESULT_PASSED:
aschiffler@6763
   573
						SDLTest_Log((char *)SDLTest_FinalResultFormat, "Test", currentTestName, "Passed");
aschiffler@6763
   574
						break;
aschiffler@6763
   575
					case TEST_RESULT_FAILED:
aschiffler@6763
   576
						SDLTest_LogError((char *)SDLTest_FinalResultFormat, "Test", currentTestName, "Failed");
aschiffler@6763
   577
						break;
aschiffler@6763
   578
					case TEST_RESULT_NO_ASSERT:
aschiffler@6763
   579
						SDLTest_LogError((char *)SDLTest_FinalResultFormat,"Test", currentTestName, "No Asserts");
aschiffler@6763
   580
						break;
aschiffler@6763
   581
					}
aschiffler@6763
   582
aschiffler@6721
   583
				}
aschiffler@6721
   584
			}
aschiffler@6721
   585
aschiffler@7189
   586
			/* Take time - suite end */
aschiffler@6763
   587
			suiteEndSeconds = GetClock();
aschiffler@6763
   588
			runtime = suiteEndSeconds - suiteStartSeconds;
aschiffler@6760
   589
			if (runtime < 0.0f) runtime = 0.0f;
aschiffler@6756
   590
aschiffler@7189
   591
			/* Log suite runtime */
aschiffler@6763
   592
			SDLTest_Log("Total Suite runtime: %.1f sec", runtime);
aschiffler@6721
   593
aschiffler@7189
   594
			/* Log summary and final Suite result */
aschiffler@6763
   595
			countSum = testPassedCount + testFailedCount + testSkippedCount;
aschiffler@6763
   596
			if (testFailedCount == 0)
aschiffler@6763
   597
			{
aschiffler@6763
   598
				SDLTest_Log(logFormat, "Suite", countSum, testPassedCount, testFailedCount, testSkippedCount);
aschiffler@6763
   599
				SDLTest_Log((char *)SDLTest_FinalResultFormat, "Suite", currentSuiteName, "Passed");
aschiffler@6763
   600
			} 
aschiffler@6763
   601
			else 
aschiffler@6763
   602
			{
aschiffler@6763
   603
				SDLTest_LogError(logFormat, "Suite", countSum, testPassedCount, testFailedCount, testSkippedCount);
aschiffler@6763
   604
				SDLTest_LogError((char *)SDLTest_FinalResultFormat, "Suite", currentSuiteName, "Failed");
aschiffler@6756
   605
			}
aschiffler@6721
   606
aschiffler@6756
   607
		}
aschiffler@6721
   608
	}
aschiffler@6721
   609
aschiffler@7189
   610
	/* Take time - run end */
aschiffler@6756
   611
	runEndSeconds = GetClock();
aschiffler@6760
   612
	runtime = runEndSeconds - runStartSeconds;
aschiffler@6760
   613
	if (runtime < 0.0f) runtime = 0.0f;
aschiffler@6756
   614
aschiffler@7189
   615
	/* Log total runtime */
aschiffler@6763
   616
	SDLTest_Log("Total Run runtime: %.1f sec", runtime);
aschiffler@6721
   617
aschiffler@7189
   618
	/* Log summary and final run result */
aschiffler@6756
   619
	countSum = totalTestPassedCount + totalTestFailedCount + totalTestSkippedCount;
aschiffler@6763
   620
	if (totalTestFailedCount == 0)
aschiffler@6756
   621
	{
aschiffler@6756
   622
		runResult = 0;
aschiffler@6756
   623
		SDLTest_Log(logFormat, "Run", countSum, totalTestPassedCount, totalTestFailedCount, totalTestSkippedCount);
aschiffler@6757
   624
		SDLTest_Log((char *)SDLTest_FinalResultFormat, "Run /w seed", runSeed, "Passed");
aschiffler@6756
   625
	} 
aschiffler@6756
   626
	else 
aschiffler@6756
   627
	{
aschiffler@6756
   628
		runResult = 1;
aschiffler@6756
   629
		SDLTest_LogError(logFormat, "Run", countSum, totalTestPassedCount, totalTestFailedCount, totalTestSkippedCount);
aschiffler@6757
   630
		SDLTest_LogError((char *)SDLTest_FinalResultFormat, "Run /w seed", runSeed, "Failed");
aschiffler@6756
   631
	}
aschiffler@6721
   632
aschiffler@6757
   633
	SDLTest_Log("Exit code: %d", runResult);	
aschiffler@6756
   634
	return runResult;
aschiffler@6721
   635
}