sdl2-compat: test: Added SDLtest lib, fixed up all tests to build.

From abfe82c7a40538f637d76d07377855468d74578c Mon Sep 17 00:00:00 2001
From: "Ryan C. Gordon" <[EMAIL REDACTED]>
Date: Sat, 26 Nov 2022 11:24:47 -0500
Subject: [PATCH] test: Added SDLtest lib, fixed up all tests to build.

Fixes #4.
---
 CMakeLists.txt                           |    88 +-
 src/test/SDL_test_assert.c               |   152 +
 src/test/SDL_test_common.c               |  2405 +
 src/test/SDL_test_compare.c              |   117 +
 src/test/SDL_test_crc32.c                |   166 +
 src/test/SDL_test_font.c                 |  3497 +
 src/test/SDL_test_fuzzer.c               |   534 +
 src/test/SDL_test_harness.c              |   698 +
 src/test/SDL_test_imageBlit.c            |  1559 +
 src/test/SDL_test_imageBlitBlend.c       |  2845 +
 src/test/SDL_test_imageFace.c            |   247 +
 src/test/SDL_test_imagePrimitives.c      |   514 +
 src/test/SDL_test_imagePrimitivesBlend.c |   696 +
 src/test/SDL_test_log.c                  |   118 +
 src/test/SDL_test_md5.c                  |   338 +
 src/test/SDL_test_memory.c               |   275 +
 src/test/SDL_test_random.c               |    97 +
 test/gles2funcs.h                        |    80 +
 test/glfuncs.h                           |   478 +
 test/testautomation_joystick.c           |     6 +
 test/testevdev.c                         |     2 +
 test/testgl2.c                           |     8 +
 test/testgles2.c                         |     8 +
 test/testgles2_sdf.c                     |     8 +
 test/testvulkan.c                        |     5 +
 test/vulkan/vk_icd.h                     |   245 +
 test/vulkan/vk_layer.h                   |   210 +
 test/vulkan/vk_platform.h                |    84 +
 test/vulkan/vk_sdk_platform.h            |    69 +
 test/vulkan/vulkan.h                     |    92 +
 test/vulkan/vulkan.hpp                   | 14537 +++
 test/vulkan/vulkan_android.h             |   125 +
 test/vulkan/vulkan_beta.h                |  1020 +
 test/vulkan/vulkan_core.h                | 15119 ++++
 test/vulkan/vulkan_directfb.h            |    54 +
 test/vulkan/vulkan_enums.hpp             |  8538 ++
 test/vulkan/vulkan_format_traits.hpp     |  7333 ++
 test/vulkan/vulkan_fuchsia.h             |   258 +
 test/vulkan/vulkan_funcs.hpp             | 20008 +++++
 test/vulkan/vulkan_ggp.h                 |    58 +
 test/vulkan/vulkan_handles.hpp           | 13585 +++
 test/vulkan/vulkan_hash.hpp              | 13489 +++
 test/vulkan/vulkan_ios.h                 |    47 +
 test/vulkan/vulkan_macos.h               |    47 +
 test/vulkan/vulkan_metal.h               |   201 +
 test/vulkan/vulkan_raii.hpp              | 17460 ++++
 test/vulkan/vulkan_screen.h              |    54 +
 test/vulkan/vulkan_static_assertions.hpp |  5847 ++
 test/vulkan/vulkan_structs.hpp           | 99721 +++++++++++++++++++++
 test/vulkan/vulkan_to_string.hpp         |  7732 ++
 test/vulkan/vulkan_vi.h                  |    47 +
 test/vulkan/vulkan_wayland.h             |    54 +
 test/vulkan/vulkan_win32.h               |   315 +
 test/vulkan/vulkan_xcb.h                 |    55 +
 test/vulkan/vulkan_xlib.h                |    55 +
 test/vulkan/vulkan_xlib_xrandr.h         |    45 +
 56 files changed, 241423 insertions(+), 22 deletions(-)
 create mode 100644 src/test/SDL_test_assert.c
 create mode 100644 src/test/SDL_test_common.c
 create mode 100644 src/test/SDL_test_compare.c
 create mode 100644 src/test/SDL_test_crc32.c
 create mode 100644 src/test/SDL_test_font.c
 create mode 100644 src/test/SDL_test_fuzzer.c
 create mode 100644 src/test/SDL_test_harness.c
 create mode 100644 src/test/SDL_test_imageBlit.c
 create mode 100644 src/test/SDL_test_imageBlitBlend.c
 create mode 100644 src/test/SDL_test_imageFace.c
 create mode 100644 src/test/SDL_test_imagePrimitives.c
 create mode 100644 src/test/SDL_test_imagePrimitivesBlend.c
 create mode 100644 src/test/SDL_test_log.c
 create mode 100644 src/test/SDL_test_md5.c
 create mode 100644 src/test/SDL_test_memory.c
 create mode 100644 src/test/SDL_test_random.c
 create mode 100644 test/gles2funcs.h
 create mode 100644 test/glfuncs.h
 create mode 100644 test/vulkan/vk_icd.h
 create mode 100644 test/vulkan/vk_layer.h
 create mode 100644 test/vulkan/vk_platform.h
 create mode 100644 test/vulkan/vk_sdk_platform.h
 create mode 100644 test/vulkan/vulkan.h
 create mode 100644 test/vulkan/vulkan.hpp
 create mode 100644 test/vulkan/vulkan_android.h
 create mode 100644 test/vulkan/vulkan_beta.h
 create mode 100644 test/vulkan/vulkan_core.h
 create mode 100644 test/vulkan/vulkan_directfb.h
 create mode 100644 test/vulkan/vulkan_enums.hpp
 create mode 100644 test/vulkan/vulkan_format_traits.hpp
 create mode 100644 test/vulkan/vulkan_fuchsia.h
 create mode 100644 test/vulkan/vulkan_funcs.hpp
 create mode 100644 test/vulkan/vulkan_ggp.h
 create mode 100644 test/vulkan/vulkan_handles.hpp
 create mode 100644 test/vulkan/vulkan_hash.hpp
 create mode 100644 test/vulkan/vulkan_ios.h
 create mode 100644 test/vulkan/vulkan_macos.h
 create mode 100644 test/vulkan/vulkan_metal.h
 create mode 100644 test/vulkan/vulkan_raii.hpp
 create mode 100644 test/vulkan/vulkan_screen.h
 create mode 100644 test/vulkan/vulkan_static_assertions.hpp
 create mode 100644 test/vulkan/vulkan_structs.hpp
 create mode 100644 test/vulkan/vulkan_to_string.hpp
 create mode 100644 test/vulkan/vulkan_vi.h
 create mode 100644 test/vulkan/vulkan_wayland.h
 create mode 100644 test/vulkan/vulkan_win32.h
 create mode 100644 test/vulkan/vulkan_xcb.h
 create mode 100644 test/vulkan/vulkan_xlib.h
 create mode 100644 test/vulkan/vulkan_xlib_xrandr.h

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 43ec4fc..3e8f9de 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -161,6 +161,27 @@ endif()
 #endif()
 target_include_directories(SDLmain PRIVATE "include/SDL2")
 
+# SDLtest library...
+add_library(SDLtest STATIC
+    src/test/SDL_test_assert.c
+    src/test/SDL_test_common.c
+    src/test/SDL_test_compare.c
+    src/test/SDL_test_crc32.c
+    src/test/SDL_test_font.c
+    src/test/SDL_test_fuzzer.c
+    src/test/SDL_test_harness.c
+    src/test/SDL_test_imageBlit.c
+    src/test/SDL_test_imageBlitBlend.c
+    src/test/SDL_test_imageFace.c
+    src/test/SDL_test_imagePrimitives.c
+    src/test/SDL_test_imagePrimitivesBlend.c
+    src/test/SDL_test_log.c
+    src/test/SDL_test_md5.c
+    src/test/SDL_test_memory.c
+    src/test/SDL_test_random.c 
+)
+target_include_directories(SDLtest PRIVATE "include/SDL2")
+
 if(SDL2TESTS)
     if(NOT (WIN32 OR APPLE OR CYGWIN OR HAIKU OR BEOS))
       find_library(MATH_LIBRARY m)
@@ -182,9 +203,9 @@ if(SDL2TESTS)
         add_executable(${_NAME} ${_SRCS})
         target_include_directories(${_NAME} PRIVATE "include/SDL2")
         if(MINGW)
-          target_link_libraries(${_NAME} mingw32 SDLmain SDL)
+          target_link_libraries(${_NAME} mingw32 SDLmain SDLtest SDL)
         else()
-          target_link_libraries(${_NAME} SDLmain SDL)
+          target_link_libraries(${_NAME} SDLmain SDLtest SDL)
         endif()
         # Turn off MSVC's aggressive C runtime warnings for the old test programs.
         if(MSVC)
@@ -203,13 +224,12 @@ if(SDL2TESTS)
     test_program(checkkeys "test/checkkeys.c")
     test_program(checkkeysthreads "test/checkkeysthreads.c")
     test_program(controllermap "test/controllermap.c")
-    test_program(loopwave "test/loopwave.c")
-    test_program(loopwavequeue "test/loopwavequeue.c")
+    test_program(loopwave "test/loopwave.c;test/testutils.c")
+    test_program(loopwavequeue "test/loopwavequeue.c;test/testutils.c")
     test_program(testatomic "test/testatomic.c")
     test_program(testaudiocapture "test/testaudiocapture.c")
-    test_program(testaudiohotplug "test/testaudiohotplug.c")
+    test_program(testaudiohotplug "test/testaudiohotplug.c;test/testutils.c")
     test_program(testaudioinfo "test/testaudioinfo.c")
-    test_program(testautomation "test/testautomation.c")
     test_program(testbounds "test/testbounds.c")
     test_program(testcustomcursor "test/testcustomcursor.c")
     test_program(testdisplayinfo "test/testdisplayinfo.c")
@@ -221,13 +241,13 @@ if(SDL2TESTS)
     test_program(testfile "test/testfile.c")
     test_program(testfilesystem "test/testfilesystem.c")
     test_program(testgamecontroller "test/testgamecontroller.c")
-    test_program(testgeometry "test/testgeometry.c")
+    test_program(testgeometry "test/testgeometry.c;test/testutils.c")
     test_program(testgesture "test/testgesture.c")
     test_program(testhaptic "test/testhaptic.c")
     test_program(testhittesting "test/testhittesting.c")
     test_program(testhotplug "test/testhotplug.c")
-    test_program(testiconv "test/testiconv.c")
-    test_program(testime "test/testime.c")
+    test_program(testiconv "test/testiconv.c;test/testutils.c")
+    test_program(testime "test/testime.c;test/testutils.c")
     test_program(testintersections "test/testintersections.c")
     test_program(testjoystick "test/testjoystick.c")
     test_program(testkeys "test/testkeys.c")
@@ -236,38 +256,62 @@ if(SDL2TESTS)
     test_program(testlock "test/testlock.c")
     test_program(testmessage "test/testmessage.c")
     test_program(testmouse "test/testmouse.c")
-    test_program(testmultiaudio "test/testmultiaudio.c")
-    test_program(testnative "test/testnative.c")
-    test_program(testoverlay2 "test/testoverlay2.c")
+    test_program(testmultiaudio "test/testmultiaudio.c;test/testutils.c")
+    test_program(testnative "test/testnative.c;test/testutils.c")
+    test_program(testoverlay2 "test/testoverlay2.c;test/testutils.c;test/testyuv_cvt.c")
     test_program(testplatform "test/testplatform.c")
     test_program(testpower "test/testpower.c")
     test_program(testqsort "test/testqsort.c")
     test_program(testrelative "test/testrelative.c")
-    test_program(testrendercopyex "test/testrendercopyex.c")
-    test_program(testrendertarget "test/testrendertarget.c")
+    test_program(testrendercopyex "test/testrendercopyex.c;test/testutils.c")
+    test_program(testrendertarget "test/testrendertarget.c;test/testutils.c")
     test_program(testresample "test/testresample.c")
     test_program(testrumble "test/testrumble.c")
-    test_program(testscale "test/testscale.c")
+    test_program(testscale "test/testscale.c;test/testutils.c")
     test_program(testsem "test/testsem.c")
     test_program(testsensor "test/testsensor.c")
     test_program(testshape "test/testshape.c")
-    test_program(testsprite2 "test/testsprite2.c")
-    test_program(testspriteminimal "test/testspriteminimal.c")
-    test_program(teststreaming "test/teststreaming.c")
+    test_program(testsprite2 "test/testsprite2.c;test/testutils.c")
+    test_program(testspriteminimal "test/testspriteminimal.c;test/testutils.c")
+    test_program(teststreaming "test/teststreaming.c;test/testutils.c")
     test_program(testsurround "test/testsurround.c")
     test_program(testthread "test/testthread.c")
     test_program(testtimer "test/testtimer.c")
     test_program(testurl "test/testurl.c")
     test_program(testver "test/testver.c")
-    test_program(testviewport "test/testviewport.c")
+    test_program(testviewport "test/testviewport.c;test/testutils.c")
     test_program(testvulkan "test/testvulkan.c")
     test_program(testwm2 "test/testwm2.c")
-    test_program(testyuv "test/testyuv.c")
+    test_program(testyuv "test/testyuv.c;test/testyuv_cvt.c")
     test_program(torturethread "test/torturethread.c")
     test_program(testgl2 "test/testgl2.c")
     test_program(testgles "test/testgles.c")
     test_program(testgles2 "test/testgles2.c")
-    test_program(testgles2_sdf "test/testgles2_sdf.c")
+    test_program(testgles2_sdf "test/testgles2_sdf.c;test/testutils.c")
+
+    list(APPEND TESTAUTOMATION_SRCS "test/testautomation.c")
+    list(APPEND TESTAUTOMATION_SRCS "test/testautomation_audio.c")
+    list(APPEND TESTAUTOMATION_SRCS "test/testautomation_guid.c")
+    list(APPEND TESTAUTOMATION_SRCS "test/testautomation_main.c")
+    list(APPEND TESTAUTOMATION_SRCS "test/testautomation_platform.c")
+    list(APPEND TESTAUTOMATION_SRCS "test/testautomation_sdltest.c")
+    list(APPEND TESTAUTOMATION_SRCS "test/testautomation_syswm.c")
+    list(APPEND TESTAUTOMATION_SRCS "test/testautomation_hints.c")
+    list(APPEND TESTAUTOMATION_SRCS "test/testautomation_math.c")
+    list(APPEND TESTAUTOMATION_SRCS "test/testautomation_rect.c")
+    list(APPEND TESTAUTOMATION_SRCS "test/testautomation_stdlib.c")
+    list(APPEND TESTAUTOMATION_SRCS "test/testautomation_timer.c")
+    list(APPEND TESTAUTOMATION_SRCS "test/testautomation_clipboard.c")
+    list(APPEND TESTAUTOMATION_SRCS "test/testautomation_joystick.c")
+    list(APPEND TESTAUTOMATION_SRCS "test/testautomation_mouse.c")
+    list(APPEND TESTAUTOMATION_SRCS "test/testautomation_render.c")
+    list(APPEND TESTAUTOMATION_SRCS "test/testautomation_video.c")
+    list(APPEND TESTAUTOMATION_SRCS "test/testautomation_events.c")
+    list(APPEND TESTAUTOMATION_SRCS "test/testautomation_keyboard.c")
+    list(APPEND TESTAUTOMATION_SRCS "test/testautomation_pixels.c")
+    list(APPEND TESTAUTOMATION_SRCS "test/testautomation_rwops.c")
+    list(APPEND TESTAUTOMATION_SRCS "test/testautomation_surface.c")
+    test_program(testautomation "${TESTAUTOMATION_SRCS}")
 
     if(OPENGL_FOUND)
       if(CMAKE_VERSION VERSION_LESS 3.10 OR NOT OPENGL_opengl_LIBRARY)
@@ -295,7 +339,7 @@ if(SDL2TESTS)
     endforeach()
 endif()
 
-install(TARGETS SDL SDLmain
+install(TARGETS SDL SDLmain SDLtest
   LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
   ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
   RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
diff --git a/src/test/SDL_test_assert.c b/src/test/SDL_test_assert.c
new file mode 100644
index 0000000..148564e
--- /dev/null
+++ b/src/test/SDL_test_assert.c
@@ -0,0 +1,152 @@
+/*
+  Simple DirectMedia Layer
+  Copyright (C) 1997-2022 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 "SDL_config.h"
+
+#include "SDL_test.h"
+
+/* 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 Passed=%d Failed=%d"
+
+/* ! \brief counts the failed asserts */
+static int SDLTest_AssertsFailed = 0;
+
+/* ! \brief 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);
+    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);
+    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, "Failed");
+    }
+    else
+    {
+        SDLTest_AssertsPassed++;
+        SDLTest_Log(SDLTEST_ASSERT_CHECK_FORMAT, logMessage, "Passed");
+    }
+
+    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);
+    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, "Passed");
+}
+
+/*
+ * Resets the assert summary counters to zero.
+ */
+void SDLTest_ResetAssertSummary()
+{
+    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()
+{
+    int totalAsserts = SDLTest_AssertsPassed + SDLTest_AssertsFailed;
+    if (SDLTest_AssertsFailed == 0)
+    {
+        SDLTest_Log(SDLTEST_ASSERT_SUMMARY_FORMAT, 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()
+{
+    if (SDLTest_AssertsFailed > 0) {
+        return TEST_RESULT_FAILED;
+    } else {
+        if (SDLTest_AssertsPassed > 0) {
+            return TEST_RESULT_PASSED;
+        } else {
+            return TEST_RESULT_NO_ASSERT;
+        }
+    }
+}
+
+/* vi: set ts=4 sw=4 expandtab: */
diff --git a/src/test/SDL_test_common.c b/src/test/SDL_test_common.c
new file mode 100644
index 0000000..1dc9793
--- /dev/null
+++ b/src/test/SDL_test_common.c
@@ -0,0 +1,2405 @@
+/*
+  Simple DirectMedia Layer
+  Copyright (C) 1997-2022 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.
+*/
+
+/* Ported from original test/common.c file. */
+
+#include "SDL_config.h"
+#include "SDL_test.h"
+
+#include <stdio.h>
+
+static const char *video_usage[] = {
+    "[--video driver]", "[--renderer driver]", "[--gldebug]",
+    "[--info all|video|modes|render|event|event_motion]",
+    "[--log all|error|system|audio|video|render|input]", "[--display N]",
+    "[--metal-window | --opengl-window | --vulkan-window]",
+    "[--fullscreen | --fullscreen-desktop | --windows N]", "[--title title]",
+    "[--icon icon.bmp]", "[--center | --position X,Y]", "[--geometry WxH]",
+    "[--min-geometry WxH]", "[--max-geometry WxH]", "[--logical WxH]",
+    "[--scale N]", "[--depth N]", "[--refresh R]", "[--vsync]", "[--noframe]",
+    "[--resizable]", "[--minimize]", "[--maximize]", "[--grab]", "[--keyboard-grab]",
+    "[--shown]", "[--hidden]", "[--input-focus]", "[--mouse-focus]",
+    "[--flash-on-focus-loss]", "[--allow-highdpi]", "[--confine-cursor X,Y,W,H]",
+    "[--usable-bounds]"
+};
+
+static const char *audio_usage[] = {
+    "[--rate N]", "[--format U8|S8|U16|U16LE|U16BE|S16|S16LE|S16BE]",
+    "[--channels N]", "[--samples N]"
+};
+
+static void SDL_snprintfcat(SDL_OUT_Z_CAP(maxlen) char *text, size_t maxlen, SDL_PRINTF_FORMAT_STRING const char *fmt, ... )
+{
+    size_t length = SDL_strlen(text);
+    va_list ap;
+
+    va_start(ap, fmt);
+    text += length;
+    maxlen -= length;
+    SDL_vsnprintf(text, maxlen, fmt, ap);
+    va_end(ap);
+}
+
+SDLTest_CommonState *
+SDLTest_CommonCreateState(char **argv, Uint32 flags)
+{
+    int i;
+    SDLTest_CommonState *state;
+
+    /* Do this first so we catch all allocations */
+    for (i = 1; argv[i]; ++i) {
+        if (SDL_strcasecmp(argv[i], "--trackmem") == 0) {
+            SDLTest_TrackAllocations();
+            break;
+        }
+    }
+
+    state = (SDLTest_CommonState *)SDL_calloc(1, sizeof(*state));
+    if (!state) {
+        SDL_OutOfMemory();
+        return NULL;
+    }
+
+    /* Initialize some defaults */
+    state->argv = argv;
+    state->flags = flags;
+    state->window_title = argv[0];
+    state->window_flags = 0;
+    state->window_x = SDL_WINDOWPOS_UNDEFINED;
+    state->window_y = SDL_WINDOWPOS_UNDEFINED;
+    state->window_w = DEFAULT_WINDOW_WIDTH;
+    state->window_h = DEFAULT_WINDOW_HEIGHT;
+    state->num_windows = 1;
+    state->audiospec.freq = 22050;
+    state->audiospec.format = AUDIO_S16;
+    state->audiospec.channels = 2;
+    state->audiospec.samples = 2048;
+
+    /* Set some very sane GL defaults */
+    state->gl_red_size = 3;
+    state->gl_green_size = 3;
+    state->gl_blue_size = 2;
+    state->gl_alpha_size = 0;
+    state->gl_buffer_size = 0;
+    state->gl_depth_size = 16;
+    state->gl_stencil_size = 0;
+    state->gl_double_buffer = 1;
+    state->gl_accum_red_size = 0;
+    state->gl_accum_green_size = 0;
+    state->gl_accum_blue_size = 0;
+    state->gl_accum_alpha_size = 0;
+    state->gl_stereo = 0;
+    state->gl_multisamplebuffers = 0;
+    state->gl_multisamplesamples = 0;
+    state->gl_retained_backing = 1;
+    state->gl_accelerated = -1;
+    state->gl_debug = 0;
+
+    return state;
+}
+
+int
+SDLTest_CommonArg(SDLTest_CommonState * state, int index)
+{
+    char **argv = state->argv;
+
+    if (SDL_strcasecmp(argv[index], "--video") == 0) {
+        ++index;
+        if (!argv[index]) {
+            return -1;
+        }
+        state->videodriver = argv[index];
+        return 2;
+    }
+    if (SDL_strcasecmp(argv[index], "--renderer") == 0) {
+        ++index;
+        if (!argv[index]) {
+            return -1;
+        }
+        state->renderdriver = argv[index];
+        return 2;
+    }
+    if (SDL_strcasecmp(argv[index], "--gldebug") == 0) {
+        state->gl_debug = 1;
+        return 1;
+    }
+    if (SDL_strcasecmp(argv[index], "--info") == 0) {
+        ++index;
+        if (!argv[index]) {
+            return -1;
+        }
+        if (SDL_strcasecmp(argv[index], "all") == 0) {
+            state->verbose |=
+                (VERBOSE_VIDEO | VERBOSE_MODES | VERBOSE_RENDER |
+                 VERBOSE_EVENT);
+            return 2;
+        }
+        if (SDL_strcasecmp(argv[index], "video") == 0) {
+            state->verbose |= VERBOSE_VIDEO;
+            return 2;
+        }
+        if (SDL_strcasecmp(argv[index], "modes") == 0) {
+            state->verbose |= VERBOSE_MODES;
+            return 2;
+        }
+        if (SDL_strcasecmp(argv[index], "render") == 0) {
+            state->verbose |= VERBOSE_RENDER;
+            return 2;
+        }
+        if (SDL_strcasecmp(argv[index], "event") == 0) {
+            state->verbose |= VERBOSE_EVENT;
+            return 2;
+        }
+        if (SDL_strcasecmp(argv[index], "event_motion") == 0) {
+            state->verbose |= (VERBOSE_EVENT | VERBOSE_MOTION);
+            return 2;
+        }
+        return -1;
+    }
+    if (SDL_strcasecmp(argv[index], "--log") == 0) {
+        ++index;
+        if (!argv[index]) {
+            return -1;
+        }
+        if (SDL_strcasecmp(argv[index], "all") == 0) {
+            SDL_LogSetAllPriority(SDL_LOG_PRIORITY_VERBOSE);
+            return 2;
+        }
+        if (SDL_strcasecmp(argv[index], "error") == 0) {
+            SDL_LogSetPriority(SDL_LOG_CATEGORY_ERROR, SDL_LOG_PRIORITY_VERBOSE);
+            return 2;
+        }
+        if (SDL_strcasecmp(argv[index], "system") == 0) {
+            SDL_LogSetPriority(SDL_LOG_CATEGORY_SYSTEM, SDL_LOG_PRIORITY_VERBOSE);
+            return 2;
+        }
+        if (SDL_strcasecmp(argv[index], "audio") == 0) {
+            SDL_LogSetPriority(SDL_LOG_CATEGORY_AUDIO, SDL_LOG_PRIORITY_VERBOSE);
+            return 2;
+        }
+        if (SDL_strcasecmp(argv[index], "video") == 0) {
+            SDL_LogSetPriority(SDL_LOG_CATEGORY_VIDEO, SDL_LOG_PRIORITY_VERBOSE);
+            return 2;
+        }
+        if (SDL_strcasecmp(argv[index], "render") == 0) {
+            SDL_LogSetPriority(SDL_LOG_CATEGORY_RENDER, SDL_LOG_PRIORITY_VERBOSE);
+            return 2;
+        }
+        if (SDL_strcasecmp(argv[index], "input") == 0) {
+            SDL_LogSetPriority(SDL_LOG_CATEGORY_INPUT, SDL_LOG_PRIORITY_VERBOSE);
+            return 2;
+        }
+        return -1;
+    }
+    if (SDL_strcasecmp(argv[index], "--display") == 0) {
+        ++index;
+        if (!argv[index]) {
+            return -1;
+        }
+        state->display = SDL_atoi(argv[index]);
+        if (SDL_WINDOWPOS_ISUNDEFINED(state->window_x)) {
+            state->window_x = SDL_WINDOWPOS_UNDEFINED_DISPLAY(state->display);
+            state->window_y = SDL_WINDOWPOS_UNDEFINED_DISPLAY(state->display);
+        }
+        if (SDL_WINDOWPOS_ISCENTERED(state->window_x)) {
+            state->window_x = SDL_WINDOWPOS_CENTERED_DISPLAY(state->display);
+            state->window_y = SDL_WINDOWPOS_CENTERED_DISPLAY(state->display);
+        }
+        return 2;
+    }
+    if (SDL_strcasecmp(argv[index], "--metal-window") == 0) {
+        state->window_flags |= SDL_WINDOW_METAL;
+        return 1;
+    }
+    if (SDL_strcasecmp(argv[index], "--opengl-window") == 0) {
+        state->window_flags |= SDL_WINDOW_OPENGL;
+        return 1;
+    }
+    if (SDL_strcasecmp(argv[index], "--vulkan-window") == 0) {
+        state->window_flags |= SDL_WINDOW_VULKAN;
+        return 1;
+    }
+    if (SDL_strcasecmp(argv[index], "--fullscreen") == 0) {
+        state->window_flags |= SDL_WINDOW_FULLSCREEN;
+        state->num_windows = 1;
+        return 1;
+    }
+    if (SDL_strcasecmp(argv[index], "--fullscreen-desktop") == 0) {
+        state->window_flags |= SDL_WINDOW_FULLSCREEN_DESKTOP;
+        state->num_windows = 1;
+        return 1;
+    }
+    if (SDL_strcasecmp(argv[index], "--allow-highdpi") == 0) {
+        state->window_flags |= SDL_WINDOW_ALLOW_HIGHDPI;
+        return 1;
+    }
+    if (SDL_strcasecmp(argv[index], "--windows") == 0) {
+        ++index;
+        if (!argv[index] || !SDL_isdigit((unsigned char) *argv[index])) {
+            return -1;
+        }
+        if (!(state->window_flags & SDL_WINDOW_FULLSCREEN)) {
+            state->num_windows = SDL_atoi(argv[index]);
+        }
+        return 2;
+    }
+    if (SDL_strcasecmp(argv[index], "--title") == 0) {
+        ++index;
+        if (!argv[index]) {
+            return -1;
+        }
+        state->window_title = argv[index];
+        return 2;
+    }
+    if (SDL_strcasecmp(argv[index], "--icon") == 0) {
+        ++index;
+        if (!argv[index]) {
+            return -1;
+        }
+        state->window_icon = argv[index];
+        return 2;
+    }
+    if (SDL_strcasecmp(argv[index], "--center") == 0) {
+        state->window_x = SDL_WINDOWPOS_CENTERED;
+        state->window_y = SDL_WINDOWPOS_CENTERED;
+        return 1;
+    }
+    if (SDL_strcasecmp(argv[index], "--position") == 0) {
+        char *x, *y;
+        ++index;
+        if (!argv[index]) {
+            return -1;
+        }
+        x = argv[index];
+        y = argv[index];
+        while (*y && *y != ',') {
+            ++y;
+        }
+        if (!*y) {
+            return -1;
+        }
+        *y++ = '\0';
+        state->window_x = SDL_atoi(x);
+        state->window_y = SDL_atoi(y);
+        return 2;
+    }
+    if (SDL_strcasecmp(argv[index], "--confine-cursor") == 0) {
+        char *x, *y, *w, *h;
+        ++index;
+        if (!argv[index]) {
+            return -1;
+        }
+        x = argv[index];
+        y = argv[index];
+        #define SEARCHARG(dim) \
+            while (*dim && *dim != ',') { \
+                ++dim; \
+            } \
+            if (!*dim) { \
+                return -1; \
+            } \
+            *dim++ = '\0';
+        SEARCHARG(y)
+        w = y;
+        SEARCHARG(w)
+        h = w;
+        SEARCHARG(h)
+        #undef SEARCHARG
+        state->confine.x = SDL_atoi(x);
+        state->confine.y = SDL_atoi(y);
+        state->confine.w = SDL_atoi(w);
+        state->confine.h = SDL_atoi(h);
+        return 2;
+    }
+    if (SDL_strcasecmp(argv[index], "--usable-bounds") == 0) {
+        /* !!! FIXME: this is a bit of a hack, but I don't want to add a
+           !!! FIXME:  flag to the public structure in 2.0.x */
+        state->window_x = -1;
+        state->window_y = -1;
+        state->window_w = -1;
+        state->window_h = -1;
+        return 1;
+    }
+    if (SDL_strcasecmp(argv[index], "--geometry") == 0) {
+        char *w, *h;
+        ++index;
+        if (!argv[index]) {
+            return -1;
+        }
+        w = argv[index];
+        h = argv[index];
+        while (*h && *h != 'x') {
+            ++h;
+        }
+        if (!*h) {
+            return -1;
+        }
+        *h++ = '\0';
+        state->window_w = SDL_atoi(w);
+        state->window_h = SDL_atoi(h);
+        return 2;
+    }
+    if (SDL_strcasecmp(argv[index], "--min-geometry") == 0) {
+        char *w, *h;
+        ++index;
+        if (!argv[index]) {
+            return -1;
+        }
+        w = argv[index];
+        h = argv[index];
+        while (*h && *h != 'x') {
+            ++h;
+        }
+        if (!*h) {
+            return -1;
+        }
+        *h++ = '\0';
+        state->window_minW = SDL_atoi(w);
+        state->window_minH = SDL_atoi(h);
+        return 2;
+    }
+    if (SDL_strcasecmp(argv[index], "--max-geometry") == 0) {
+        char *w, *h;
+        ++index;
+        if (!argv[index]) {
+            return -1;
+        }
+        w = argv[index];
+        h = argv[index];
+        while (*h && *h != 'x') {
+            ++h;
+        }
+        if (!*h) {
+            return -1;
+        }
+        *h++ = '\0';
+        state->window_maxW = SDL_atoi(w);
+        state->window_maxH = SDL_atoi(h);
+        return 2;
+    }
+    if (SDL_strcasecmp(argv[index], "--logical") == 0) {
+        char *w, *h;
+        ++index;
+        if (!argv[index]) {
+            return -1;
+        

(Patch may be truncated, please check the link at the top of this post.)