SDL: ctest: fail if there are outstanding allocations

From b68ac011e0bce42b2c5142e200c1441f846b4faa Mon Sep 17 00:00:00 2001
From: Anonymous Maarten <[EMAIL REDACTED]>
Date: Sun, 28 Jul 2024 17:19:49 +0200
Subject: [PATCH] ctest: fail if there are outstanding allocations

---
 .github/workflows/generic.yml |  1 +
 test/CMakeLists.txt           | 16 ++++++++++++++--
 2 files changed, 15 insertions(+), 2 deletions(-)

diff --git a/.github/workflows/generic.yml b/.github/workflows/generic.yml
index 0deb5f34c9805..9a05ff16d2fd1 100644
--- a/.github/workflows/generic.yml
+++ b/.github/workflows/generic.yml
@@ -138,6 +138,7 @@ jobs:
             -DSDL_WERROR=${{ matrix.platform.werror }} \
             -DSDL_EXAMPLES=${{ matrix.platform.build-tests }} \
             -DSDL_TESTS=${{ matrix.platform.build-tests }} \
+            -DSDLTEST_TRACKMEM=ON \
             -DSDL_INSTALL_TESTS=${{ matrix.platform.build-tests }} \
             -DSDL_CLANG_TIDY=${{ matrix.platform.clang-tidy }} \
             -DSDL_DISABLE_INSTALL_DOCS=OFF \
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index 713b45b3e114e..70efce63f1154 100644
--- a/test/CMakeLists.txt
+++ b/test/CMakeLists.txt
@@ -38,6 +38,8 @@ target_link_libraries(sdltests_utils PRIVATE SDL3::Headers)
 
 file(GLOB RESOURCE_FILES *.bmp *.wav *.hex moose.dat utf8.txt)
 
+option(SDLTEST_TRACKMEM "Run tests with --trackmem" OFF)
+
 if(WIN32 AND NOT WINDOWS_STORE)
     option(SDLTEST_PROCDUMP "Run tests using sdlprocdump for minidump generation" OFF)
     add_executable(sdlprocdump win32/sdlprocdump.c)
@@ -97,7 +99,7 @@ if(WINDOWS_STORE)
 endif()
 
 macro(add_sdl_test_executable TARGET)
-    cmake_parse_arguments(AST "BUILD_DEPENDENT;NONINTERACTIVE;NEEDS_RESOURCES;TESTUTILS;NO_C90;MAIN_CALLBACKS" "" "NONINTERACTIVE_TIMEOUT;NONINTERACTIVE_ARGS;SOURCES" ${ARGN})
+    cmake_parse_arguments(AST "BUILD_DEPENDENT;NONINTERACTIVE;NEEDS_RESOURCES;TESTUTILS;NO_C90;MAIN_CALLBACKS;NOTRACKMEM" "" "NONINTERACTIVE_TIMEOUT;NONINTERACTIVE_ARGS;SOURCES" ${ARGN})
     if(AST_UNPARSED_ARGUMENTS)
         message(FATAL_ERROR "Unknown argument(s): ${AST_UNPARSED_ARGUMENTS}")
     endif()
@@ -151,6 +153,7 @@ macro(add_sdl_test_executable TARGET)
     endif()
 
     list(APPEND SDL_TEST_EXECUTABLES ${TARGET})
+    set_property(TARGET ${TARGET} PROPERTY SDL_NOTRACKMEM ${AST_NOTRACKMEM})
     if(AST_NONINTERACTIVE)
         set_property(TARGET ${TARGET} PROPERTY SDL_NONINTERACTIVE 1)
     endif()
@@ -409,7 +412,7 @@ add_sdl_test_executable(testspritesurface SOURCES testspritesurface.c ${icon_bmp
 add_sdl_test_executable(teststreaming NEEDS_RESOURCES TESTUTILS SOURCES teststreaming.c)
 add_sdl_test_executable(testtimer NONINTERACTIVE NONINTERACTIVE_ARGS --no-interactive NONINTERACTIVE_TIMEOUT 60 SOURCES testtimer.c)
 add_sdl_test_executable(testurl SOURCES testurl.c)
-add_sdl_test_executable(testver NONINTERACTIVE SOURCES testver.c)
+add_sdl_test_executable(testver NONINTERACTIVE NOTRACKMEM SOURCES testver.c)
 add_sdl_test_executable(testcamera MAIN_CALLBACKS SOURCES testcamera.c)
 add_sdl_test_executable(testviewport NEEDS_RESOURCES TESTUTILS SOURCES testviewport.c)
 add_sdl_test_executable(testwm SOURCES testwm.c)
@@ -610,11 +613,20 @@ function(add_sdl_test TEST TARGET)
         if(noninteractive_arguments)
             list(APPEND command ${noninteractive_arguments})
         endif()
+        if(SDLTEST_TRACKMEM)
+            get_property(notrackmem TARGET ${TARGET} PROPERTY SDL_NOTRACKMEM)
+            if(NOT notrackmem)
+                list(APPEND command --trackmem)
+            endif()
+        endif()
         add_test(
                 NAME ${TEST}
                 COMMAND ${command}
                 WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
         )
+        if(NOT notrackmem)
+            set_property(TEST ${TEST} PROPERTY FAIL_REGULAR_EXPRESSION "Total: [0-9]+\\.[0-9]+ Kb in [1-9][0-9]* allocations")
+        endif()
         set_tests_properties(${TEST} PROPERTIES ENVIRONMENT "${TESTS_ENVIRONMENT}")
         get_property(noninteractive_timeout TARGET ${TARGET} PROPERTY SDL_NONINTERACTIVE_TIMEOUT)
         if(NOT noninteractive_timeout)