mirror of
https://github.com/thunderbrewhq/thunderbrew
synced 2025-12-13 03:32:28 +00:00
chore(build): use SDL3
This commit is contained in:
parent
9d04a35d87
commit
b3c0734a9e
3286 changed files with 866354 additions and 554996 deletions
157
vendor/sdl-3.2.10/src/test/SDL_test_assert.c
vendored
Normal file
157
vendor/sdl-3.2.10/src/test/SDL_test_assert.c
vendored
Normal file
|
|
@ -0,0 +1,157 @@
|
|||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
/*
|
||||
|
||||
Used by the test framework and test cases.
|
||||
|
||||
*/
|
||||
#include <SDL3/SDL_test.h>
|
||||
|
||||
/* Enable to have color in logs */
|
||||
#if 1
|
||||
#define COLOR_RED "\033[0;31m"
|
||||
#define COLOR_GREEN "\033[0;32m"
|
||||
#define COLOR_YELLOW "\033[0;93m"
|
||||
#define COLOR_BLUE "\033[0;94m"
|
||||
#define COLOR_END "\033[0m"
|
||||
#else
|
||||
#define COLOR_RED ""
|
||||
#define COLOR_GREEN ""
|
||||
#define COLOR_BLUE ""
|
||||
#define COLOR_YELLOW ""
|
||||
#define COLOR_END ""
|
||||
#endif
|
||||
|
||||
/* Assert check message format */
|
||||
#define SDLTEST_ASSERT_CHECK_FORMAT "Assert '%s': %s"
|
||||
|
||||
/* Assert summary message format */
|
||||
#define SDLTEST_ASSERT_SUMMARY_FORMAT "Assert Summary: Total=%d " COLOR_GREEN "Passed=%d" COLOR_END " " COLOR_RED "Failed=%d" COLOR_END
|
||||
#define SDLTEST_ASSERT_SUMMARY_FORMAT_OK "Assert Summary: Total=%d " COLOR_GREEN "Passed=%d" COLOR_END " " COLOR_GREEN "Failed=%d" COLOR_END
|
||||
|
||||
/* ! counts the failed asserts */
|
||||
static int SDLTest_AssertsFailed = 0;
|
||||
|
||||
/* ! counts the passed asserts */
|
||||
static int SDLTest_AssertsPassed = 0;
|
||||
|
||||
/*
|
||||
* Assert that logs and break execution flow on failures (i.e. for harness errors).
|
||||
*/
|
||||
void SDLTest_Assert(int assertCondition, SDL_PRINTF_FORMAT_STRING const char *assertDescription, ...)
|
||||
{
|
||||
va_list list;
|
||||
char logMessage[SDLTEST_MAX_LOGMESSAGE_LENGTH];
|
||||
|
||||
/* Print assert description into a buffer */
|
||||
SDL_memset(logMessage, 0, SDLTEST_MAX_LOGMESSAGE_LENGTH);
|
||||
va_start(list, assertDescription);
|
||||
(void)SDL_vsnprintf(logMessage, SDLTEST_MAX_LOGMESSAGE_LENGTH - 1, assertDescription, list);
|
||||
va_end(list);
|
||||
|
||||
/* Log, then assert and break on failure */
|
||||
SDL_assert((SDLTest_AssertCheck(assertCondition, "%s", logMessage)));
|
||||
}
|
||||
|
||||
/*
|
||||
* Assert that logs but does not break execution flow on failures (i.e. for test cases).
|
||||
*/
|
||||
int SDLTest_AssertCheck(int assertCondition, SDL_PRINTF_FORMAT_STRING const char *assertDescription, ...)
|
||||
{
|
||||
va_list list;
|
||||
char logMessage[SDLTEST_MAX_LOGMESSAGE_LENGTH];
|
||||
|
||||
/* Print assert description into a buffer */
|
||||
SDL_memset(logMessage, 0, SDLTEST_MAX_LOGMESSAGE_LENGTH);
|
||||
va_start(list, assertDescription);
|
||||
(void)SDL_vsnprintf(logMessage, SDLTEST_MAX_LOGMESSAGE_LENGTH - 1, assertDescription, list);
|
||||
va_end(list);
|
||||
|
||||
/* Log pass or fail message */
|
||||
if (assertCondition == ASSERT_FAIL) {
|
||||
SDLTest_AssertsFailed++;
|
||||
SDLTest_LogError(SDLTEST_ASSERT_CHECK_FORMAT, logMessage, COLOR_RED "Failed" COLOR_END);
|
||||
} else {
|
||||
SDLTest_AssertsPassed++;
|
||||
SDLTest_Log(SDLTEST_ASSERT_CHECK_FORMAT, logMessage, COLOR_GREEN "Passed" COLOR_END);
|
||||
}
|
||||
|
||||
return assertCondition;
|
||||
}
|
||||
|
||||
/*
|
||||
* Explicitly passing Assert that logs (i.e. for test cases).
|
||||
*/
|
||||
void SDLTest_AssertPass(SDL_PRINTF_FORMAT_STRING const char *assertDescription, ...)
|
||||
{
|
||||
va_list list;
|
||||
char logMessage[SDLTEST_MAX_LOGMESSAGE_LENGTH];
|
||||
|
||||
/* Print assert description into a buffer */
|
||||
SDL_memset(logMessage, 0, SDLTEST_MAX_LOGMESSAGE_LENGTH);
|
||||
va_start(list, assertDescription);
|
||||
(void)SDL_vsnprintf(logMessage, SDLTEST_MAX_LOGMESSAGE_LENGTH - 1, assertDescription, list);
|
||||
va_end(list);
|
||||
|
||||
/* Log pass message */
|
||||
SDLTest_AssertsPassed++;
|
||||
SDLTest_Log(SDLTEST_ASSERT_CHECK_FORMAT, logMessage, COLOR_GREEN "Passed" COLOR_END);
|
||||
}
|
||||
|
||||
/*
|
||||
* Resets the assert summary counters to zero.
|
||||
*/
|
||||
void SDLTest_ResetAssertSummary(void)
|
||||
{
|
||||
SDLTest_AssertsPassed = 0;
|
||||
SDLTest_AssertsFailed = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Logs summary of all assertions (total, pass, fail) since last reset
|
||||
* as INFO (failed==0) or ERROR (failed > 0).
|
||||
*/
|
||||
void SDLTest_LogAssertSummary(void)
|
||||
{
|
||||
int totalAsserts = SDLTest_AssertsPassed + SDLTest_AssertsFailed;
|
||||
if (SDLTest_AssertsFailed == 0) {
|
||||
SDLTest_Log(SDLTEST_ASSERT_SUMMARY_FORMAT_OK, totalAsserts, SDLTest_AssertsPassed, SDLTest_AssertsFailed);
|
||||
} else {
|
||||
SDLTest_LogError(SDLTEST_ASSERT_SUMMARY_FORMAT, totalAsserts, SDLTest_AssertsPassed, SDLTest_AssertsFailed);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Converts the current assert state into a test result
|
||||
*/
|
||||
int SDLTest_AssertSummaryToTestResult(void)
|
||||
{
|
||||
if (SDLTest_AssertsFailed > 0) {
|
||||
return TEST_RESULT_FAILED;
|
||||
} else {
|
||||
if (SDLTest_AssertsPassed > 0) {
|
||||
return TEST_RESULT_PASSED;
|
||||
} else {
|
||||
return TEST_RESULT_NO_ASSERT;
|
||||
}
|
||||
}
|
||||
}
|
||||
2861
vendor/sdl-3.2.10/src/test/SDL_test_common.c
vendored
Normal file
2861
vendor/sdl-3.2.10/src/test/SDL_test_common.c
vendored
Normal file
File diff suppressed because it is too large
Load diff
218
vendor/sdl-3.2.10/src/test/SDL_test_compare.c
vendored
Normal file
218
vendor/sdl-3.2.10/src/test/SDL_test_compare.c
vendored
Normal file
|
|
@ -0,0 +1,218 @@
|
|||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
/*
|
||||
|
||||
Based on automated SDL_Surface tests originally written by Edgar Simo 'bobbens'.
|
||||
|
||||
Rewritten for test lib by Andreas Schiffler.
|
||||
|
||||
*/
|
||||
#include <SDL3/SDL_test.h>
|
||||
|
||||
#define FILENAME_SIZE 128
|
||||
|
||||
/* Counter for _CompareSurface calls; used for filename creation when comparisons fail */
|
||||
static int _CompareSurfaceCount = 0;
|
||||
|
||||
/* Compare surfaces */
|
||||
int SDLTest_CompareSurfaces(SDL_Surface *surface, SDL_Surface *referenceSurface, int allowable_error)
|
||||
{
|
||||
int ret;
|
||||
int i, j;
|
||||
int dist;
|
||||
int sampleErrorX = 0, sampleErrorY = 0, sampleDist = 0;
|
||||
SDL_Color sampleReference = { 0, 0, 0, 0 };
|
||||
SDL_Color sampleActual = { 0, 0, 0, 0 };
|
||||
Uint8 R, G, B, A;
|
||||
Uint8 Rd, Gd, Bd, Ad;
|
||||
char imageFilename[FILENAME_SIZE];
|
||||
char referenceFilename[FILENAME_SIZE];
|
||||
|
||||
/* Validate input surfaces */
|
||||
if (!surface) {
|
||||
SDLTest_LogError("Cannot compare NULL surface");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!referenceSurface) {
|
||||
SDLTest_LogError("Cannot compare NULL reference surface");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Make sure surface size is the same. */
|
||||
if ((surface->w != referenceSurface->w) || (surface->h != referenceSurface->h)) {
|
||||
SDLTest_LogError("Expected %dx%d surface, got %dx%d", referenceSurface->w, referenceSurface->h, surface->w, surface->h);
|
||||
return -2;
|
||||
}
|
||||
|
||||
/* Sanitize input value */
|
||||
if (allowable_error < 0) {
|
||||
allowable_error = 0;
|
||||
}
|
||||
|
||||
SDL_LockSurface(surface);
|
||||
SDL_LockSurface(referenceSurface);
|
||||
|
||||
ret = 0;
|
||||
/* Compare image - should be same format. */
|
||||
for (j = 0; j < surface->h; j++) {
|
||||
for (i = 0; i < surface->w; i++) {
|
||||
int temp;
|
||||
|
||||
temp = SDL_ReadSurfacePixel(surface, i, j, &R, &G, &B, &A);
|
||||
if (!temp) {
|
||||
SDLTest_LogError("Failed to retrieve pixel (%d,%d): %s", i, j, SDL_GetError());
|
||||
ret++;
|
||||
continue;
|
||||
}
|
||||
|
||||
temp = SDL_ReadSurfacePixel(referenceSurface, i, j, &Rd, &Gd, &Bd, &Ad);
|
||||
if (!temp) {
|
||||
SDLTest_LogError("Failed to retrieve reference pixel (%d,%d): %s", i, j, SDL_GetError());
|
||||
ret++;
|
||||
continue;
|
||||
}
|
||||
|
||||
dist = 0;
|
||||
dist += (R - Rd) * (R - Rd);
|
||||
dist += (G - Gd) * (G - Gd);
|
||||
dist += (B - Bd) * (B - Bd);
|
||||
|
||||
/* Allow some difference in blending accuracy */
|
||||
if (dist > allowable_error) {
|
||||
ret++;
|
||||
if (ret == 1) {
|
||||
sampleErrorX = i;
|
||||
sampleErrorY = j;
|
||||
sampleDist = dist;
|
||||
sampleReference.r = Rd;
|
||||
sampleReference.g = Gd;
|
||||
sampleReference.b = Bd;
|
||||
sampleReference.a = Ad;
|
||||
sampleActual.r = R;
|
||||
sampleActual.g = G;
|
||||
sampleActual.b = B;
|
||||
sampleActual.a = A;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SDL_UnlockSurface(surface);
|
||||
SDL_UnlockSurface(referenceSurface);
|
||||
|
||||
/* Save test image and reference for analysis on failures */
|
||||
_CompareSurfaceCount++;
|
||||
if (ret != 0) {
|
||||
SDLTest_LogError("Comparison of pixels with allowable error of %i failed %i times.", allowable_error, ret);
|
||||
SDLTest_LogError("Reference surface format: %s", SDL_GetPixelFormatName(referenceSurface->format));
|
||||
SDLTest_LogError("Actual surface format: %s", SDL_GetPixelFormatName(surface->format));
|
||||
SDLTest_LogError("First detected occurrence at position %i,%i with a squared RGB-difference of %i.", sampleErrorX, sampleErrorY, sampleDist);
|
||||
SDLTest_LogError("Reference pixel: R=%u G=%u B=%u A=%u", sampleReference.r, sampleReference.g, sampleReference.b, sampleReference.a);
|
||||
SDLTest_LogError("Actual pixel : R=%u G=%u B=%u A=%u", sampleActual.r, sampleActual.g, sampleActual.b, sampleActual.a);
|
||||
(void)SDL_snprintf(imageFilename, FILENAME_SIZE - 1, "CompareSurfaces%04d_TestOutput.bmp", _CompareSurfaceCount);
|
||||
SDL_SaveBMP(surface, imageFilename);
|
||||
(void)SDL_snprintf(referenceFilename, FILENAME_SIZE - 1, "CompareSurfaces%04d_Reference.bmp", _CompareSurfaceCount);
|
||||
SDL_SaveBMP(referenceSurface, referenceFilename);
|
||||
SDLTest_LogError("Surfaces from failed comparison saved as '%s' and '%s'", imageFilename, referenceFilename);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int SDLTest_CompareMemory(const void *actual, size_t size_actual, const void *reference, size_t size_reference) {
|
||||
#define WIDTH 16
|
||||
|
||||
const size_t size_max = SDL_max(size_actual, size_reference);
|
||||
size_t i;
|
||||
struct {
|
||||
const char *header;
|
||||
const Uint8 *data;
|
||||
size_t size;
|
||||
} columns[] = {
|
||||
{
|
||||
"actual",
|
||||
actual,
|
||||
size_actual,
|
||||
},
|
||||
{
|
||||
"reference",
|
||||
reference,
|
||||
size_reference,
|
||||
},
|
||||
};
|
||||
char line_buffer[16 + SDL_arraysize(columns) * (4 * WIDTH + 1) + (SDL_arraysize(columns) - 1) * 2 + 1];
|
||||
|
||||
SDLTest_AssertCheck(size_actual == size_reference, "Sizes of memory blocks must be equal (actual=%" SDL_PRIu64 " expected=%" SDL_PRIu64 ")", (Uint64)size_actual, (Uint64)size_reference);
|
||||
if (size_actual == size_reference) {
|
||||
int equals;
|
||||
equals = SDL_memcmp(actual, reference, size_max) == 0;
|
||||
SDLTest_AssertCheck(equals, "Memory blocks contain the same data");
|
||||
if (equals) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
SDL_memset(line_buffer, ' ', sizeof(line_buffer));
|
||||
line_buffer[sizeof(line_buffer) - 1] = '\0';
|
||||
for (i = 0; i < SDL_arraysize(columns); i++) {
|
||||
SDL_memcpy(line_buffer + 16 + 1 + i * (4 * WIDTH + 3), columns[i].header, SDL_strlen(columns[i].header));
|
||||
}
|
||||
SDLTest_LogError("%s", line_buffer);
|
||||
|
||||
for (i = 0; i < size_max; i += WIDTH) {
|
||||
size_t pos = 0;
|
||||
size_t col;
|
||||
|
||||
pos += SDL_snprintf(line_buffer + pos, SDL_arraysize(line_buffer) - pos, "%016" SDL_PRIx64 , (Uint64)i);
|
||||
|
||||
for (col = 0; col < SDL_arraysize(columns); col++) {
|
||||
size_t j;
|
||||
|
||||
for (j = 0; j < WIDTH; j++) {
|
||||
if (i + j < columns[col].size) {
|
||||
pos += SDL_snprintf(line_buffer + pos, SDL_arraysize(line_buffer) - pos, " %02x", columns[col].data[i + j]);
|
||||
} else {
|
||||
pos += SDL_snprintf(line_buffer + pos, SDL_arraysize(line_buffer) - pos, " ");
|
||||
}
|
||||
}
|
||||
pos += SDL_snprintf(line_buffer + pos, SDL_arraysize(line_buffer) - pos, " ");
|
||||
for (j = 0; j < WIDTH; j++) {
|
||||
char c = ' ';
|
||||
if (i + j < columns[col].size) {
|
||||
c = columns[col].data[i + j];
|
||||
if (!SDL_isprint(c)) {
|
||||
c = '.';
|
||||
}
|
||||
}
|
||||
pos += SDL_snprintf(line_buffer + pos, SDL_arraysize(line_buffer) - pos, "%c", c);
|
||||
}
|
||||
if (col < SDL_arraysize(columns) - 1) {
|
||||
pos += SDL_snprintf(line_buffer + pos, SDL_arraysize(line_buffer), " |");
|
||||
}
|
||||
}
|
||||
SDLTest_LogError("%s", line_buffer);
|
||||
SDL_assert(pos == SDL_arraysize(line_buffer) - 1);
|
||||
}
|
||||
#undef WIDTH
|
||||
return 1;
|
||||
}
|
||||
160
vendor/sdl-3.2.10/src/test/SDL_test_crc32.c
vendored
Normal file
160
vendor/sdl-3.2.10/src/test/SDL_test_crc32.c
vendored
Normal file
|
|
@ -0,0 +1,160 @@
|
|||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
/*
|
||||
|
||||
Used by the test execution component.
|
||||
Original source code contributed by A. Schiffler for GSOC project.
|
||||
|
||||
*/
|
||||
#include <SDL3/SDL_test.h>
|
||||
|
||||
bool SDLTest_Crc32Init(SDLTest_Crc32Context *crcContext)
|
||||
{
|
||||
int i, j;
|
||||
CrcUint32 c;
|
||||
|
||||
/* Sanity check context pointer */
|
||||
if (!crcContext) {
|
||||
return SDL_InvalidParamError("crcContext");
|
||||
}
|
||||
|
||||
/*
|
||||
* Build auxiliary table for parallel byte-at-a-time CRC-32
|
||||
*/
|
||||
#ifdef ORIGINAL_METHOD
|
||||
for (i = 0; i < 256; ++i) {
|
||||
for (c = i << 24, j = 8; j > 0; --j) {
|
||||
c = c & 0x80000000 ? (c << 1) ^ CRC32_POLY : (c << 1);
|
||||
}
|
||||
crcContext->crc32_table[i] = c;
|
||||
}
|
||||
#else
|
||||
for (i = 0; i < 256; i++) {
|
||||
c = i;
|
||||
for (j = 8; j > 0; j--) {
|
||||
if (c & 1) {
|
||||
c = (c >> 1) ^ CRC32_POLY;
|
||||
} else {
|
||||
c >>= 1;
|
||||
}
|
||||
}
|
||||
crcContext->crc32_table[i] = c;
|
||||
}
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Complete CRC32 calculation on a memory block */
|
||||
bool SDLTest_Crc32Calc(SDLTest_Crc32Context *crcContext, CrcUint8 *inBuf, CrcUint32 inLen, CrcUint32 *crc32)
|
||||
{
|
||||
if (!SDLTest_Crc32CalcStart(crcContext, crc32)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!SDLTest_Crc32CalcBuffer(crcContext, inBuf, inLen, crc32)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!SDLTest_Crc32CalcEnd(crcContext, crc32)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Start crc calculation */
|
||||
|
||||
bool SDLTest_Crc32CalcStart(SDLTest_Crc32Context *crcContext, CrcUint32 *crc32)
|
||||
{
|
||||
/* Sanity check pointers */
|
||||
if (!crcContext) {
|
||||
*crc32 = 0;
|
||||
return SDL_InvalidParamError("crcContext");
|
||||
}
|
||||
|
||||
/*
|
||||
* Preload shift register, per CRC-32 spec
|
||||
*/
|
||||
*crc32 = 0xffffffff;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Finish crc calculation */
|
||||
|
||||
bool SDLTest_Crc32CalcEnd(SDLTest_Crc32Context *crcContext, CrcUint32 *crc32)
|
||||
{
|
||||
/* Sanity check pointers */
|
||||
if (!crcContext) {
|
||||
*crc32 = 0;
|
||||
return SDL_InvalidParamError("crcContext");
|
||||
}
|
||||
|
||||
/*
|
||||
* Return complement, per CRC-32 spec
|
||||
*/
|
||||
*crc32 = (~(*crc32));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Include memory block in crc */
|
||||
|
||||
bool SDLTest_Crc32CalcBuffer(SDLTest_Crc32Context *crcContext, CrcUint8 *inBuf, CrcUint32 inLen, CrcUint32 *crc32)
|
||||
{
|
||||
CrcUint8 *p;
|
||||
register CrcUint32 crc;
|
||||
|
||||
if (!crcContext) {
|
||||
*crc32 = 0;
|
||||
return SDL_InvalidParamError("crcContext");
|
||||
}
|
||||
|
||||
if (!inBuf) {
|
||||
return SDL_InvalidParamError("inBuf");
|
||||
}
|
||||
|
||||
/*
|
||||
* Calculate CRC from data
|
||||
*/
|
||||
crc = *crc32;
|
||||
for (p = inBuf; inLen > 0; ++p, --inLen) {
|
||||
#ifdef ORIGINAL_METHOD
|
||||
crc = (crc << 8) ^ crcContext->crc32_table[(crc >> 24) ^ *p];
|
||||
#else
|
||||
crc = ((crc >> 8) & 0x00FFFFFF) ^ crcContext->crc32_table[(crc ^ *p) & 0xFF];
|
||||
#endif
|
||||
}
|
||||
*crc32 = crc;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SDLTest_Crc32Done(SDLTest_Crc32Context *crcContext)
|
||||
{
|
||||
if (!crcContext) {
|
||||
return SDL_InvalidParamError("crcContext");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
159
vendor/sdl-3.2.10/src/test/SDL_test_font.c
vendored
Normal file
159
vendor/sdl-3.2.10/src/test/SDL_test_font.c
vendored
Normal file
|
|
@ -0,0 +1,159 @@
|
|||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
#include <SDL3/SDL_test.h>
|
||||
|
||||
#define UTF8_IsTrailingByte(c) ((c) >= 0x80 && (c) <= 0xBF)
|
||||
|
||||
int FONT_CHARACTER_SIZE = SDL_DEBUG_TEXT_FONT_CHARACTER_SIZE;
|
||||
|
||||
bool SDLTest_DrawCharacter(SDL_Renderer *renderer, float x, float y, Uint32 c)
|
||||
{
|
||||
char str[5];
|
||||
char *ptr = SDL_UCS4ToUTF8(c, str);
|
||||
*ptr = '\0';
|
||||
return SDL_RenderDebugText(renderer, x, y, str);
|
||||
}
|
||||
|
||||
bool SDLTest_DrawString(SDL_Renderer *renderer, float x, float y, const char *s)
|
||||
{
|
||||
return SDL_RenderDebugText(renderer, x, y, s);
|
||||
}
|
||||
|
||||
SDLTest_TextWindow *SDLTest_TextWindowCreate(float x, float y, float w, float h)
|
||||
{
|
||||
SDLTest_TextWindow *textwin = (SDLTest_TextWindow *)SDL_malloc(sizeof(*textwin));
|
||||
|
||||
if (!textwin) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
textwin->rect.x = x;
|
||||
textwin->rect.y = y;
|
||||
textwin->rect.w = w;
|
||||
textwin->rect.h = h;
|
||||
textwin->current = 0;
|
||||
textwin->numlines = (int)SDL_ceilf(h / FONT_LINE_HEIGHT);
|
||||
textwin->lines = (char **)SDL_calloc(textwin->numlines, sizeof(*textwin->lines));
|
||||
if (!textwin->lines) {
|
||||
SDL_free(textwin);
|
||||
return NULL;
|
||||
}
|
||||
return textwin;
|
||||
}
|
||||
|
||||
void SDLTest_TextWindowDisplay(SDLTest_TextWindow *textwin, SDL_Renderer *renderer)
|
||||
{
|
||||
int i;
|
||||
float y;
|
||||
|
||||
for (y = textwin->rect.y, i = 0; i < textwin->numlines; ++i, y += FONT_LINE_HEIGHT) {
|
||||
if (textwin->lines[i]) {
|
||||
SDLTest_DrawString(renderer, textwin->rect.x, y, textwin->lines[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SDLTest_TextWindowAddText(SDLTest_TextWindow *textwin, const char *fmt, ...)
|
||||
{
|
||||
char text[1024];
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
(void)SDL_vsnprintf(text, sizeof(text), fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
SDLTest_TextWindowAddTextWithLength(textwin, text, SDL_strlen(text));
|
||||
}
|
||||
|
||||
void SDLTest_TextWindowAddTextWithLength(SDLTest_TextWindow *textwin, const char *text, size_t len)
|
||||
{
|
||||
size_t existing;
|
||||
bool newline = false;
|
||||
char *line;
|
||||
|
||||
if (len > 0 && text[len - 1] == '\n') {
|
||||
--len;
|
||||
newline = true;
|
||||
}
|
||||
|
||||
if (textwin->lines[textwin->current]) {
|
||||
existing = SDL_strlen(textwin->lines[textwin->current]);
|
||||
} else {
|
||||
existing = 0;
|
||||
}
|
||||
|
||||
if (*text == '\b') {
|
||||
if (existing) {
|
||||
while (existing > 1 && UTF8_IsTrailingByte((Uint8)textwin->lines[textwin->current][existing - 1])) {
|
||||
--existing;
|
||||
}
|
||||
--existing;
|
||||
textwin->lines[textwin->current][existing] = '\0';
|
||||
} else if (textwin->current > 0) {
|
||||
SDL_free(textwin->lines[textwin->current]);
|
||||
textwin->lines[textwin->current] = NULL;
|
||||
--textwin->current;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
line = (char *)SDL_realloc(textwin->lines[textwin->current], existing + len + 1);
|
||||
if (line) {
|
||||
SDL_memcpy(&line[existing], text, len);
|
||||
line[existing + len] = '\0';
|
||||
textwin->lines[textwin->current] = line;
|
||||
if (newline) {
|
||||
if (textwin->current == textwin->numlines - 1) {
|
||||
SDL_free(textwin->lines[0]);
|
||||
SDL_memmove(&textwin->lines[0], &textwin->lines[1], (textwin->numlines - 1) * sizeof(textwin->lines[1]));
|
||||
textwin->lines[textwin->current] = NULL;
|
||||
} else {
|
||||
++textwin->current;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SDLTest_TextWindowClear(SDLTest_TextWindow *textwin)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < textwin->numlines; ++i) {
|
||||
if (textwin->lines[i]) {
|
||||
SDL_free(textwin->lines[i]);
|
||||
textwin->lines[i] = NULL;
|
||||
}
|
||||
}
|
||||
textwin->current = 0;
|
||||
}
|
||||
|
||||
void SDLTest_TextWindowDestroy(SDLTest_TextWindow *textwin)
|
||||
{
|
||||
if (textwin) {
|
||||
SDLTest_TextWindowClear(textwin);
|
||||
SDL_free(textwin->lines);
|
||||
SDL_free(textwin);
|
||||
}
|
||||
}
|
||||
|
||||
void SDLTest_CleanupTextDrawing(void)
|
||||
{
|
||||
}
|
||||
494
vendor/sdl-3.2.10/src/test/SDL_test_fuzzer.c
vendored
Normal file
494
vendor/sdl-3.2.10/src/test/SDL_test_fuzzer.c
vendored
Normal file
|
|
@ -0,0 +1,494 @@
|
|||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
/*
|
||||
|
||||
Data generators for fuzzing test data in a reproducible way.
|
||||
|
||||
*/
|
||||
#include <SDL3/SDL_test.h>
|
||||
|
||||
#include <float.h> /* Needed for FLT_MAX and DBL_EPSILON */
|
||||
#include <limits.h> /* Needed for UCHAR_MAX, etc. */
|
||||
|
||||
/**
|
||||
* Counter for fuzzer invocations
|
||||
*/
|
||||
static int fuzzerInvocationCounter = 0;
|
||||
|
||||
/**
|
||||
* Context for shared random number generator
|
||||
*/
|
||||
static Uint64 rndContext;
|
||||
|
||||
/*
|
||||
* Note: doxygen documentation markup for functions is in the header file.
|
||||
*/
|
||||
|
||||
void SDLTest_FuzzerInit(Uint64 execKey)
|
||||
{
|
||||
rndContext = execKey;
|
||||
fuzzerInvocationCounter = 0;
|
||||
}
|
||||
|
||||
int SDLTest_GetFuzzerInvocationCount(void)
|
||||
{
|
||||
return fuzzerInvocationCounter;
|
||||
}
|
||||
|
||||
Uint8 SDLTest_RandomUint8(void)
|
||||
{
|
||||
fuzzerInvocationCounter++;
|
||||
|
||||
return (Uint8)(SDL_rand_bits_r(&rndContext) >> 24);
|
||||
}
|
||||
|
||||
Sint8 SDLTest_RandomSint8(void)
|
||||
{
|
||||
fuzzerInvocationCounter++;
|
||||
|
||||
return (Sint8)(SDL_rand_bits_r(&rndContext) >> 24);
|
||||
}
|
||||
|
||||
Uint16 SDLTest_RandomUint16(void)
|
||||
{
|
||||
fuzzerInvocationCounter++;
|
||||
|
||||
return (Uint16)(SDL_rand_bits_r(&rndContext) >> 16);
|
||||
}
|
||||
|
||||
Sint16 SDLTest_RandomSint16(void)
|
||||
{
|
||||
fuzzerInvocationCounter++;
|
||||
|
||||
return (Sint16)(SDL_rand_bits_r(&rndContext) >> 16);
|
||||
}
|
||||
|
||||
Uint32 SDLTest_RandomUint32(void)
|
||||
{
|
||||
fuzzerInvocationCounter++;
|
||||
|
||||
return SDL_rand_bits_r(&rndContext);
|
||||
}
|
||||
|
||||
Sint32 SDLTest_RandomSint32(void)
|
||||
{
|
||||
fuzzerInvocationCounter++;
|
||||
|
||||
return (Sint32)SDL_rand_bits_r(&rndContext);
|
||||
}
|
||||
|
||||
Uint64 SDLTest_RandomUint64(void)
|
||||
{
|
||||
union
|
||||
{
|
||||
Uint64 v64;
|
||||
Uint32 v32[2];
|
||||
} value;
|
||||
|
||||
fuzzerInvocationCounter++;
|
||||
|
||||
value.v32[0] = SDLTest_RandomUint32();
|
||||
value.v32[1] = SDLTest_RandomUint32();
|
||||
|
||||
return value.v64;
|
||||
}
|
||||
|
||||
Sint64 SDLTest_RandomSint64(void)
|
||||
{
|
||||
union
|
||||
{
|
||||
Uint64 v64;
|
||||
Uint32 v32[2];
|
||||
} value;
|
||||
|
||||
fuzzerInvocationCounter++;
|
||||
|
||||
value.v32[0] = SDLTest_RandomUint32();
|
||||
value.v32[1] = SDLTest_RandomUint32();
|
||||
|
||||
return (Sint64)value.v64;
|
||||
}
|
||||
|
||||
Sint32 SDLTest_RandomIntegerInRange(Sint32 min, Sint32 max)
|
||||
{
|
||||
fuzzerInvocationCounter++;
|
||||
|
||||
if (min == max) {
|
||||
return min;
|
||||
}
|
||||
|
||||
if (min > max) {
|
||||
Sint32 temp = min;
|
||||
min = max;
|
||||
max = temp;
|
||||
}
|
||||
|
||||
Uint64 range = (Sint64)max - (Sint64)min;
|
||||
if (range < SDL_MAX_SINT32) {
|
||||
return min + SDL_rand_r(&rndContext, (Sint32) range + 1);
|
||||
} else {
|
||||
Uint64 add = SDL_rand_bits_r(&rndContext) | ((Uint64) SDL_rand_bits_r(&rndContext) << 32);
|
||||
return (Sint32) (min + (Sint64) (add % (range + 1)));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a unsigned boundary value between the given boundaries.
|
||||
* Boundary values are inclusive. See the examples below.
|
||||
* If boundary2 < boundary1, the values are swapped.
|
||||
* If boundary1 == boundary2, value of boundary1 will be returned
|
||||
*
|
||||
* Generating boundary values for Uint8:
|
||||
* BoundaryValues(UINT8_MAX, 10, 20, True) -> [10,11,19,20]
|
||||
* BoundaryValues(UINT8_MAX, 10, 20, False) -> [9,21]
|
||||
* BoundaryValues(UINT8_MAX, 0, 15, True) -> [0, 1, 14, 15]
|
||||
* BoundaryValues(UINT8_MAX, 0, 15, False) -> [16]
|
||||
* BoundaryValues(UINT8_MAX, 0, 0xFF, False) -> [0], error set
|
||||
*
|
||||
* Generator works the same for other types of unsigned integers.
|
||||
*
|
||||
* \param maxValue The biggest value that is acceptable for this data type.
|
||||
* For instance, for Uint8 -> 255, Uint16 -> 65536 etc.
|
||||
* \param boundary1 defines lower boundary
|
||||
* \param boundary2 defines upper boundary
|
||||
* \param validDomain Generate only for valid domain (for the data type)
|
||||
*
|
||||
* \returns Returns a random boundary value for the domain or 0 in case of error
|
||||
*/
|
||||
static Uint64 SDLTest_GenerateUnsignedBoundaryValues(const Uint64 maxValue, Uint64 boundary1, Uint64 boundary2, bool validDomain)
|
||||
{
|
||||
Uint64 b1, b2;
|
||||
Uint64 delta;
|
||||
Uint64 tempBuf[4];
|
||||
Uint8 index;
|
||||
|
||||
/* Maybe swap */
|
||||
if (boundary1 > boundary2) {
|
||||
b1 = boundary2;
|
||||
b2 = boundary1;
|
||||
} else {
|
||||
b1 = boundary1;
|
||||
b2 = boundary2;
|
||||
}
|
||||
|
||||
index = 0;
|
||||
if (validDomain == true) {
|
||||
if (b1 == b2) {
|
||||
return b1;
|
||||
}
|
||||
|
||||
/* Generate up to 4 values within bounds */
|
||||
delta = b2 - b1;
|
||||
if (delta < 4) {
|
||||
do {
|
||||
tempBuf[index] = b1 + index;
|
||||
index++;
|
||||
} while (index < delta);
|
||||
} else {
|
||||
tempBuf[index] = b1;
|
||||
index++;
|
||||
tempBuf[index] = b1 + 1;
|
||||
index++;
|
||||
tempBuf[index] = b2 - 1;
|
||||
index++;
|
||||
tempBuf[index] = b2;
|
||||
index++;
|
||||
}
|
||||
} else {
|
||||
/* Generate up to 2 values outside of bounds */
|
||||
if (b1 > 0) {
|
||||
tempBuf[index] = b1 - 1;
|
||||
index++;
|
||||
}
|
||||
|
||||
if (b2 < maxValue) {
|
||||
tempBuf[index] = b2 + 1;
|
||||
index++;
|
||||
}
|
||||
}
|
||||
|
||||
if (index == 0) {
|
||||
/* There are no valid boundaries */
|
||||
SDL_Unsupported();
|
||||
return 0;
|
||||
}
|
||||
|
||||
return tempBuf[SDLTest_RandomUint8() % index];
|
||||
}
|
||||
|
||||
Uint8 SDLTest_RandomUint8BoundaryValue(Uint8 boundary1, Uint8 boundary2, bool validDomain)
|
||||
{
|
||||
/* max value for Uint8 */
|
||||
const Uint64 maxValue = UCHAR_MAX;
|
||||
return (Uint8)SDLTest_GenerateUnsignedBoundaryValues(maxValue,
|
||||
(Uint64)boundary1, (Uint64)boundary2,
|
||||
validDomain);
|
||||
}
|
||||
|
||||
Uint16 SDLTest_RandomUint16BoundaryValue(Uint16 boundary1, Uint16 boundary2, bool validDomain)
|
||||
{
|
||||
/* max value for Uint16 */
|
||||
const Uint64 maxValue = USHRT_MAX;
|
||||
return (Uint16)SDLTest_GenerateUnsignedBoundaryValues(maxValue,
|
||||
(Uint64)boundary1, (Uint64)boundary2,
|
||||
validDomain);
|
||||
}
|
||||
|
||||
Uint32 SDLTest_RandomUint32BoundaryValue(Uint32 boundary1, Uint32 boundary2, bool validDomain)
|
||||
{
|
||||
/* max value for Uint32 */
|
||||
#if ((ULONG_MAX) == (UINT_MAX))
|
||||
const Uint64 maxValue = ULONG_MAX;
|
||||
#else
|
||||
const Uint64 maxValue = UINT_MAX;
|
||||
#endif
|
||||
return (Uint32)SDLTest_GenerateUnsignedBoundaryValues(maxValue,
|
||||
(Uint64)boundary1, (Uint64)boundary2,
|
||||
validDomain);
|
||||
}
|
||||
|
||||
Uint64 SDLTest_RandomUint64BoundaryValue(Uint64 boundary1, Uint64 boundary2, bool validDomain)
|
||||
{
|
||||
/* max value for Uint64 */
|
||||
const Uint64 maxValue = UINT64_MAX;
|
||||
return SDLTest_GenerateUnsignedBoundaryValues(maxValue,
|
||||
boundary1, boundary2,
|
||||
validDomain);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a signed boundary value between the given boundaries.
|
||||
* Boundary values are inclusive. See the examples below.
|
||||
* If boundary2 < boundary1, the values are swapped.
|
||||
* If boundary1 == boundary2, value of boundary1 will be returned
|
||||
*
|
||||
* Generating boundary values for Sint8:
|
||||
* SignedBoundaryValues(SCHAR_MIN, SCHAR_MAX, -10, 20, True) -> [-10,-9,19,20]
|
||||
* SignedBoundaryValues(SCHAR_MIN, SCHAR_MAX, -10, 20, False) -> [-11,21]
|
||||
* SignedBoundaryValues(SCHAR_MIN, SCHAR_MAX, -30, -15, True) -> [-30, -29, -16, -15]
|
||||
* SignedBoundaryValues(SCHAR_MIN, SCHAR_MAX, -127, 15, False) -> [16]
|
||||
* SignedBoundaryValues(SCHAR_MIN, SCHAR_MAX, -127, 127, False) -> [0], error set
|
||||
*
|
||||
* Generator works the same for other types of signed integers.
|
||||
*
|
||||
* \param minValue The smallest value that is acceptable for this data type.
|
||||
* For instance, for Uint8 -> -127, etc.
|
||||
* \param maxValue The biggest value that is acceptable for this data type.
|
||||
* For instance, for Uint8 -> 127, etc.
|
||||
* \param boundary1 defines lower boundary
|
||||
* \param boundary2 defines upper boundary
|
||||
* \param validDomain Generate only for valid domain (for the data type)
|
||||
*
|
||||
* \returns Returns a random boundary value for the domain or 0 in case of error
|
||||
*/
|
||||
static Sint64 SDLTest_GenerateSignedBoundaryValues(const Sint64 minValue, const Sint64 maxValue, Sint64 boundary1, Sint64 boundary2, bool validDomain)
|
||||
{
|
||||
Sint64 b1, b2;
|
||||
Sint64 delta;
|
||||
Sint64 tempBuf[4];
|
||||
Uint8 index;
|
||||
|
||||
/* Maybe swap */
|
||||
if (boundary1 > boundary2) {
|
||||
b1 = boundary2;
|
||||
b2 = boundary1;
|
||||
} else {
|
||||
b1 = boundary1;
|
||||
b2 = boundary2;
|
||||
}
|
||||
|
||||
index = 0;
|
||||
if (validDomain == true) {
|
||||
if (b1 == b2) {
|
||||
return b1;
|
||||
}
|
||||
|
||||
/* Generate up to 4 values within bounds */
|
||||
delta = b2 - b1;
|
||||
if (delta < 4) {
|
||||
do {
|
||||
tempBuf[index] = b1 + index;
|
||||
index++;
|
||||
} while (index < delta);
|
||||
} else {
|
||||
tempBuf[index] = b1;
|
||||
index++;
|
||||
tempBuf[index] = b1 + 1;
|
||||
index++;
|
||||
tempBuf[index] = b2 - 1;
|
||||
index++;
|
||||
tempBuf[index] = b2;
|
||||
index++;
|
||||
}
|
||||
} else {
|
||||
/* Generate up to 2 values outside of bounds */
|
||||
if (b1 > minValue) {
|
||||
tempBuf[index] = b1 - 1;
|
||||
index++;
|
||||
}
|
||||
|
||||
if (b2 < maxValue) {
|
||||
tempBuf[index] = b2 + 1;
|
||||
index++;
|
||||
}
|
||||
}
|
||||
|
||||
if (index == 0) {
|
||||
/* There are no valid boundaries */
|
||||
SDL_Unsupported();
|
||||
return minValue;
|
||||
}
|
||||
|
||||
return tempBuf[SDLTest_RandomUint8() % index];
|
||||
}
|
||||
|
||||
Sint8 SDLTest_RandomSint8BoundaryValue(Sint8 boundary1, Sint8 boundary2, bool validDomain)
|
||||
{
|
||||
/* min & max values for Sint8 */
|
||||
const Sint64 maxValue = SCHAR_MAX;
|
||||
const Sint64 minValue = SCHAR_MIN;
|
||||
return (Sint8)SDLTest_GenerateSignedBoundaryValues(minValue, maxValue,
|
||||
(Sint64)boundary1, (Sint64)boundary2,
|
||||
validDomain);
|
||||
}
|
||||
|
||||
Sint16 SDLTest_RandomSint16BoundaryValue(Sint16 boundary1, Sint16 boundary2, bool validDomain)
|
||||
{
|
||||
/* min & max values for Sint16 */
|
||||
const Sint64 maxValue = SHRT_MAX;
|
||||
const Sint64 minValue = SHRT_MIN;
|
||||
return (Sint16)SDLTest_GenerateSignedBoundaryValues(minValue, maxValue,
|
||||
(Sint64)boundary1, (Sint64)boundary2,
|
||||
validDomain);
|
||||
}
|
||||
|
||||
Sint32 SDLTest_RandomSint32BoundaryValue(Sint32 boundary1, Sint32 boundary2, bool validDomain)
|
||||
{
|
||||
/* min & max values for Sint32 */
|
||||
#if ((ULONG_MAX) == (UINT_MAX))
|
||||
const Sint64 maxValue = LONG_MAX;
|
||||
const Sint64 minValue = LONG_MIN;
|
||||
#else
|
||||
const Sint64 maxValue = INT_MAX;
|
||||
const Sint64 minValue = INT_MIN;
|
||||
#endif
|
||||
return (Sint32)SDLTest_GenerateSignedBoundaryValues(minValue, maxValue,
|
||||
(Sint64)boundary1, (Sint64)boundary2,
|
||||
validDomain);
|
||||
}
|
||||
|
||||
Sint64 SDLTest_RandomSint64BoundaryValue(Sint64 boundary1, Sint64 boundary2, bool validDomain)
|
||||
{
|
||||
/* min & max values for Sint64 */
|
||||
const Sint64 maxValue = INT64_MAX;
|
||||
const Sint64 minValue = INT64_MIN;
|
||||
return SDLTest_GenerateSignedBoundaryValues(minValue, maxValue,
|
||||
boundary1, boundary2,
|
||||
validDomain);
|
||||
}
|
||||
|
||||
float SDLTest_RandomUnitFloat(void)
|
||||
{
|
||||
return SDL_randf_r(&rndContext);
|
||||
}
|
||||
|
||||
float SDLTest_RandomFloat(void)
|
||||
{
|
||||
union
|
||||
{
|
||||
float f;
|
||||
Uint32 v32;
|
||||
} value;
|
||||
|
||||
do {
|
||||
value.v32 = SDLTest_RandomUint32();
|
||||
} while (SDL_isnanf(value.f) || SDL_isinff(value.f));
|
||||
|
||||
return value.f;
|
||||
}
|
||||
|
||||
double SDLTest_RandomUnitDouble(void)
|
||||
{
|
||||
return (double)(SDLTest_RandomUint64() >> (64-53)) * 0x1.0p-53;
|
||||
}
|
||||
|
||||
double SDLTest_RandomDouble(void)
|
||||
{
|
||||
union
|
||||
{
|
||||
double d;
|
||||
Uint64 v64;
|
||||
} value;
|
||||
|
||||
do {
|
||||
value.v64 = SDLTest_RandomUint64();
|
||||
} while (SDL_isnan(value.d) || SDL_isinf(value.d));
|
||||
|
||||
return value.d;
|
||||
}
|
||||
|
||||
char *SDLTest_RandomAsciiString(void)
|
||||
{
|
||||
return SDLTest_RandomAsciiStringWithMaximumLength(255);
|
||||
}
|
||||
|
||||
char *SDLTest_RandomAsciiStringWithMaximumLength(int maxLength)
|
||||
{
|
||||
int size;
|
||||
|
||||
if (maxLength < 1) {
|
||||
SDL_InvalidParamError("maxLength");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
size = (SDLTest_RandomUint32() % (maxLength + 1));
|
||||
if (size == 0) {
|
||||
size = 1;
|
||||
}
|
||||
return SDLTest_RandomAsciiStringOfSize(size);
|
||||
}
|
||||
|
||||
char *SDLTest_RandomAsciiStringOfSize(int size)
|
||||
{
|
||||
char *string;
|
||||
int counter;
|
||||
|
||||
if (size < 1) {
|
||||
SDL_InvalidParamError("size");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
string = (char *)SDL_malloc((size + 1) * sizeof(char));
|
||||
if (!string) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (counter = 0; counter < size; ++counter) {
|
||||
string[counter] = (char)SDLTest_RandomIntegerInRange(32, 126);
|
||||
}
|
||||
|
||||
string[counter] = '\0';
|
||||
|
||||
fuzzerInvocationCounter++;
|
||||
|
||||
return string;
|
||||
}
|
||||
864
vendor/sdl-3.2.10/src/test/SDL_test_harness.c
vendored
Normal file
864
vendor/sdl-3.2.10/src/test/SDL_test_harness.c
vendored
Normal file
|
|
@ -0,0 +1,864 @@
|
|||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
#include <SDL3/SDL_test.h>
|
||||
|
||||
#include <stdlib.h> /* Needed for exit() */
|
||||
|
||||
/* Enable to have color in logs */
|
||||
#if 1
|
||||
#define COLOR_RED "\033[0;31m"
|
||||
#define COLOR_GREEN "\033[0;32m"
|
||||
#define COLOR_YELLOW "\033[0;93m"
|
||||
#define COLOR_BLUE "\033[0;94m"
|
||||
#define COLOR_END "\033[0m"
|
||||
#else
|
||||
#define COLOR_RED ""
|
||||
#define COLOR_GREEN ""
|
||||
#define COLOR_BLUE ""
|
||||
#define COLOR_YELLOW ""
|
||||
#define COLOR_END ""
|
||||
#endif
|
||||
|
||||
/* Invalid test name/description message format */
|
||||
#define SDLTEST_INVALID_NAME_FORMAT "(Invalid)"
|
||||
|
||||
/* Log summary message format */
|
||||
#define SDLTEST_LOG_SUMMARY_FORMAT "%s Summary: Total=%d " COLOR_GREEN "Passed=%d" COLOR_END " " COLOR_RED "Failed=%d" COLOR_END " " COLOR_BLUE "Skipped=%d" COLOR_END
|
||||
#define SDLTEST_LOG_SUMMARY_FORMAT_OK "%s Summary: Total=%d " COLOR_GREEN "Passed=%d" COLOR_END " " COLOR_GREEN "Failed=%d" COLOR_END " " COLOR_BLUE "Skipped=%d" COLOR_END
|
||||
|
||||
/* Final result message format */
|
||||
#define SDLTEST_FINAL_RESULT_FORMAT COLOR_YELLOW ">>> %s '%s':" COLOR_END " %s\n"
|
||||
|
||||
struct SDLTest_TestSuiteRunner {
|
||||
struct
|
||||
{
|
||||
SDLTest_TestSuiteReference **testSuites;
|
||||
char *runSeed;
|
||||
Uint64 execKey;
|
||||
char *filter;
|
||||
int testIterations;
|
||||
bool randomOrder;
|
||||
} user;
|
||||
|
||||
SDLTest_ArgumentParser argparser;
|
||||
};
|
||||
|
||||
/* ! Timeout for single test case execution */
|
||||
static Uint32 SDLTest_TestCaseTimeout = 3600;
|
||||
|
||||
static const char *common_harness_usage[] = {
|
||||
"[--iterations #]",
|
||||
"[--execKey #]",
|
||||
"[--seed string]",
|
||||
"[--filter suite_name|test_name]",
|
||||
"[--random-order]",
|
||||
NULL
|
||||
};
|
||||
|
||||
char *SDLTest_GenerateRunSeed(char *buffer, int length)
|
||||
{
|
||||
Uint64 randomContext = SDL_GetPerformanceCounter();
|
||||
int counter;
|
||||
|
||||
if (!buffer) {
|
||||
SDLTest_LogError("Input buffer must not be NULL.");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Sanity check input */
|
||||
if (length <= 0) {
|
||||
SDLTest_LogError("The length of the harness seed must be >0.");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Generate a random string of alphanumeric characters */
|
||||
for (counter = 0; counter < length; counter++) {
|
||||
char ch;
|
||||
int v = SDL_rand_r(&randomContext, 10 + 26);
|
||||
if (v < 10) {
|
||||
ch = (char)('0' + v);
|
||||
} else {
|
||||
ch = (char)('A' + v - 10);
|
||||
}
|
||||
buffer[counter] = ch;
|
||||
}
|
||||
buffer[length] = '\0';
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates an execution key for the fuzzer.
|
||||
*
|
||||
* \param runSeed The run seed to use
|
||||
* \param suiteName The name of the test suite
|
||||
* \param testName The name of the test
|
||||
* \param iteration The iteration count
|
||||
*
|
||||
* \returns The generated execution key to initialize the fuzzer with.
|
||||
*
|
||||
*/
|
||||
static Uint64 SDLTest_GenerateExecKey(const char *runSeed, const char *suiteName, const char *testName, int iteration)
|
||||
{
|
||||
SDLTest_Md5Context md5Context;
|
||||
Uint64 *keys;
|
||||
char iterationString[16];
|
||||
size_t runSeedLength;
|
||||
size_t suiteNameLength;
|
||||
size_t testNameLength;
|
||||
size_t iterationStringLength;
|
||||
size_t entireStringLength;
|
||||
char *buffer;
|
||||
|
||||
if (!runSeed || runSeed[0] == '\0') {
|
||||
SDLTest_LogError("Invalid runSeed string.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!suiteName || suiteName[0] == '\0') {
|
||||
SDLTest_LogError("Invalid suiteName string.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!testName || testName[0] == '\0') {
|
||||
SDLTest_LogError("Invalid testName string.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (iteration <= 0) {
|
||||
SDLTest_LogError("Invalid iteration count.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Convert iteration number into a string */
|
||||
SDL_memset(iterationString, 0, sizeof(iterationString));
|
||||
(void)SDL_snprintf(iterationString, sizeof(iterationString) - 1, "%d", iteration);
|
||||
|
||||
/* Combine the parameters into single string */
|
||||
runSeedLength = SDL_strlen(runSeed);
|
||||
suiteNameLength = SDL_strlen(suiteName);
|
||||
testNameLength = SDL_strlen(testName);
|
||||
iterationStringLength = SDL_strlen(iterationString);
|
||||
entireStringLength = runSeedLength + suiteNameLength + testNameLength + iterationStringLength + 1;
|
||||
buffer = (char *)SDL_malloc(entireStringLength);
|
||||
if (!buffer) {
|
||||
SDLTest_LogError("Failed to allocate buffer for execKey generation.");
|
||||
return 0;
|
||||
}
|
||||
(void)SDL_snprintf(buffer, entireStringLength, "%s%s%s%d", runSeed, suiteName, testName, iteration);
|
||||
|
||||
/* Hash string and use half of the digest as 64bit exec key */
|
||||
SDLTest_Md5Init(&md5Context);
|
||||
SDLTest_Md5Update(&md5Context, (unsigned char *)buffer, (unsigned int)entireStringLength);
|
||||
SDLTest_Md5Final(&md5Context);
|
||||
SDL_free(buffer);
|
||||
keys = (Uint64 *)md5Context.digest;
|
||||
|
||||
return keys[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* Set timeout handler for test.
|
||||
*
|
||||
* \param timeout Timeout interval in seconds.
|
||||
* \param callback Function that will be called after timeout has elapsed.
|
||||
*
|
||||
* \return Timer id or -1 on failure.
|
||||
*/
|
||||
static SDL_TimerID SDLTest_SetTestTimeout(int timeout, SDL_TimerCallback callback)
|
||||
{
|
||||
Uint32 timeoutInMilliseconds;
|
||||
SDL_TimerID timerID;
|
||||
|
||||
if (!callback) {
|
||||
SDLTest_LogError("Timeout callback can't be NULL");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (timeout < 0) {
|
||||
SDLTest_LogError("Timeout value must be bigger than zero.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Set timer */
|
||||
timeoutInMilliseconds = timeout * 1000;
|
||||
timerID = SDL_AddTimer(timeoutInMilliseconds, callback, 0x0);
|
||||
if (timerID == 0) {
|
||||
SDLTest_LogError("Creation of SDL timer failed: %s", SDL_GetError());
|
||||
return 0;
|
||||
}
|
||||
|
||||
return timerID;
|
||||
}
|
||||
|
||||
/**
|
||||
* Timeout handler. Aborts test run and exits harness process.
|
||||
*/
|
||||
static Uint32 SDLCALL SDLTest_BailOut(void *userdata, SDL_TimerID timerID, Uint32 interval)
|
||||
{
|
||||
SDLTest_LogError("TestCaseTimeout timer expired. Aborting test run.");
|
||||
exit(TEST_ABORTED); /* bail out from the test */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute a test using the given execution key.
|
||||
*
|
||||
* \param testSuite Suite containing the test case.
|
||||
* \param testCase Case to execute.
|
||||
* \param execKey Execution key for the fuzzer.
|
||||
* \param forceTestRun Force test to run even if test was disabled in suite.
|
||||
*
|
||||
* \returns Test case result.
|
||||
*/
|
||||
static int SDLTest_RunTest(SDLTest_TestSuiteReference *testSuite, const SDLTest_TestCaseReference *testCase, Uint64 execKey, bool forceTestRun)
|
||||
{
|
||||
SDL_TimerID timer = 0;
|
||||
int testCaseResult = 0;
|
||||
int testResult = 0;
|
||||
int fuzzerCount;
|
||||
void *data = NULL;
|
||||
|
||||
if (!testSuite || !testCase || !testSuite->name || !testCase->name) {
|
||||
SDLTest_LogError("Setup failure: testSuite or testCase references NULL");
|
||||
return TEST_RESULT_SETUP_FAILURE;
|
||||
}
|
||||
|
||||
if (!testCase->enabled && forceTestRun == false) {
|
||||
SDLTest_Log(SDLTEST_FINAL_RESULT_FORMAT, "Test", testCase->name, "Skipped (Disabled)");
|
||||
return TEST_RESULT_SKIPPED;
|
||||
}
|
||||
|
||||
/* Initialize fuzzer */
|
||||
SDLTest_FuzzerInit(execKey);
|
||||
|
||||
/* Reset assert tracker */
|
||||
SDLTest_ResetAssertSummary();
|
||||
|
||||
/* Set timeout timer */
|
||||
timer = SDLTest_SetTestTimeout(SDLTest_TestCaseTimeout, SDLTest_BailOut);
|
||||
|
||||
/* Maybe run suite initializer function */
|
||||
if (testSuite->testSetUp) {
|
||||
testSuite->testSetUp(&data);
|
||||
if (SDLTest_AssertSummaryToTestResult() == TEST_RESULT_FAILED) {
|
||||
SDLTest_LogError(SDLTEST_FINAL_RESULT_FORMAT, "Suite Setup", testSuite->name, COLOR_RED "Failed" COLOR_END);
|
||||
return TEST_RESULT_SETUP_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
/* Run test case function */
|
||||
testCaseResult = testCase->testCase(data);
|
||||
|
||||
/* Convert test execution result into harness result */
|
||||
if (testCaseResult == TEST_SKIPPED) {
|
||||
/* Test was programmatically skipped */
|
||||
testResult = TEST_RESULT_SKIPPED;
|
||||
} else if (testCaseResult == TEST_STARTED) {
|
||||
/* Test did not return a TEST_COMPLETED value; assume it failed */
|
||||
testResult = TEST_RESULT_FAILED;
|
||||
} else if (testCaseResult == TEST_ABORTED) {
|
||||
/* Test was aborted early; assume it failed */
|
||||
testResult = TEST_RESULT_FAILED;
|
||||
} else {
|
||||
/* Perform failure analysis based on asserts */
|
||||
testResult = SDLTest_AssertSummaryToTestResult();
|
||||
}
|
||||
|
||||
/* Maybe run suite cleanup function (ignore failed asserts) */
|
||||
if (testSuite->testTearDown) {
|
||||
testSuite->testTearDown(data);
|
||||
}
|
||||
|
||||
/* Cancel timeout timer */
|
||||
if (timer) {
|
||||
SDL_RemoveTimer(timer);
|
||||
}
|
||||
|
||||
/* Report on asserts and fuzzer usage */
|
||||
fuzzerCount = SDLTest_GetFuzzerInvocationCount();
|
||||
if (fuzzerCount > 0) {
|
||||
SDLTest_Log("Fuzzer invocations: %d", fuzzerCount);
|
||||
}
|
||||
|
||||
/* Final log based on test execution result */
|
||||
if (testCaseResult == TEST_SKIPPED) {
|
||||
/* Test was programmatically skipped */
|
||||
SDLTest_Log(SDLTEST_FINAL_RESULT_FORMAT, "Test", testCase->name, COLOR_BLUE "Skipped (Programmatically)" COLOR_END);
|
||||
} else if (testCaseResult == TEST_STARTED) {
|
||||
/* Test did not return a TEST_COMPLETED value; assume it failed */
|
||||
SDLTest_LogError(SDLTEST_FINAL_RESULT_FORMAT, "Test", testCase->name, COLOR_RED "Failed (test started, but did not return TEST_COMPLETED)" COLOR_END);
|
||||
} else if (testCaseResult == TEST_ABORTED) {
|
||||
/* Test was aborted early; assume it failed */
|
||||
SDLTest_LogError(SDLTEST_FINAL_RESULT_FORMAT, "Test", testCase->name, COLOR_RED "Failed (Aborted)" COLOR_END);
|
||||
} else {
|
||||
SDLTest_LogAssertSummary();
|
||||
}
|
||||
|
||||
return testResult;
|
||||
}
|
||||
|
||||
/* Prints summary of all suites/tests contained in the given reference */
|
||||
#if 0
|
||||
static void SDLTest_LogTestSuiteSummary(SDLTest_TestSuiteReference *testSuites)
|
||||
{
|
||||
int suiteCounter;
|
||||
int testCounter;
|
||||
SDLTest_TestSuiteReference *testSuite;
|
||||
SDLTest_TestCaseReference *testCase;
|
||||
|
||||
/* Loop over all suites */
|
||||
suiteCounter = 0;
|
||||
while (&testSuites[suiteCounter]) {
|
||||
testSuite=&testSuites[suiteCounter];
|
||||
suiteCounter++;
|
||||
SDLTest_Log("Test Suite %i - %s\n", suiteCounter,
|
||||
(testSuite->name) ? testSuite->name : SDLTEST_INVALID_NAME_FORMAT);
|
||||
|
||||
/* Loop over all test cases */
|
||||
testCounter = 0;
|
||||
while (testSuite->testCases[testCounter]) {
|
||||
testCase=(SDLTest_TestCaseReference *)testSuite->testCases[testCounter];
|
||||
testCounter++;
|
||||
SDLTest_Log(" Test Case %i - %s: %s", testCounter,
|
||||
(testCase->name) ? testCase->name : SDLTEST_INVALID_NAME_FORMAT,
|
||||
(testCase->description) ? testCase->description : SDLTEST_INVALID_NAME_FORMAT);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Gets a timer value in seconds */
|
||||
static float GetClock(void)
|
||||
{
|
||||
float currentClock = SDL_GetPerformanceCounter() / (float)SDL_GetPerformanceFrequency();
|
||||
return currentClock;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute a test suite using the given run seed and execution key.
|
||||
*
|
||||
* The filter string is matched to the suite name (full comparison) to select a single suite,
|
||||
* or if no suite matches, it is matched to the test names (full comparison) to select a single test.
|
||||
*
|
||||
* \param runner The runner to execute.
|
||||
*
|
||||
* \returns Test run result; 0 when all tests passed, 1 if any tests failed.
|
||||
*/
|
||||
int SDLTest_ExecuteTestSuiteRunner(SDLTest_TestSuiteRunner *runner)
|
||||
{
|
||||
int totalNumberOfTests = 0;
|
||||
int failedNumberOfTests = 0;
|
||||
int suiteCounter;
|
||||
int testCounter;
|
||||
int iterationCounter;
|
||||
SDLTest_TestSuiteReference *testSuite;
|
||||
const SDLTest_TestCaseReference *testCase;
|
||||
const char *runSeed = NULL;
|
||||
const char *currentSuiteName;
|
||||
const char *currentTestName;
|
||||
Uint64 execKey;
|
||||
float runStartSeconds;
|
||||
float suiteStartSeconds;
|
||||
float testStartSeconds;
|
||||
float runEndSeconds;
|
||||
float suiteEndSeconds;
|
||||
float testEndSeconds;
|
||||
float runtime;
|
||||
int suiteFilter = 0;
|
||||
const char *suiteFilterName = NULL;
|
||||
int testFilter = 0;
|
||||
const char *testFilterName = NULL;
|
||||
bool forceTestRun = false;
|
||||
int testResult = 0;
|
||||
int runResult = 0;
|
||||
int totalTestFailedCount = 0;
|
||||
int totalTestPassedCount = 0;
|
||||
int totalTestSkippedCount = 0;
|
||||
int testFailedCount = 0;
|
||||
int testPassedCount = 0;
|
||||
int testSkippedCount = 0;
|
||||
int countSum = 0;
|
||||
const SDLTest_TestCaseReference **failedTests;
|
||||
char generatedSeed[16 + 1];
|
||||
int nbSuites = 0;
|
||||
int i = 0;
|
||||
int *arraySuites = NULL;
|
||||
|
||||
/* Sanitize test iterations */
|
||||
if (runner->user.testIterations < 1) {
|
||||
runner->user.testIterations = 1;
|
||||
}
|
||||
|
||||
/* Generate run see if we don't have one already */
|
||||
if (!runner->user.runSeed || runner->user.runSeed[0] == '\0') {
|
||||
runSeed = SDLTest_GenerateRunSeed(generatedSeed, 16);
|
||||
if (!runSeed) {
|
||||
SDLTest_LogError("Generating a random seed failed");
|
||||
return 2;
|
||||
}
|
||||
} else {
|
||||
runSeed = runner->user.runSeed;
|
||||
}
|
||||
|
||||
/* Reset per-run counters */
|
||||
totalTestFailedCount = 0;
|
||||
totalTestPassedCount = 0;
|
||||
totalTestSkippedCount = 0;
|
||||
|
||||
/* Take time - run start */
|
||||
runStartSeconds = GetClock();
|
||||
|
||||
/* Log run with fuzzer parameters */
|
||||
SDLTest_Log("::::: Test Run /w seed '%s' started\n", runSeed);
|
||||
|
||||
/* Count the total number of tests */
|
||||
suiteCounter = 0;
|
||||
while (runner->user.testSuites[suiteCounter]) {
|
||||
testSuite = runner->user.testSuites[suiteCounter];
|
||||
suiteCounter++;
|
||||
testCounter = 0;
|
||||
while (testSuite->testCases[testCounter]) {
|
||||
testCounter++;
|
||||
totalNumberOfTests++;
|
||||
}
|
||||
}
|
||||
|
||||
if (totalNumberOfTests == 0) {
|
||||
SDLTest_LogError("No tests to run?");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Pre-allocate an array for tracking failed tests (potentially all test cases) */
|
||||
failedTests = (const SDLTest_TestCaseReference **)SDL_malloc(totalNumberOfTests * sizeof(SDLTest_TestCaseReference *));
|
||||
if (!failedTests) {
|
||||
SDLTest_LogError("Unable to allocate cache for failed tests");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Initialize filtering */
|
||||
if (runner->user.filter && runner->user.filter[0] != '\0') {
|
||||
/* Loop over all suites to check if we have a filter match */
|
||||
suiteCounter = 0;
|
||||
while (runner->user.testSuites[suiteCounter] && suiteFilter == 0) {
|
||||
testSuite = runner->user.testSuites[suiteCounter];
|
||||
suiteCounter++;
|
||||
if (testSuite->name && SDL_strcasecmp(runner->user.filter, testSuite->name) == 0) {
|
||||
/* Matched a suite name */
|
||||
suiteFilter = 1;
|
||||
suiteFilterName = testSuite->name;
|
||||
SDLTest_Log("Filtering: running only suite '%s'", suiteFilterName);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Within each suite, loop over all test cases to check if we have a filter match */
|
||||
testCounter = 0;
|
||||
while (testSuite->testCases[testCounter] && testFilter == 0) {
|
||||
testCase = testSuite->testCases[testCounter];
|
||||
testCounter++;
|
||||
if (testCase->name && SDL_strcasecmp(runner->user.filter, testCase->name) == 0) {
|
||||
/* Matched a test name */
|
||||
suiteFilter = 1;
|
||||
suiteFilterName = testSuite->name;
|
||||
testFilter = 1;
|
||||
testFilterName = testCase->name;
|
||||
SDLTest_Log("Filtering: running only test '%s' in suite '%s'", testFilterName, suiteFilterName);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (suiteFilter == 0 && testFilter == 0) {
|
||||
SDLTest_LogError("Filter '%s' did not match any test suite/case.", runner->user.filter);
|
||||
for (suiteCounter = 0; runner->user.testSuites[suiteCounter]; ++suiteCounter) {
|
||||
testSuite = runner->user.testSuites[suiteCounter];
|
||||
if (testSuite->name) {
|
||||
SDLTest_Log("Test suite: %s", testSuite->name);
|
||||
}
|
||||
|
||||
/* Within each suite, loop over all test cases to check if we have a filter match */
|
||||
for (testCounter = 0; testSuite->testCases[testCounter]; ++testCounter) {
|
||||
testCase = testSuite->testCases[testCounter];
|
||||
SDLTest_Log(" test: %s%s", testCase->name, testCase->enabled ? "" : " (disabled)");
|
||||
}
|
||||
}
|
||||
SDLTest_Log("Exit code: 2");
|
||||
SDL_free((void *)failedTests);
|
||||
return 2;
|
||||
}
|
||||
|
||||
runner->user.randomOrder = false;
|
||||
}
|
||||
|
||||
/* Number of test suites */
|
||||
while (runner->user.testSuites[nbSuites]) {
|
||||
nbSuites++;
|
||||
}
|
||||
|
||||
arraySuites = SDL_malloc(nbSuites * sizeof(int));
|
||||
if (!arraySuites) {
|
||||
SDL_free((void *)failedTests);
|
||||
return SDL_OutOfMemory();
|
||||
}
|
||||
for (i = 0; i < nbSuites; i++) {
|
||||
arraySuites[i] = i;
|
||||
}
|
||||
|
||||
/* Mix the list of suites to run them in random order */
|
||||
{
|
||||
/* Exclude last test "subsystemsTestSuite" which is said to interfere with other tests */
|
||||
nbSuites--;
|
||||
|
||||
if (runner->user.execKey != 0) {
|
||||
execKey = runner->user.execKey;
|
||||
} else {
|
||||
/* dummy values to have random numbers working */
|
||||
execKey = SDLTest_GenerateExecKey(runSeed, "random testSuites", "initialisation", 1);
|
||||
}
|
||||
|
||||
/* Initialize fuzzer */
|
||||
SDLTest_FuzzerInit(execKey);
|
||||
|
||||
i = 100;
|
||||
while (i--) {
|
||||
int a, b;
|
||||
int tmp;
|
||||
a = SDLTest_RandomIntegerInRange(0, nbSuites - 1);
|
||||
b = SDLTest_RandomIntegerInRange(0, nbSuites - 1);
|
||||
/*
|
||||
* NB: prevent swapping here to make sure the tests start with the same
|
||||
* random seed (whether they are run in order or not).
|
||||
* So we consume same number of SDLTest_RandomIntegerInRange() in all cases.
|
||||
*
|
||||
* If some random value were used at initialization before the tests start, the --seed wouldn't do the same with or without randomOrder.
|
||||
*/
|
||||
/* Swap */
|
||||
if (runner->user.randomOrder) {
|
||||
tmp = arraySuites[b];
|
||||
arraySuites[b] = arraySuites[a];
|
||||
arraySuites[a] = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
/* re-add last lest */
|
||||
nbSuites++;
|
||||
}
|
||||
|
||||
/* Loop over all suites */
|
||||
for (i = 0; i < nbSuites; i++) {
|
||||
suiteCounter = arraySuites[i];
|
||||
testSuite = runner->user.testSuites[suiteCounter];
|
||||
currentSuiteName = (testSuite->name ? testSuite->name : SDLTEST_INVALID_NAME_FORMAT);
|
||||
suiteCounter++;
|
||||
|
||||
/* Filter suite if flag set and we have a name */
|
||||
if (suiteFilter == 1 && suiteFilterName && testSuite->name &&
|
||||
SDL_strcasecmp(suiteFilterName, testSuite->name) != 0) {
|
||||
/* Skip suite */
|
||||
SDLTest_Log("===== Test Suite %i: '%s' " COLOR_BLUE "skipped" COLOR_END "\n",
|
||||
suiteCounter,
|
||||
currentSuiteName);
|
||||
} else {
|
||||
|
||||
int nbTestCases = 0;
|
||||
int *arrayTestCases;
|
||||
int j;
|
||||
while (testSuite->testCases[nbTestCases]) {
|
||||
nbTestCases++;
|
||||
}
|
||||
|
||||
arrayTestCases = SDL_malloc(nbTestCases * sizeof(int));
|
||||
if (!arrayTestCases) {
|
||||
SDL_free(arraySuites);
|
||||
SDL_free((void *)failedTests);
|
||||
return SDL_OutOfMemory();
|
||||
}
|
||||
for (j = 0; j < nbTestCases; j++) {
|
||||
arrayTestCases[j] = j;
|
||||
}
|
||||
|
||||
/* Mix the list of testCases to run them in random order */
|
||||
j = 100;
|
||||
while (j--) {
|
||||
int a, b;
|
||||
int tmp;
|
||||
a = SDLTest_RandomIntegerInRange(0, nbTestCases - 1);
|
||||
b = SDLTest_RandomIntegerInRange(0, nbTestCases - 1);
|
||||
/* Swap */
|
||||
/* See previous note */
|
||||
if (runner->user.randomOrder) {
|
||||
tmp = arrayTestCases[b];
|
||||
arrayTestCases[b] = arrayTestCases[a];
|
||||
arrayTestCases[a] = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
/* Reset per-suite counters */
|
||||
testFailedCount = 0;
|
||||
testPassedCount = 0;
|
||||
testSkippedCount = 0;
|
||||
|
||||
/* Take time - suite start */
|
||||
suiteStartSeconds = GetClock();
|
||||
|
||||
/* Log suite started */
|
||||
SDLTest_Log("===== Test Suite %i: '%s' started\n",
|
||||
suiteCounter,
|
||||
currentSuiteName);
|
||||
|
||||
/* Loop over all test cases */
|
||||
for (j = 0; j < nbTestCases; j++) {
|
||||
testCounter = arrayTestCases[j];
|
||||
testCase = testSuite->testCases[testCounter];
|
||||
currentTestName = (testCase->name ? testCase->name : SDLTEST_INVALID_NAME_FORMAT);
|
||||
testCounter++;
|
||||
|
||||
/* Filter tests if flag set and we have a name */
|
||||
if (testFilter == 1 && testFilterName && testCase->name &&
|
||||
SDL_strcasecmp(testFilterName, testCase->name) != 0) {
|
||||
/* Skip test */
|
||||
SDLTest_Log("===== Test Case %i.%i: '%s' " COLOR_BLUE "skipped" COLOR_END "\n",
|
||||
suiteCounter,
|
||||
testCounter,
|
||||
currentTestName);
|
||||
} else {
|
||||
/* Override 'disabled' flag if we specified a test filter (i.e. force run for debugging) */
|
||||
if (testFilter == 1 && !testCase->enabled) {
|
||||
SDLTest_Log("Force run of disabled test since test filter was set");
|
||||
forceTestRun = true;
|
||||
}
|
||||
|
||||
/* Take time - test start */
|
||||
testStartSeconds = GetClock();
|
||||
|
||||
/* Log test started */
|
||||
SDLTest_Log(COLOR_YELLOW "----- Test Case %i.%i: '%s' started" COLOR_END,
|
||||
suiteCounter,
|
||||
testCounter,
|
||||
currentTestName);
|
||||
if (testCase->description && testCase->description[0] != '\0') {
|
||||
SDLTest_Log("Test Description: '%s'",
|
||||
(testCase->description) ? testCase->description : SDLTEST_INVALID_NAME_FORMAT);
|
||||
}
|
||||
|
||||
/* Loop over all iterations */
|
||||
iterationCounter = 0;
|
||||
while (iterationCounter < runner->user.testIterations) {
|
||||
iterationCounter++;
|
||||
|
||||
if (runner->user.execKey != 0) {
|
||||
execKey = runner->user.execKey;
|
||||
} else {
|
||||
execKey = SDLTest_GenerateExecKey(runSeed, testSuite->name, testCase->name, iterationCounter);
|
||||
}
|
||||
|
||||
SDLTest_Log("Test Iteration %i: execKey %" SDL_PRIu64, iterationCounter, execKey);
|
||||
testResult = SDLTest_RunTest(testSuite, testCase, execKey, forceTestRun);
|
||||
|
||||
if (testResult == TEST_RESULT_PASSED) {
|
||||
testPassedCount++;
|
||||
totalTestPassedCount++;
|
||||
} else if (testResult == TEST_RESULT_SKIPPED) {
|
||||
testSkippedCount++;
|
||||
totalTestSkippedCount++;
|
||||
} else {
|
||||
testFailedCount++;
|
||||
totalTestFailedCount++;
|
||||
}
|
||||
}
|
||||
|
||||
/* Take time - test end */
|
||||
testEndSeconds = GetClock();
|
||||
runtime = testEndSeconds - testStartSeconds;
|
||||
if (runtime < 0.0f) {
|
||||
runtime = 0.0f;
|
||||
}
|
||||
|
||||
if (runner->user.testIterations > 1) {
|
||||
/* Log test runtime */
|
||||
SDLTest_Log("Runtime of %i iterations: %.1f sec", runner->user.testIterations, runtime);
|
||||
SDLTest_Log("Average Test runtime: %.5f sec", runtime / (float)runner->user.testIterations);
|
||||
} else {
|
||||
/* Log test runtime */
|
||||
SDLTest_Log("Total Test runtime: %.1f sec", runtime);
|
||||
}
|
||||
|
||||
/* Log final test result */
|
||||
switch (testResult) {
|
||||
case TEST_RESULT_PASSED:
|
||||
SDLTest_Log(SDLTEST_FINAL_RESULT_FORMAT, "Test", currentTestName, COLOR_GREEN "Passed" COLOR_END);
|
||||
break;
|
||||
case TEST_RESULT_FAILED:
|
||||
SDLTest_LogError(SDLTEST_FINAL_RESULT_FORMAT, "Test", currentTestName, COLOR_RED "Failed" COLOR_END);
|
||||
break;
|
||||
case TEST_RESULT_NO_ASSERT:
|
||||
SDLTest_LogError(SDLTEST_FINAL_RESULT_FORMAT, "Test", currentTestName, COLOR_BLUE "No Asserts" COLOR_END);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Collect failed test case references for repro-step display */
|
||||
if (testResult == TEST_RESULT_FAILED) {
|
||||
failedTests[failedNumberOfTests] = testCase;
|
||||
failedNumberOfTests++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Take time - suite end */
|
||||
suiteEndSeconds = GetClock();
|
||||
runtime = suiteEndSeconds - suiteStartSeconds;
|
||||
if (runtime < 0.0f) {
|
||||
runtime = 0.0f;
|
||||
}
|
||||
|
||||
/* Log suite runtime */
|
||||
SDLTest_Log("Total Suite runtime: %.1f sec", runtime);
|
||||
|
||||
/* Log summary and final Suite result */
|
||||
countSum = testPassedCount + testFailedCount + testSkippedCount;
|
||||
if (testFailedCount == 0) {
|
||||
SDLTest_Log(SDLTEST_LOG_SUMMARY_FORMAT_OK, "Suite", countSum, testPassedCount, testFailedCount, testSkippedCount);
|
||||
SDLTest_Log(SDLTEST_FINAL_RESULT_FORMAT, "Suite", currentSuiteName, COLOR_GREEN "Passed" COLOR_END);
|
||||
} else {
|
||||
SDLTest_LogError(SDLTEST_LOG_SUMMARY_FORMAT, "Suite", countSum, testPassedCount, testFailedCount, testSkippedCount);
|
||||
SDLTest_LogError(SDLTEST_FINAL_RESULT_FORMAT, "Suite", currentSuiteName, COLOR_RED "Failed" COLOR_END);
|
||||
}
|
||||
|
||||
SDL_free(arrayTestCases);
|
||||
}
|
||||
}
|
||||
|
||||
SDL_free(arraySuites);
|
||||
|
||||
/* Take time - run end */
|
||||
runEndSeconds = GetClock();
|
||||
runtime = runEndSeconds - runStartSeconds;
|
||||
if (runtime < 0.0f) {
|
||||
runtime = 0.0f;
|
||||
}
|
||||
|
||||
/* Log total runtime */
|
||||
SDLTest_Log("Total Run runtime: %.1f sec", runtime);
|
||||
|
||||
/* Log summary and final run result */
|
||||
countSum = totalTestPassedCount + totalTestFailedCount + totalTestSkippedCount;
|
||||
if (totalTestFailedCount == 0) {
|
||||
runResult = 0;
|
||||
SDLTest_Log(SDLTEST_LOG_SUMMARY_FORMAT_OK, "Run", countSum, totalTestPassedCount, totalTestFailedCount, totalTestSkippedCount);
|
||||
SDLTest_Log(SDLTEST_FINAL_RESULT_FORMAT, "Run /w seed", runSeed, COLOR_GREEN "Passed" COLOR_END);
|
||||
} else {
|
||||
runResult = 1;
|
||||
SDLTest_LogError(SDLTEST_LOG_SUMMARY_FORMAT, "Run", countSum, totalTestPassedCount, totalTestFailedCount, totalTestSkippedCount);
|
||||
SDLTest_LogError(SDLTEST_FINAL_RESULT_FORMAT, "Run /w seed", runSeed, COLOR_RED "Failed" COLOR_END);
|
||||
}
|
||||
|
||||
/* Print repro steps for failed tests */
|
||||
if (failedNumberOfTests > 0) {
|
||||
SDLTest_Log("Harness input to repro failures:");
|
||||
for (testCounter = 0; testCounter < failedNumberOfTests; testCounter++) {
|
||||
SDLTest_Log(COLOR_RED " --seed %s --filter %s" COLOR_END, runSeed, failedTests[testCounter]->name);
|
||||
}
|
||||
}
|
||||
SDL_free((void *)failedTests);
|
||||
|
||||
SDLTest_Log("Exit code: %d", runResult);
|
||||
return runResult;
|
||||
}
|
||||
|
||||
static int SDLCALL SDLTest_TestSuiteCommonArg(void *data, char **argv, int index)
|
||||
{
|
||||
SDLTest_TestSuiteRunner *runner = data;
|
||||
|
||||
if (SDL_strcasecmp(argv[index], "--iterations") == 0) {
|
||||
if (argv[index + 1]) {
|
||||
runner->user.testIterations = SDL_atoi(argv[index + 1]);
|
||||
if (runner->user.testIterations < 1) {
|
||||
runner->user.testIterations = 1;
|
||||
}
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
else if (SDL_strcasecmp(argv[index], "--execKey") == 0) {
|
||||
if (argv[index + 1]) {
|
||||
(void)SDL_sscanf(argv[index + 1], "%" SDL_PRIu64, &runner->user.execKey);
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
else if (SDL_strcasecmp(argv[index], "--seed") == 0) {
|
||||
if (argv[index + 1]) {
|
||||
runner->user.runSeed = SDL_strdup(argv[index + 1]);
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
else if (SDL_strcasecmp(argv[index], "--filter") == 0) {
|
||||
if (argv[index + 1]) {
|
||||
runner->user.filter = SDL_strdup(argv[index + 1]);
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
else if (SDL_strcasecmp(argv[index], "--random-order") == 0) {
|
||||
runner->user.randomOrder = true;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
SDLTest_TestSuiteRunner *SDLTest_CreateTestSuiteRunner(SDLTest_CommonState *state, SDLTest_TestSuiteReference *testSuites[])
|
||||
{
|
||||
SDLTest_TestSuiteRunner *runner;
|
||||
SDLTest_ArgumentParser *argparser;
|
||||
|
||||
if (!state) {
|
||||
SDLTest_LogError("SDL Test Suites require a common state");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
runner = SDL_calloc(1, sizeof(SDLTest_TestSuiteRunner));
|
||||
if (!runner) {
|
||||
SDLTest_LogError("Failed to allocate memory for test suite runner");
|
||||
return NULL;
|
||||
}
|
||||
runner->user.testSuites = testSuites;
|
||||
|
||||
runner->argparser.parse_arguments = SDLTest_TestSuiteCommonArg;
|
||||
runner->argparser.usage = common_harness_usage;
|
||||
runner->argparser.data = runner;
|
||||
|
||||
/* Find last argument description and append our description */
|
||||
argparser = state->argparser;
|
||||
for (;;) {
|
||||
if (argparser->next == NULL) {
|
||||
argparser->next = &runner->argparser;
|
||||
break;
|
||||
}
|
||||
argparser = argparser->next;
|
||||
|
||||
}
|
||||
|
||||
return runner;
|
||||
}
|
||||
|
||||
void SDLTest_DestroyTestSuiteRunner(SDLTest_TestSuiteRunner *runner) {
|
||||
|
||||
SDL_free(runner->user.filter);
|
||||
SDL_free(runner->user.runSeed);
|
||||
SDL_free(runner);
|
||||
}
|
||||
211
vendor/sdl-3.2.10/src/test/SDL_test_log.c
vendored
Normal file
211
vendor/sdl-3.2.10/src/test/SDL_test_log.c
vendored
Normal file
|
|
@ -0,0 +1,211 @@
|
|||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
/*
|
||||
|
||||
Used by the test framework and test cases.
|
||||
|
||||
*/
|
||||
|
||||
/* quiet windows compiler warnings */
|
||||
#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS)
|
||||
#define _CRT_SECURE_NO_WARNINGS
|
||||
#endif
|
||||
#include <SDL3/SDL_test.h>
|
||||
|
||||
#include <time.h> /* Needed for localtime() */
|
||||
|
||||
/* work around compiler warning on older GCCs. */
|
||||
#if (defined(__GNUC__) && (__GNUC__ <= 2))
|
||||
static size_t strftime_gcc2_workaround(char *s, size_t max, const char *fmt, const struct tm *tm)
|
||||
{
|
||||
return strftime(s, max, fmt, tm);
|
||||
}
|
||||
#ifdef strftime
|
||||
#undef strftime
|
||||
#endif
|
||||
#define strftime strftime_gcc2_workaround
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Converts unix timestamp to its ascii representation in localtime
|
||||
*
|
||||
* Note: Uses a static buffer internally, so the return value
|
||||
* isn't valid after the next call of this function. If you
|
||||
* want to retain the return value, make a copy of it.
|
||||
*
|
||||
* \param timestamp A Timestamp, i.e. time(0)
|
||||
*
|
||||
* \return Ascii representation of the timestamp in localtime in the format '08/23/01 14:55:02'
|
||||
*/
|
||||
static const char *SDLTest_TimestampToString(const time_t timestamp)
|
||||
{
|
||||
time_t copy;
|
||||
static char buffer[64];
|
||||
struct tm *local;
|
||||
size_t result = 0;
|
||||
|
||||
SDL_memset(buffer, 0, sizeof(buffer));
|
||||
copy = timestamp;
|
||||
local = localtime(©);
|
||||
result = strftime(buffer, sizeof(buffer), "%x %X", local);
|
||||
if (result == 0) {
|
||||
return "";
|
||||
}
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
/*
|
||||
* Prints given message with a timestamp in the TEST category and INFO priority.
|
||||
*/
|
||||
void SDLTest_Log(SDL_PRINTF_FORMAT_STRING const char *fmt, ...)
|
||||
{
|
||||
va_list list;
|
||||
char logMessage[SDLTEST_MAX_LOGMESSAGE_LENGTH];
|
||||
|
||||
/* Print log message into a buffer */
|
||||
SDL_memset(logMessage, 0, SDLTEST_MAX_LOGMESSAGE_LENGTH);
|
||||
va_start(list, fmt);
|
||||
(void)SDL_vsnprintf(logMessage, SDLTEST_MAX_LOGMESSAGE_LENGTH - 1, fmt, list);
|
||||
va_end(list);
|
||||
|
||||
/* Log with timestamp and newline */
|
||||
SDL_LogMessage(SDL_LOG_CATEGORY_TEST, SDL_LOG_PRIORITY_INFO, " %s: %s", SDLTest_TimestampToString(time(0)), logMessage);
|
||||
}
|
||||
|
||||
/*
|
||||
* Prints given message with a timestamp in the TEST category and the ERROR priority.
|
||||
*/
|
||||
void SDLTest_LogError(SDL_PRINTF_FORMAT_STRING const char *fmt, ...)
|
||||
{
|
||||
va_list list;
|
||||
char logMessage[SDLTEST_MAX_LOGMESSAGE_LENGTH];
|
||||
|
||||
/* Print log message into a buffer */
|
||||
SDL_memset(logMessage, 0, SDLTEST_MAX_LOGMESSAGE_LENGTH);
|
||||
va_start(list, fmt);
|
||||
(void)SDL_vsnprintf(logMessage, SDLTEST_MAX_LOGMESSAGE_LENGTH - 1, fmt, list);
|
||||
va_end(list);
|
||||
|
||||
/* Log with timestamp and newline */
|
||||
SDL_LogMessage(SDL_LOG_CATEGORY_TEST, SDL_LOG_PRIORITY_ERROR, "%s: %s", SDLTest_TimestampToString(time(0)), logMessage);
|
||||
}
|
||||
|
||||
static char nibble_to_char(Uint8 nibble)
|
||||
{
|
||||
if (nibble < 0xa) {
|
||||
return '0' + nibble;
|
||||
} else {
|
||||
return 'a' + nibble - 10;
|
||||
}
|
||||
}
|
||||
|
||||
void SDLTest_LogEscapedString(const char *prefix, const void *buffer, size_t size)
|
||||
{
|
||||
const Uint8 *data = buffer;
|
||||
char logMessage[SDLTEST_MAX_LOGMESSAGE_LENGTH];
|
||||
|
||||
if (data) {
|
||||
size_t i;
|
||||
size_t pos = 0;
|
||||
#define NEED_X_CHARS(N) \
|
||||
if (pos + (N) > sizeof(logMessage) - 2) { \
|
||||
break; \
|
||||
}
|
||||
|
||||
logMessage[pos++] = '"';
|
||||
for (i = 0; i < size; i++) {
|
||||
Uint8 c = data[i];
|
||||
size_t pos_start = pos;
|
||||
switch (c) {
|
||||
case '\0':
|
||||
NEED_X_CHARS(2);
|
||||
logMessage[pos++] = '\\';
|
||||
logMessage[pos++] = '0';
|
||||
break;
|
||||
case '"':
|
||||
NEED_X_CHARS(2);
|
||||
logMessage[pos++] = '\\';
|
||||
logMessage[pos++] = '"';
|
||||
break;
|
||||
case '\n':
|
||||
NEED_X_CHARS(2);
|
||||
logMessage[pos++] = '\\';
|
||||
logMessage[pos++] = 'n';
|
||||
break;
|
||||
case '\r':
|
||||
NEED_X_CHARS(2);
|
||||
logMessage[pos++] = '\\';
|
||||
logMessage[pos++] = 'r';
|
||||
break;
|
||||
case '\t':
|
||||
NEED_X_CHARS(2);
|
||||
logMessage[pos++] = '\\';
|
||||
logMessage[pos++] = 't';
|
||||
break;
|
||||
case '\f':
|
||||
NEED_X_CHARS(2);
|
||||
logMessage[pos++] = '\\';
|
||||
logMessage[pos++] = 'f';
|
||||
break;
|
||||
case '\b':
|
||||
NEED_X_CHARS(2);
|
||||
logMessage[pos++] = '\\';
|
||||
logMessage[pos++] = 'b';
|
||||
break;
|
||||
case '\\':
|
||||
NEED_X_CHARS(2);
|
||||
logMessage[pos++] = '\\';
|
||||
logMessage[pos++] = '\\';
|
||||
break;
|
||||
default:
|
||||
if (SDL_isprint(c)) {
|
||||
NEED_X_CHARS(1);
|
||||
logMessage[pos++] = c;
|
||||
} else {
|
||||
NEED_X_CHARS(4);
|
||||
logMessage[pos++] = '\\';
|
||||
logMessage[pos++] = 'x';
|
||||
logMessage[pos++] = nibble_to_char(c >> 4);
|
||||
logMessage[pos++] = nibble_to_char(c & 0xf);
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (pos == pos_start) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i < size) {
|
||||
logMessage[sizeof(logMessage) - 4] = '.';
|
||||
logMessage[sizeof(logMessage) - 3] = '.';
|
||||
logMessage[sizeof(logMessage) - 2] = '.';
|
||||
logMessage[sizeof(logMessage) - 1] = '\0';
|
||||
} else {
|
||||
logMessage[pos++] = '"';
|
||||
logMessage[pos] = '\0';
|
||||
}
|
||||
} else {
|
||||
SDL_strlcpy(logMessage, "(nil)", sizeof(logMessage));
|
||||
}
|
||||
|
||||
SDLTest_Log("%s%s", prefix, logMessage);
|
||||
}
|
||||
342
vendor/sdl-3.2.10/src/test/SDL_test_md5.c
vendored
Normal file
342
vendor/sdl-3.2.10/src/test/SDL_test_md5.c
vendored
Normal file
|
|
@ -0,0 +1,342 @@
|
|||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
/*
|
||||
***********************************************************************
|
||||
** RSA Data Security, Inc. MD5 Message-Digest Algorithm **
|
||||
** Created: 2/17/90 RLR **
|
||||
** Revised: 1/91 SRD,AJ,BSK,JT Reference C ver., 7/10 constant corr. **
|
||||
***********************************************************************
|
||||
*/
|
||||
|
||||
/*
|
||||
***********************************************************************
|
||||
** Copyright (C) 1990, RSA Data Security, Inc. All rights reserved. **
|
||||
** **
|
||||
** License to copy and use this software is granted provided that **
|
||||
** it is identified as the "RSA Data Security, Inc. MD5 Message- **
|
||||
** Digest Algorithm" in all material mentioning or referencing this **
|
||||
** software or this function. **
|
||||
** **
|
||||
** License is also granted to make and use derivative works **
|
||||
** provided that such works are identified as "derived from the RSA **
|
||||
** Data Security, Inc. MD5 Message-Digest Algorithm" in all **
|
||||
** material mentioning or referencing the derived work. **
|
||||
** **
|
||||
** RSA Data Security, Inc. makes no representations concerning **
|
||||
** either the merchantability of this software or the suitability **
|
||||
** of this software for any particular purpose. It is provided "as **
|
||||
** is" without express or implied warranty of any kind. **
|
||||
** **
|
||||
** These notices must be retained in any copies of any part of this **
|
||||
** documentation and/or software. **
|
||||
***********************************************************************
|
||||
*/
|
||||
#include <SDL3/SDL_test.h>
|
||||
|
||||
/* Forward declaration of static helper function */
|
||||
static void SDLTest_Md5Transform(MD5UINT4 *buf, const MD5UINT4 *in);
|
||||
|
||||
static unsigned char MD5PADDING[64] = {
|
||||
0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||
};
|
||||
|
||||
/* F, G, H and I are basic MD5 functions */
|
||||
#define F(x, y, z) (((x) & (y)) | ((~(x)) & (z)))
|
||||
#define G(x, y, z) (((x) & (z)) | ((y) & (~(z))))
|
||||
#define H(x, y, z) ((x) ^ (y) ^ (z))
|
||||
#define I(x, y, z) ((y) ^ ((x) | (~(z))))
|
||||
|
||||
/* ROTATE_LEFT rotates x left n bits */
|
||||
#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n))))
|
||||
|
||||
/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4 */
|
||||
|
||||
/* Rotation is separate from addition to prevent recomputation */
|
||||
#define FF(a, b, c, d, x, s, ac) \
|
||||
{ \
|
||||
(a) += F((b), (c), (d)) + (x) + (MD5UINT4)(ac); \
|
||||
(a) = ROTATE_LEFT((a), (s)); \
|
||||
(a) += (b); \
|
||||
}
|
||||
#define GG(a, b, c, d, x, s, ac) \
|
||||
{ \
|
||||
(a) += G((b), (c), (d)) + (x) + (MD5UINT4)(ac); \
|
||||
(a) = ROTATE_LEFT((a), (s)); \
|
||||
(a) += (b); \
|
||||
}
|
||||
#define HH(a, b, c, d, x, s, ac) \
|
||||
{ \
|
||||
(a) += H((b), (c), (d)) + (x) + (MD5UINT4)(ac); \
|
||||
(a) = ROTATE_LEFT((a), (s)); \
|
||||
(a) += (b); \
|
||||
}
|
||||
#define II(a, b, c, d, x, s, ac) \
|
||||
{ \
|
||||
(a) += I((b), (c), (d)) + (x) + (MD5UINT4)(ac); \
|
||||
(a) = ROTATE_LEFT((a), (s)); \
|
||||
(a) += (b); \
|
||||
}
|
||||
|
||||
/*
|
||||
The routine MD5Init initializes the message-digest context
|
||||
mdContext. All fields are set to zero.
|
||||
*/
|
||||
|
||||
void SDLTest_Md5Init(SDLTest_Md5Context *mdContext)
|
||||
{
|
||||
if (!mdContext) {
|
||||
return;
|
||||
}
|
||||
|
||||
mdContext->i[0] = mdContext->i[1] = (MD5UINT4)0;
|
||||
|
||||
/*
|
||||
* Load magic initialization constants.
|
||||
*/
|
||||
mdContext->buf[0] = (MD5UINT4)0x67452301;
|
||||
mdContext->buf[1] = (MD5UINT4)0xefcdab89;
|
||||
mdContext->buf[2] = (MD5UINT4)0x98badcfe;
|
||||
mdContext->buf[3] = (MD5UINT4)0x10325476;
|
||||
}
|
||||
|
||||
/*
|
||||
The routine MD5Update updates the message-digest context to
|
||||
account for the presence of each of the characters inBuf[0..inLen-1]
|
||||
in the message whose digest is being computed.
|
||||
*/
|
||||
|
||||
void SDLTest_Md5Update(SDLTest_Md5Context *mdContext, unsigned char *inBuf,
|
||||
unsigned int inLen)
|
||||
{
|
||||
MD5UINT4 in[16];
|
||||
int mdi;
|
||||
unsigned int i, ii;
|
||||
|
||||
if (!mdContext) {
|
||||
return;
|
||||
}
|
||||
if (!inBuf || inLen < 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* compute number of bytes mod 64
|
||||
*/
|
||||
mdi = (int)((mdContext->i[0] >> 3) & 0x3F);
|
||||
|
||||
/*
|
||||
* update number of bits
|
||||
*/
|
||||
if ((mdContext->i[0] + ((MD5UINT4)inLen << 3)) < mdContext->i[0]) {
|
||||
mdContext->i[1]++;
|
||||
}
|
||||
mdContext->i[0] += ((MD5UINT4)inLen << 3);
|
||||
mdContext->i[1] += ((MD5UINT4)inLen >> 29);
|
||||
|
||||
while (inLen--) {
|
||||
/*
|
||||
* add new character to buffer, increment mdi
|
||||
*/
|
||||
mdContext->in[mdi++] = *inBuf++;
|
||||
|
||||
/*
|
||||
* transform if necessary
|
||||
*/
|
||||
if (mdi == 0x40) {
|
||||
for (i = 0, ii = 0; i < 16; i++, ii += 4) {
|
||||
in[i] = (((MD5UINT4)mdContext->in[ii + 3]) << 24) | (((MD5UINT4)mdContext->in[ii + 2]) << 16) | (((MD5UINT4)mdContext->in[ii + 1]) << 8) | ((MD5UINT4)mdContext->in[ii]);
|
||||
}
|
||||
SDLTest_Md5Transform(mdContext->buf, in);
|
||||
mdi = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
The routine MD5Final terminates the message-digest computation and
|
||||
ends with the desired message digest in mdContext->digest[0...15].
|
||||
*/
|
||||
|
||||
void SDLTest_Md5Final(SDLTest_Md5Context *mdContext)
|
||||
{
|
||||
MD5UINT4 in[16];
|
||||
int mdi;
|
||||
unsigned int i, ii;
|
||||
unsigned int padLen;
|
||||
|
||||
if (!mdContext) {
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* save number of bits
|
||||
*/
|
||||
in[14] = mdContext->i[0];
|
||||
in[15] = mdContext->i[1];
|
||||
|
||||
/*
|
||||
* compute number of bytes mod 64
|
||||
*/
|
||||
mdi = (int)((mdContext->i[0] >> 3) & 0x3F);
|
||||
|
||||
/*
|
||||
* pad out to 56 mod 64
|
||||
*/
|
||||
padLen = (mdi < 56) ? (56 - mdi) : (120 - mdi);
|
||||
SDLTest_Md5Update(mdContext, MD5PADDING, padLen);
|
||||
|
||||
/*
|
||||
* append length in bits and transform
|
||||
*/
|
||||
for (i = 0, ii = 0; i < 14; i++, ii += 4) {
|
||||
in[i] = (((MD5UINT4)mdContext->in[ii + 3]) << 24) | (((MD5UINT4)mdContext->in[ii + 2]) << 16) | (((MD5UINT4)mdContext->in[ii + 1]) << 8) | ((MD5UINT4)mdContext->in[ii]);
|
||||
}
|
||||
SDLTest_Md5Transform(mdContext->buf, in);
|
||||
|
||||
/*
|
||||
* store buffer in digest
|
||||
*/
|
||||
for (i = 0, ii = 0; i < 4; i++, ii += 4) {
|
||||
mdContext->digest[ii] = (unsigned char)(mdContext->buf[i] & 0xFF);
|
||||
mdContext->digest[ii + 1] =
|
||||
(unsigned char)((mdContext->buf[i] >> 8) & 0xFF);
|
||||
mdContext->digest[ii + 2] =
|
||||
(unsigned char)((mdContext->buf[i] >> 16) & 0xFF);
|
||||
mdContext->digest[ii + 3] =
|
||||
(unsigned char)((mdContext->buf[i] >> 24) & 0xFF);
|
||||
}
|
||||
}
|
||||
|
||||
/* Basic MD5 step. Transforms buf based on in.
|
||||
*/
|
||||
static void SDLTest_Md5Transform(MD5UINT4 *buf, const MD5UINT4 *in)
|
||||
{
|
||||
MD5UINT4 a = buf[0], b = buf[1], c = buf[2], d = buf[3];
|
||||
|
||||
/*
|
||||
* Round 1
|
||||
*/
|
||||
#define S11 7
|
||||
#define S12 12
|
||||
#define S13 17
|
||||
#define S14 22
|
||||
FF(a, b, c, d, in[0], S11, 3614090360u); /* 1 */
|
||||
FF(d, a, b, c, in[1], S12, 3905402710u); /* 2 */
|
||||
FF(c, d, a, b, in[2], S13, 606105819u); /* 3 */
|
||||
FF(b, c, d, a, in[3], S14, 3250441966u); /* 4 */
|
||||
FF(a, b, c, d, in[4], S11, 4118548399u); /* 5 */
|
||||
FF(d, a, b, c, in[5], S12, 1200080426u); /* 6 */
|
||||
FF(c, d, a, b, in[6], S13, 2821735955u); /* 7 */
|
||||
FF(b, c, d, a, in[7], S14, 4249261313u); /* 8 */
|
||||
FF(a, b, c, d, in[8], S11, 1770035416u); /* 9 */
|
||||
FF(d, a, b, c, in[9], S12, 2336552879u); /* 10 */
|
||||
FF(c, d, a, b, in[10], S13, 4294925233u); /* 11 */
|
||||
FF(b, c, d, a, in[11], S14, 2304563134u); /* 12 */
|
||||
FF(a, b, c, d, in[12], S11, 1804603682u); /* 13 */
|
||||
FF(d, a, b, c, in[13], S12, 4254626195u); /* 14 */
|
||||
FF(c, d, a, b, in[14], S13, 2792965006u); /* 15 */
|
||||
FF(b, c, d, a, in[15], S14, 1236535329u); /* 16 */
|
||||
|
||||
/*
|
||||
* Round 2
|
||||
*/
|
||||
#define S21 5
|
||||
#define S22 9
|
||||
#define S23 14
|
||||
#define S24 20
|
||||
GG(a, b, c, d, in[1], S21, 4129170786u); /* 17 */
|
||||
GG(d, a, b, c, in[6], S22, 3225465664u); /* 18 */
|
||||
GG(c, d, a, b, in[11], S23, 643717713u); /* 19 */
|
||||
GG(b, c, d, a, in[0], S24, 3921069994u); /* 20 */
|
||||
GG(a, b, c, d, in[5], S21, 3593408605u); /* 21 */
|
||||
GG(d, a, b, c, in[10], S22, 38016083u); /* 22 */
|
||||
GG(c, d, a, b, in[15], S23, 3634488961u); /* 23 */
|
||||
GG(b, c, d, a, in[4], S24, 3889429448u); /* 24 */
|
||||
GG(a, b, c, d, in[9], S21, 568446438u); /* 25 */
|
||||
GG(d, a, b, c, in[14], S22, 3275163606u); /* 26 */
|
||||
GG(c, d, a, b, in[3], S23, 4107603335u); /* 27 */
|
||||
GG(b, c, d, a, in[8], S24, 1163531501u); /* 28 */
|
||||
GG(a, b, c, d, in[13], S21, 2850285829u); /* 29 */
|
||||
GG(d, a, b, c, in[2], S22, 4243563512u); /* 30 */
|
||||
GG(c, d, a, b, in[7], S23, 1735328473u); /* 31 */
|
||||
GG(b, c, d, a, in[12], S24, 2368359562u); /* 32 */
|
||||
|
||||
/*
|
||||
* Round 3
|
||||
*/
|
||||
#define S31 4
|
||||
#define S32 11
|
||||
#define S33 16
|
||||
#define S34 23
|
||||
HH(a, b, c, d, in[5], S31, 4294588738u); /* 33 */
|
||||
HH(d, a, b, c, in[8], S32, 2272392833u); /* 34 */
|
||||
HH(c, d, a, b, in[11], S33, 1839030562u); /* 35 */
|
||||
HH(b, c, d, a, in[14], S34, 4259657740u); /* 36 */
|
||||
HH(a, b, c, d, in[1], S31, 2763975236u); /* 37 */
|
||||
HH(d, a, b, c, in[4], S32, 1272893353u); /* 38 */
|
||||
HH(c, d, a, b, in[7], S33, 4139469664u); /* 39 */
|
||||
HH(b, c, d, a, in[10], S34, 3200236656u); /* 40 */
|
||||
HH(a, b, c, d, in[13], S31, 681279174u); /* 41 */
|
||||
HH(d, a, b, c, in[0], S32, 3936430074u); /* 42 */
|
||||
HH(c, d, a, b, in[3], S33, 3572445317u); /* 43 */
|
||||
HH(b, c, d, a, in[6], S34, 76029189u); /* 44 */
|
||||
HH(a, b, c, d, in[9], S31, 3654602809u); /* 45 */
|
||||
HH(d, a, b, c, in[12], S32, 3873151461u); /* 46 */
|
||||
HH(c, d, a, b, in[15], S33, 530742520u); /* 47 */
|
||||
HH(b, c, d, a, in[2], S34, 3299628645u); /* 48 */
|
||||
|
||||
/*
|
||||
* Round 4
|
||||
*/
|
||||
#define S41 6
|
||||
#define S42 10
|
||||
#define S43 15
|
||||
#define S44 21
|
||||
II(a, b, c, d, in[0], S41, 4096336452u); /* 49 */
|
||||
II(d, a, b, c, in[7], S42, 1126891415u); /* 50 */
|
||||
II(c, d, a, b, in[14], S43, 2878612391u); /* 51 */
|
||||
II(b, c, d, a, in[5], S44, 4237533241u); /* 52 */
|
||||
II(a, b, c, d, in[12], S41, 1700485571u); /* 53 */
|
||||
II(d, a, b, c, in[3], S42, 2399980690u); /* 54 */
|
||||
II(c, d, a, b, in[10], S43, 4293915773u); /* 55 */
|
||||
II(b, c, d, a, in[1], S44, 2240044497u); /* 56 */
|
||||
II(a, b, c, d, in[8], S41, 1873313359u); /* 57 */
|
||||
II(d, a, b, c, in[15], S42, 4264355552u); /* 58 */
|
||||
II(c, d, a, b, in[6], S43, 2734768916u); /* 59 */
|
||||
II(b, c, d, a, in[13], S44, 1309151649u); /* 60 */
|
||||
II(a, b, c, d, in[4], S41, 4149444226u); /* 61 */
|
||||
II(d, a, b, c, in[11], S42, 3174756917u); /* 62 */
|
||||
II(c, d, a, b, in[2], S43, 718787259u); /* 63 */
|
||||
II(b, c, d, a, in[9], S44, 3951481745u); /* 64 */
|
||||
|
||||
buf[0] += a;
|
||||
buf[1] += b;
|
||||
buf[2] += c;
|
||||
buf[3] += d;
|
||||
}
|
||||
458
vendor/sdl-3.2.10/src/test/SDL_test_memory.c
vendored
Normal file
458
vendor/sdl-3.2.10/src/test/SDL_test_memory.c
vendored
Normal file
|
|
@ -0,0 +1,458 @@
|
|||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
#include <SDL3/SDL_test.h>
|
||||
|
||||
#ifdef HAVE_LIBUNWIND_H
|
||||
#define UNW_LOCAL_ONLY
|
||||
#include <libunwind.h>
|
||||
#ifndef unw_get_proc_name_by_ip
|
||||
#define SDLTEST_UNWIND_NO_PROC_NAME_BY_IP
|
||||
static bool s_unwind_symbol_names = true;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef SDL_PLATFORM_WIN32
|
||||
#include <windows.h>
|
||||
#include <dbghelp.h>
|
||||
|
||||
static struct {
|
||||
SDL_SharedObject *module;
|
||||
BOOL (WINAPI *pSymInitialize)(HANDLE hProcess, PCSTR UserSearchPath, BOOL fInvadeProcess);
|
||||
BOOL (WINAPI *pSymFromAddr)(HANDLE hProcess, DWORD64 Address, PDWORD64 Displacement, PSYMBOL_INFO Symbol);
|
||||
BOOL (WINAPI *pSymGetLineFromAddr64)(HANDLE hProcess, DWORD64 qwAddr, PDWORD pdwDisplacement, PIMAGEHLP_LINE64 Line);
|
||||
} dyn_dbghelp;
|
||||
|
||||
/* older SDKs might not have this: */
|
||||
__declspec(dllimport) USHORT WINAPI RtlCaptureStackBackTrace(ULONG FramesToSkip, ULONG FramesToCapture, PVOID* BackTrace, PULONG BackTraceHash);
|
||||
#define CaptureStackBackTrace RtlCaptureStackBackTrace
|
||||
|
||||
#endif
|
||||
|
||||
/* This is a simple tracking allocator to demonstrate the use of SDL's
|
||||
memory allocation replacement functionality.
|
||||
|
||||
It gets slow with large numbers of allocations and shouldn't be used
|
||||
for production code.
|
||||
*/
|
||||
|
||||
#define MAXIMUM_TRACKED_STACK_DEPTH 32
|
||||
|
||||
typedef struct SDL_tracked_allocation
|
||||
{
|
||||
void *mem;
|
||||
size_t size;
|
||||
Uint64 stack[MAXIMUM_TRACKED_STACK_DEPTH];
|
||||
struct SDL_tracked_allocation *next;
|
||||
#ifdef SDLTEST_UNWIND_NO_PROC_NAME_BY_IP
|
||||
char stack_names[MAXIMUM_TRACKED_STACK_DEPTH][256];
|
||||
#endif
|
||||
} SDL_tracked_allocation;
|
||||
|
||||
static SDLTest_Crc32Context s_crc32_context;
|
||||
static SDL_malloc_func SDL_malloc_orig = NULL;
|
||||
static SDL_calloc_func SDL_calloc_orig = NULL;
|
||||
static SDL_realloc_func SDL_realloc_orig = NULL;
|
||||
static SDL_free_func SDL_free_orig = NULL;
|
||||
static int s_previous_allocations = 0;
|
||||
static int s_unknown_frees = 0;
|
||||
static SDL_tracked_allocation *s_tracked_allocations[256];
|
||||
static bool s_randfill_allocations = false;
|
||||
static SDL_AtomicInt s_lock;
|
||||
|
||||
#define LOCK_ALLOCATOR() \
|
||||
do { \
|
||||
if (SDL_CompareAndSwapAtomicInt(&s_lock, 0, 1)) { \
|
||||
break; \
|
||||
} \
|
||||
SDL_CPUPauseInstruction(); \
|
||||
} while (true)
|
||||
#define UNLOCK_ALLOCATOR() do { SDL_SetAtomicInt(&s_lock, 0); } while (0)
|
||||
|
||||
static unsigned int get_allocation_bucket(void *mem)
|
||||
{
|
||||
CrcUint32 crc_value;
|
||||
unsigned int index;
|
||||
SDLTest_Crc32Calc(&s_crc32_context, (CrcUint8 *)&mem, sizeof(mem), &crc_value);
|
||||
index = (crc_value & (SDL_arraysize(s_tracked_allocations) - 1));
|
||||
return index;
|
||||
}
|
||||
|
||||
static SDL_tracked_allocation* SDL_GetTrackedAllocation(void *mem)
|
||||
{
|
||||
SDL_tracked_allocation *entry;
|
||||
LOCK_ALLOCATOR();
|
||||
int index = get_allocation_bucket(mem);
|
||||
for (entry = s_tracked_allocations[index]; entry; entry = entry->next) {
|
||||
if (mem == entry->mem) {
|
||||
UNLOCK_ALLOCATOR();
|
||||
return entry;
|
||||
}
|
||||
}
|
||||
UNLOCK_ALLOCATOR();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static size_t SDL_GetTrackedAllocationSize(void *mem)
|
||||
{
|
||||
SDL_tracked_allocation *entry = SDL_GetTrackedAllocation(mem);
|
||||
|
||||
return entry ? entry->size : SIZE_MAX;
|
||||
}
|
||||
|
||||
static bool SDL_IsAllocationTracked(void *mem)
|
||||
{
|
||||
return SDL_GetTrackedAllocation(mem) != NULL;
|
||||
}
|
||||
|
||||
static void SDL_TrackAllocation(void *mem, size_t size)
|
||||
{
|
||||
SDL_tracked_allocation *entry;
|
||||
int index = get_allocation_bucket(mem);
|
||||
|
||||
if (SDL_IsAllocationTracked(mem)) {
|
||||
return;
|
||||
}
|
||||
entry = (SDL_tracked_allocation *)SDL_malloc_orig(sizeof(*entry));
|
||||
if (!entry) {
|
||||
return;
|
||||
}
|
||||
LOCK_ALLOCATOR();
|
||||
entry->mem = mem;
|
||||
entry->size = size;
|
||||
|
||||
/* Generate the stack trace for the allocation */
|
||||
SDL_zeroa(entry->stack);
|
||||
#ifdef HAVE_LIBUNWIND_H
|
||||
{
|
||||
int stack_index;
|
||||
unw_cursor_t cursor;
|
||||
unw_context_t context;
|
||||
|
||||
unw_getcontext(&context);
|
||||
unw_init_local(&cursor, &context);
|
||||
|
||||
stack_index = 0;
|
||||
while (unw_step(&cursor) > 0) {
|
||||
unw_word_t pc;
|
||||
#ifdef SDLTEST_UNWIND_NO_PROC_NAME_BY_IP
|
||||
unw_word_t offset;
|
||||
char sym[236];
|
||||
#endif
|
||||
|
||||
unw_get_reg(&cursor, UNW_REG_IP, &pc);
|
||||
entry->stack[stack_index] = pc;
|
||||
|
||||
#ifdef SDLTEST_UNWIND_NO_PROC_NAME_BY_IP
|
||||
if (s_unwind_symbol_names && unw_get_proc_name(&cursor, sym, sizeof(sym), &offset) == 0) {
|
||||
SDL_snprintf(entry->stack_names[stack_index], sizeof(entry->stack_names[stack_index]), "%s+0x%llx", sym, (unsigned long long)offset);
|
||||
}
|
||||
#endif
|
||||
++stack_index;
|
||||
|
||||
if (stack_index == SDL_arraysize(entry->stack)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
#elif defined(SDL_PLATFORM_WIN32)
|
||||
{
|
||||
Uint32 count;
|
||||
PVOID frames[63];
|
||||
Uint32 i;
|
||||
|
||||
count = CaptureStackBackTrace(1, SDL_arraysize(frames), frames, NULL);
|
||||
|
||||
count = SDL_min(count, MAXIMUM_TRACKED_STACK_DEPTH);
|
||||
for (i = 0; i < count; i++) {
|
||||
entry->stack[i] = (Uint64)(uintptr_t)frames[i];
|
||||
}
|
||||
}
|
||||
#endif /* HAVE_LIBUNWIND_H */
|
||||
|
||||
entry->next = s_tracked_allocations[index];
|
||||
s_tracked_allocations[index] = entry;
|
||||
UNLOCK_ALLOCATOR();
|
||||
}
|
||||
|
||||
static void SDL_UntrackAllocation(void *mem)
|
||||
{
|
||||
SDL_tracked_allocation *entry, *prev;
|
||||
int index = get_allocation_bucket(mem);
|
||||
|
||||
LOCK_ALLOCATOR();
|
||||
prev = NULL;
|
||||
for (entry = s_tracked_allocations[index]; entry; entry = entry->next) {
|
||||
if (mem == entry->mem) {
|
||||
if (prev) {
|
||||
prev->next = entry->next;
|
||||
} else {
|
||||
s_tracked_allocations[index] = entry->next;
|
||||
}
|
||||
SDL_free_orig(entry);
|
||||
UNLOCK_ALLOCATOR();
|
||||
return;
|
||||
}
|
||||
prev = entry;
|
||||
}
|
||||
s_unknown_frees += 1;
|
||||
UNLOCK_ALLOCATOR();
|
||||
}
|
||||
|
||||
static void rand_fill_memory(void* ptr, size_t start, size_t end)
|
||||
{
|
||||
Uint8* mem = (Uint8*) ptr;
|
||||
size_t i;
|
||||
|
||||
if (!s_randfill_allocations)
|
||||
return;
|
||||
|
||||
for (i = start; i < end; ++i) {
|
||||
mem[i] = SDLTest_RandomUint8();
|
||||
}
|
||||
}
|
||||
|
||||
static void * SDLCALL SDLTest_TrackedMalloc(size_t size)
|
||||
{
|
||||
void *mem;
|
||||
|
||||
mem = SDL_malloc_orig(size);
|
||||
if (mem) {
|
||||
SDL_TrackAllocation(mem, size);
|
||||
rand_fill_memory(mem, 0, size);
|
||||
}
|
||||
return mem;
|
||||
}
|
||||
|
||||
static void * SDLCALL SDLTest_TrackedCalloc(size_t nmemb, size_t size)
|
||||
{
|
||||
void *mem;
|
||||
|
||||
mem = SDL_calloc_orig(nmemb, size);
|
||||
if (mem) {
|
||||
SDL_TrackAllocation(mem, nmemb * size);
|
||||
}
|
||||
return mem;
|
||||
}
|
||||
|
||||
static void * SDLCALL SDLTest_TrackedRealloc(void *ptr, size_t size)
|
||||
{
|
||||
void *mem;
|
||||
size_t old_size = 0;
|
||||
if (ptr) {
|
||||
old_size = SDL_GetTrackedAllocationSize(ptr);
|
||||
SDL_assert(old_size != SIZE_MAX);
|
||||
}
|
||||
mem = SDL_realloc_orig(ptr, size);
|
||||
if (ptr) {
|
||||
SDL_UntrackAllocation(ptr);
|
||||
}
|
||||
if (mem) {
|
||||
SDL_TrackAllocation(mem, size);
|
||||
if (size > old_size) {
|
||||
rand_fill_memory(mem, old_size, size);
|
||||
}
|
||||
}
|
||||
return mem;
|
||||
}
|
||||
|
||||
static void SDLCALL SDLTest_TrackedFree(void *ptr)
|
||||
{
|
||||
if (!ptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (s_previous_allocations == 0) {
|
||||
SDL_assert(SDL_IsAllocationTracked(ptr));
|
||||
}
|
||||
SDL_UntrackAllocation(ptr);
|
||||
SDL_free_orig(ptr);
|
||||
}
|
||||
|
||||
void SDLTest_TrackAllocations(void)
|
||||
{
|
||||
if (SDL_malloc_orig) {
|
||||
return;
|
||||
}
|
||||
|
||||
SDLTest_Crc32Init(&s_crc32_context);
|
||||
|
||||
s_previous_allocations = SDL_GetNumAllocations();
|
||||
if (s_previous_allocations < 0) {
|
||||
SDL_Log("SDL was built without allocation count support, disabling free() validation");
|
||||
} else if (s_previous_allocations != 0) {
|
||||
SDL_Log("SDLTest_TrackAllocations(): There are %d previous allocations, disabling free() validation", s_previous_allocations);
|
||||
}
|
||||
#ifdef SDLTEST_UNWIND_NO_PROC_NAME_BY_IP
|
||||
do {
|
||||
/* Don't use SDL_GetHint: SDL_malloc is off limits. */
|
||||
const char *env_trackmem = SDL_getenv_unsafe("SDL_TRACKMEM_SYMBOL_NAMES");
|
||||
if (env_trackmem) {
|
||||
if (SDL_strcasecmp(env_trackmem, "1") == 0 || SDL_strcasecmp(env_trackmem, "yes") == 0 || SDL_strcasecmp(env_trackmem, "true") == 0) {
|
||||
s_unwind_symbol_names = true;
|
||||
} else if (SDL_strcasecmp(env_trackmem, "0") == 0 || SDL_strcasecmp(env_trackmem, "no") == 0 || SDL_strcasecmp(env_trackmem, "false") == 0) {
|
||||
s_unwind_symbol_names = false;
|
||||
}
|
||||
}
|
||||
} while (0);
|
||||
|
||||
#elif defined(SDL_PLATFORM_WIN32)
|
||||
do {
|
||||
dyn_dbghelp.module = SDL_LoadObject("dbghelp.dll");
|
||||
if (!dyn_dbghelp.module) {
|
||||
goto dbghelp_failed;
|
||||
}
|
||||
dyn_dbghelp.pSymInitialize = (void *)SDL_LoadFunction(dyn_dbghelp.module, "SymInitialize");
|
||||
dyn_dbghelp.pSymFromAddr = (void *)SDL_LoadFunction(dyn_dbghelp.module, "SymFromAddr");
|
||||
dyn_dbghelp.pSymGetLineFromAddr64 = (void *)SDL_LoadFunction(dyn_dbghelp.module, "SymGetLineFromAddr64");
|
||||
if (!dyn_dbghelp.pSymInitialize || !dyn_dbghelp.pSymFromAddr || !dyn_dbghelp.pSymGetLineFromAddr64) {
|
||||
goto dbghelp_failed;
|
||||
}
|
||||
if (!dyn_dbghelp.pSymInitialize(GetCurrentProcess(), NULL, TRUE)) {
|
||||
goto dbghelp_failed;
|
||||
}
|
||||
break;
|
||||
dbghelp_failed:
|
||||
if (dyn_dbghelp.module) {
|
||||
SDL_UnloadObject(dyn_dbghelp.module);
|
||||
dyn_dbghelp.module = NULL;
|
||||
}
|
||||
} while (0);
|
||||
#endif
|
||||
|
||||
SDL_GetMemoryFunctions(&SDL_malloc_orig,
|
||||
&SDL_calloc_orig,
|
||||
&SDL_realloc_orig,
|
||||
&SDL_free_orig);
|
||||
|
||||
SDL_SetMemoryFunctions(SDLTest_TrackedMalloc,
|
||||
SDLTest_TrackedCalloc,
|
||||
SDLTest_TrackedRealloc,
|
||||
SDLTest_TrackedFree);
|
||||
}
|
||||
|
||||
void SDLTest_RandFillAllocations(void)
|
||||
{
|
||||
SDLTest_TrackAllocations();
|
||||
|
||||
s_randfill_allocations = true;
|
||||
}
|
||||
|
||||
void SDLTest_LogAllocations(void)
|
||||
{
|
||||
char *message = NULL;
|
||||
size_t message_size = 0;
|
||||
char line[256], *tmp;
|
||||
SDL_tracked_allocation *entry;
|
||||
int index, count, stack_index;
|
||||
Uint64 total_allocated;
|
||||
|
||||
if (!SDL_malloc_orig) {
|
||||
return;
|
||||
}
|
||||
|
||||
message = SDL_realloc_orig(NULL, 1);
|
||||
if (!message) {
|
||||
return;
|
||||
}
|
||||
*message = 0;
|
||||
|
||||
#define ADD_LINE() \
|
||||
message_size += (SDL_strlen(line) + 1); \
|
||||
tmp = (char *)SDL_realloc_orig(message, message_size); \
|
||||
if (!tmp) { \
|
||||
return; \
|
||||
} \
|
||||
message = tmp; \
|
||||
SDL_strlcat(message, line, message_size)
|
||||
|
||||
SDL_strlcpy(line, "Memory allocations:\n", sizeof(line));
|
||||
ADD_LINE();
|
||||
|
||||
count = 0;
|
||||
total_allocated = 0;
|
||||
for (index = 0; index < SDL_arraysize(s_tracked_allocations); ++index) {
|
||||
for (entry = s_tracked_allocations[index]; entry; entry = entry->next) {
|
||||
(void)SDL_snprintf(line, sizeof(line), "Allocation %d: %d bytes\n", count, (int)entry->size);
|
||||
ADD_LINE();
|
||||
/* Start at stack index 1 to skip our tracking functions */
|
||||
for (stack_index = 1; stack_index < SDL_arraysize(entry->stack); ++stack_index) {
|
||||
char stack_entry_description[256] = "???";
|
||||
|
||||
if (!entry->stack[stack_index]) {
|
||||
break;
|
||||
}
|
||||
#ifdef HAVE_LIBUNWIND_H
|
||||
{
|
||||
#ifdef SDLTEST_UNWIND_NO_PROC_NAME_BY_IP
|
||||
if (s_unwind_symbol_names) {
|
||||
(void)SDL_snprintf(stack_entry_description, sizeof(stack_entry_description), "%s", entry->stack_names[stack_index]);
|
||||
}
|
||||
#else
|
||||
char name[256] = "???";
|
||||
unw_word_t offset = 0;
|
||||
unw_get_proc_name_by_ip(unw_local_addr_space, entry->stack[stack_index], name, sizeof(name), &offset, NULL);
|
||||
(void)SDL_snprintf(stack_entry_description, sizeof(stack_entry_description), "%s+0x%llx", name, (long long unsigned int)offset);
|
||||
#endif
|
||||
}
|
||||
#elif defined(SDL_PLATFORM_WIN32)
|
||||
{
|
||||
DWORD64 dwDisplacement = 0;
|
||||
char symbol_buffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME * sizeof(TCHAR)];
|
||||
PSYMBOL_INFO pSymbol = (PSYMBOL_INFO)symbol_buffer;
|
||||
DWORD lineColumn = 0;
|
||||
pSymbol->SizeOfStruct = sizeof(SYMBOL_INFO);
|
||||
pSymbol->MaxNameLen = MAX_SYM_NAME;
|
||||
IMAGEHLP_LINE64 dbg_line;
|
||||
dbg_line.SizeOfStruct = sizeof(dbg_line);
|
||||
dbg_line.FileName = "";
|
||||
dbg_line.LineNumber = 0;
|
||||
|
||||
if (dyn_dbghelp.module) {
|
||||
if (!dyn_dbghelp.pSymFromAddr(GetCurrentProcess(), entry->stack[stack_index], &dwDisplacement, pSymbol)) {
|
||||
SDL_strlcpy(pSymbol->Name, "???", MAX_SYM_NAME);
|
||||
dwDisplacement = 0;
|
||||
}
|
||||
dyn_dbghelp.pSymGetLineFromAddr64(GetCurrentProcess(), (DWORD64)entry->stack[stack_index], &lineColumn, &dbg_line);
|
||||
}
|
||||
SDL_snprintf(stack_entry_description, sizeof(stack_entry_description), "%s+0x%I64x %s:%u", pSymbol->Name, dwDisplacement, dbg_line.FileName, (Uint32)dbg_line.LineNumber);
|
||||
}
|
||||
#endif
|
||||
(void)SDL_snprintf(line, sizeof(line), "\t0x%" SDL_PRIx64 ": %s\n", entry->stack[stack_index], stack_entry_description);
|
||||
|
||||
ADD_LINE();
|
||||
}
|
||||
total_allocated += entry->size;
|
||||
++count;
|
||||
}
|
||||
}
|
||||
(void)SDL_snprintf(line, sizeof(line), "Total: %.2f Kb in %d allocations", total_allocated / 1024.0, count);
|
||||
ADD_LINE();
|
||||
if (s_unknown_frees != 0) {
|
||||
(void)SDL_snprintf(line, sizeof(line), ", %d unknown frees", s_unknown_frees);
|
||||
ADD_LINE();
|
||||
}
|
||||
(void)SDL_snprintf(line, sizeof(line), "\n");
|
||||
ADD_LINE();
|
||||
#undef ADD_LINE
|
||||
|
||||
SDL_Log("%s", message);
|
||||
SDL_free_orig(message);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue