Stop set_tests_properties from eating the test environment lists

The example games failed on the CI runner with "ALSA: Couldn't open audio
device" despite SDL_AUDIODRIVER=dummy sitting right there in their CMake --
because it never reached the process. set_tests_properties parses its
PROPERTIES arguments as name/value pairs, so a semicolon-separated value
list is split and every element after the first is consumed as a bogus
property name: ENVIRONMENT kept only SDL_VIDEODRIVER=dummy, and the
LD_LIBRARY_PATH prepend list kept only its first directory. ctest
--show-only=json-v1 shows the truncation plainly.

Nobody could see it. Video survived because SDL3 falls through its driver
list to dummy on a headless machine with no hint at all; audio survived on
every developer machine because the real device works there; the library
paths survived because RPATH covered them. A runner with no sound card was
the first environment where any of it mattered.

Every list-valued test property now goes through set_property(TEST ...),
which takes real list arguments -- the examples' ENVIRONMENT triplets and
vendored-path modifications, the suites' LD_LIBRARY_PATH prepends, and the
docs harness's driver variables. Verified by property dump (3 environment
entries and all 7 prepends present) and by running the example tests with
ALSA_CONFIG_PATH=/dev/null, which now pass where a real ALSA open would
fail: the dummy driver is finally the one being asked.

Co-Authored-By: Claude Code (Claude Fable 5, claude-fable-5) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KzBDV2fqgnUAcqCKqKvc71
Co-Authored-By: Andrew Kesterson <andrew@aklabs.net>
This commit is contained in:
2026-08-02 14:19:05 -04:00
parent 3fb9e8eb62
commit 12c18d4370
4 changed files with 64 additions and 33 deletions

View File

@@ -662,20 +662,26 @@ if(AKGL_VENDORED_DEPENDENCIES)
"${CMAKE_CURRENT_BINARY_DIR}/deps/libakerror" "${CMAKE_CURRENT_BINARY_DIR}/deps/libakerror"
"${CMAKE_CURRENT_BINARY_DIR}/deps/libakstdlib" "${CMAKE_CURRENT_BINARY_DIR}/deps/libakstdlib"
) )
# set_property rather than set_tests_properties for the list-valued
# property: set_tests_properties parses its PROPERTIES arguments as
# name/value pairs, so a semicolon-separated value is split and every
# element after the first is consumed as a bogus property name -- which
# silently reduced this prepend list to its first directory for as long as
# it existed. RPATH covered for it locally; a runner found it.
if(CMAKE_VERSION VERSION_GREATER_EQUAL "3.22") if(CMAKE_VERSION VERSION_GREATER_EQUAL "3.22")
set(AKGL_TEST_ENV_MOD "") set(AKGL_TEST_ENV_MOD "")
foreach(dir IN LISTS AKGL_TEST_LIBPATH) foreach(dir IN LISTS AKGL_TEST_LIBPATH)
list(APPEND AKGL_TEST_ENV_MOD "LD_LIBRARY_PATH=path_list_prepend:${dir}") list(APPEND AKGL_TEST_ENV_MOD "LD_LIBRARY_PATH=path_list_prepend:${dir}")
endforeach() endforeach()
set_tests_properties( set_property(
${AKGL_TEST_SUITES} ${AKGL_PERF_SUITES} TEST ${AKGL_TEST_SUITES} ${AKGL_PERF_SUITES}
PROPERTIES ENVIRONMENT_MODIFICATION "${AKGL_TEST_ENV_MOD}" PROPERTY ENVIRONMENT_MODIFICATION ${AKGL_TEST_ENV_MOD}
) )
else() else()
string(REPLACE ";" ":" AKGL_TEST_LIBPATH_JOINED "${AKGL_TEST_LIBPATH}") string(REPLACE ";" ":" AKGL_TEST_LIBPATH_JOINED "${AKGL_TEST_LIBPATH}")
set_tests_properties( set_property(
${AKGL_TEST_SUITES} ${AKGL_PERF_SUITES} TEST ${AKGL_TEST_SUITES} ${AKGL_PERF_SUITES}
PROPERTIES ENVIRONMENT "LD_LIBRARY_PATH=${AKGL_TEST_LIBPATH_JOINED}:$ENV{LD_LIBRARY_PATH}" PROPERTY ENVIRONMENT "LD_LIBRARY_PATH=${AKGL_TEST_LIBPATH_JOINED}:$ENV{LD_LIBRARY_PATH}"
) )
endif() endif()
endif() endif()
@@ -783,7 +789,12 @@ add_test(
set_tests_properties(docs_examples PROPERTIES set_tests_properties(docs_examples PROPERTIES
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
TIMEOUT 900 TIMEOUT 900
ENVIRONMENT "SDL_VIDEODRIVER=dummy;SDL_AUDIODRIVER=dummy;SDL_RENDER_DRIVER=software" )
# set_property for the same pair-splitting reason as the suites above.
set_property(TEST docs_examples PROPERTY ENVIRONMENT
"SDL_VIDEODRIVER=dummy"
"SDL_AUDIODRIVER=dummy"
"SDL_RENDER_DRIVER=software"
) )
# Every figure in docs/ re-rendered and byte-compared against the tracked copy. # Every figure in docs/ re-rendered and byte-compared against the tracked copy.
@@ -808,7 +819,11 @@ add_test(
set_tests_properties(docs_screenshots PROPERTIES set_tests_properties(docs_screenshots PROPERTIES
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
TIMEOUT 900 TIMEOUT 900
ENVIRONMENT "SDL_VIDEODRIVER=dummy;SDL_AUDIODRIVER=dummy;SDL_RENDER_DRIVER=software" )
set_property(TEST docs_screenshots PROPERTY ENVIRONMENT
"SDL_VIDEODRIVER=dummy"
"SDL_AUDIODRIVER=dummy"
"SDL_RENDER_DRIVER=software"
) )
# Regenerating the figures is a deliberate act, never part of a build: the PNGs # Regenerating the figures is a deliberate act, never part of a build: the PNGs

View File

@@ -47,26 +47,31 @@ endif()
# it to suppress the vendored projects' registrations and lifts the suppression # it to suppress the vendored projects' registrations and lifts the suppression
# again long before examples/ is added. # again long before examples/ is added.
add_test(NAME example_jrpg COMMAND jrpg --frames 320 --demo) add_test(NAME example_jrpg COMMAND jrpg --frames 320 --demo)
set_tests_properties(example_jrpg PROPERTIES set_tests_properties(example_jrpg PROPERTIES TIMEOUT 120)
TIMEOUT 120 # set_property, not set_tests_properties: the latter parses its PROPERTIES
ENVIRONMENT "SDL_VIDEODRIVER=dummy;SDL_RENDER_DRIVER=software;SDL_AUDIODRIVER=dummy" # arguments as name/value *pairs*, so a semicolon-separated value is split and
# every element after the first is consumed as a bogus property name. The
# audio and render entries of this list were silently lost that way --
# invisible on any machine whose real audio device works, and found the first
# time CI ran on a runner without one.
set_property(TEST example_jrpg PROPERTY ENVIRONMENT
"SDL_VIDEODRIVER=dummy"
"SDL_RENDER_DRIVER=software"
"SDL_AUDIODRIVER=dummy"
) )
# ENVIRONMENT above replaces the environment wholesale, so LD_LIBRARY_PATH has # LD_LIBRARY_PATH for the vendored satellite libraries. Only needed when they
# to go in the same property rather than a second one. Only needed when the # were vendored; an installed build resolves them normally.
# dependencies were vendored; an installed build resolves them normally.
if(AKGL_VENDORED_DEPENDENCIES) if(AKGL_VENDORED_DEPENDENCIES)
if(CMAKE_VERSION VERSION_GREATER_EQUAL "3.22") if(CMAKE_VERSION VERSION_GREATER_EQUAL "3.22")
set(JRPG_TEST_ENV_MOD "") set(JRPG_TEST_ENV_MOD "")
foreach(dir IN LISTS AKGL_TEST_LIBPATH) foreach(dir IN LISTS AKGL_TEST_LIBPATH)
list(APPEND JRPG_TEST_ENV_MOD "LD_LIBRARY_PATH=path_list_prepend:${dir}") list(APPEND JRPG_TEST_ENV_MOD "LD_LIBRARY_PATH=path_list_prepend:${dir}")
endforeach() endforeach()
set_tests_properties(example_jrpg set_property(TEST example_jrpg PROPERTY ENVIRONMENT_MODIFICATION ${JRPG_TEST_ENV_MOD})
PROPERTIES ENVIRONMENT_MODIFICATION "${JRPG_TEST_ENV_MOD}")
else() else()
string(REPLACE ";" ":" JRPG_TEST_LIBPATH_JOINED "${AKGL_TEST_LIBPATH}") string(REPLACE ";" ":" JRPG_TEST_LIBPATH_JOINED "${AKGL_TEST_LIBPATH}")
set_tests_properties(example_jrpg PROPERTIES set_property(TEST example_jrpg APPEND PROPERTY ENVIRONMENT
ENVIRONMENT "SDL_VIDEODRIVER=dummy;SDL_RENDER_DRIVER=software;SDL_AUDIODRIVER=dummy;LD_LIBRARY_PATH=${JRPG_TEST_LIBPATH_JOINED}:$ENV{LD_LIBRARY_PATH}" "LD_LIBRARY_PATH=${JRPG_TEST_LIBPATH_JOINED}:$ENV{LD_LIBRARY_PATH}")
)
endif() endif()
endif() endif()

View File

@@ -41,7 +41,15 @@ endif()
# while this project is top-level, and by the time examples/ is added the # while this project is top-level, and by the time examples/ is added the
# suppression has already been lifted. An embedded build gets the builtin. # suppression has already been lifted. An embedded build gets the builtin.
add_test(NAME example_sidescroller COMMAND sidescroller --frames 240 --autoplay) add_test(NAME example_sidescroller COMMAND sidescroller --frames 240 --autoplay)
set_tests_properties(example_sidescroller PROPERTIES set_tests_properties(example_sidescroller PROPERTIES TIMEOUT 120)
TIMEOUT 120 # set_property, not set_tests_properties: the latter parses its PROPERTIES
ENVIRONMENT "SDL_VIDEODRIVER=dummy;SDL_RENDER_DRIVER=software;SDL_AUDIODRIVER=dummy" # arguments as name/value *pairs*, so a semicolon-separated value is split and
# every element after the first is consumed as a bogus property name. The
# audio and render entries of this very list were silently lost that way for
# as long as the list existed -- invisible on any machine whose real audio
# device works, and found the first time CI ran on a runner without one.
set_property(TEST example_sidescroller PROPERTY ENVIRONMENT
"SDL_VIDEODRIVER=dummy"
"SDL_RENDER_DRIVER=software"
"SDL_AUDIODRIVER=dummy"
) )

View File

@@ -34,26 +34,29 @@ endif()
# main() returns. There is no physics here, so nothing needs a driven clock; # main() returns. There is no physics here, so nothing needs a driven clock;
# `--frames` is a backstop above the script's last step, not the exit path. # `--frames` is a backstop above the script's last step, not the exit path.
add_test(NAME example_uidemo COMMAND uidemo --frames 240 --demo) add_test(NAME example_uidemo COMMAND uidemo --frames 240 --demo)
set_tests_properties(example_uidemo PROPERTIES set_tests_properties(example_uidemo PROPERTIES TIMEOUT 120)
TIMEOUT 120 # set_property, not set_tests_properties: the latter parses its PROPERTIES
ENVIRONMENT "SDL_VIDEODRIVER=dummy;SDL_RENDER_DRIVER=software;SDL_AUDIODRIVER=dummy" # arguments as name/value *pairs*, so a semicolon-separated value is split and
# every element after the first is consumed as a bogus property name. See the
# same note in the other examples' CMakeLists.
set_property(TEST example_uidemo PROPERTY ENVIRONMENT
"SDL_VIDEODRIVER=dummy"
"SDL_RENDER_DRIVER=software"
"SDL_AUDIODRIVER=dummy"
) )
# ENVIRONMENT above replaces the environment wholesale, so LD_LIBRARY_PATH has # LD_LIBRARY_PATH for the vendored satellite libraries. Only needed when they
# to go in the same property rather than a second one. Only needed when the # were vendored; an installed build resolves them normally.
# dependencies were vendored; an installed build resolves them normally.
if(AKGL_VENDORED_DEPENDENCIES) if(AKGL_VENDORED_DEPENDENCIES)
if(CMAKE_VERSION VERSION_GREATER_EQUAL "3.22") if(CMAKE_VERSION VERSION_GREATER_EQUAL "3.22")
set(UIDEMO_TEST_ENV_MOD "") set(UIDEMO_TEST_ENV_MOD "")
foreach(dir IN LISTS AKGL_TEST_LIBPATH) foreach(dir IN LISTS AKGL_TEST_LIBPATH)
list(APPEND UIDEMO_TEST_ENV_MOD "LD_LIBRARY_PATH=path_list_prepend:${dir}") list(APPEND UIDEMO_TEST_ENV_MOD "LD_LIBRARY_PATH=path_list_prepend:${dir}")
endforeach() endforeach()
set_tests_properties(example_uidemo set_property(TEST example_uidemo PROPERTY ENVIRONMENT_MODIFICATION ${UIDEMO_TEST_ENV_MOD})
PROPERTIES ENVIRONMENT_MODIFICATION "${UIDEMO_TEST_ENV_MOD}")
else() else()
string(REPLACE ";" ":" UIDEMO_TEST_LIBPATH_JOINED "${AKGL_TEST_LIBPATH}") string(REPLACE ";" ":" UIDEMO_TEST_LIBPATH_JOINED "${AKGL_TEST_LIBPATH}")
set_tests_properties(example_uidemo PROPERTIES set_property(TEST example_uidemo APPEND PROPERTY ENVIRONMENT
ENVIRONMENT "SDL_VIDEODRIVER=dummy;SDL_RENDER_DRIVER=software;SDL_AUDIODRIVER=dummy;LD_LIBRARY_PATH=${UIDEMO_TEST_LIBPATH_JOINED}:$ENV{LD_LIBRARY_PATH}" "LD_LIBRARY_PATH=${UIDEMO_TEST_LIBPATH_JOINED}:$ENV{LD_LIBRARY_PATH}")
)
endif() endif()
endif() endif()