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