Add physics, heap, json_helpers, game, and actor test suites
Raise line coverage from 39.6 to 61.8 percent with four new suites and an extension to the actor suite, and register every suite through a single CMake list so a new test file cannot be left out of the coverage fixture. Give the test targets a build-tree RPATH and prepend the build tree to LD_LIBRARY_PATH for CTest, so a developer with a previously installed libakgl.so exercises the library that was just compiled. Fix six defects the new tests exposed: - akgl_physics_simulate read self->gravity_time before its NULL check, so a NULL backend crashed instead of reporting AKERR_NULLPOINTER. - akgl_game_save transposed CLEANUP and PROCESS, which placed the fclose inside the PROCESS switch. An ordinary save never flushed or closed its stream and produced an empty file. - akgl_game_save_actors wrote each name table terminator from the address of a single char, emitting stack contents into the save file and a sentinel the loader could not recognize. - akgl_game_load_objectnamemap used CATCH directly inside while(1), where the break leaves the loop rather than propagating, so a truncated name table loaded as a successful game. - akgl_Actor_cmhf_up_on and _down_on dereferenced actor->basechar with no NULL check, unlike their left and right counterparts. - akgl_actor_logic_movement checked actor twice instead of checking actor->basechar before dereferencing it. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
107
CMakeLists.txt
107
CMakeLists.txt
@@ -119,27 +119,34 @@ add_library(akgl SHARED
|
||||
add_library(akgl::akgl ALIAS akgl)
|
||||
|
||||
add_executable(charviewer util/charviewer.c)
|
||||
add_executable(test_actor tests/actor.c)
|
||||
add_executable(test_bitmasks tests/bitmasks.c)
|
||||
add_executable(test_character tests/character.c)
|
||||
add_executable(test_registry tests/registry.c)
|
||||
add_executable(test_sprite tests/sprite.c)
|
||||
add_executable(test_staticstring tests/staticstring.c)
|
||||
add_executable(test_tilemap tests/tilemap.c)
|
||||
add_executable(test_util tests/util.c)
|
||||
add_executable(test_semver_unit deps/semver/semver_unit.c)
|
||||
add_test(NAME actor COMMAND test_actor)
|
||||
add_test(NAME bitmasks COMMAND test_bitmasks)
|
||||
add_test(NAME character COMMAND test_character)
|
||||
add_test(NAME registry COMMAND test_registry)
|
||||
add_test(NAME sprite COMMAND test_sprite)
|
||||
add_test(NAME staticstring COMMAND test_staticstring)
|
||||
add_test(NAME tilemap COMMAND test_tilemap)
|
||||
add_test(NAME util COMMAND test_util)
|
||||
|
||||
# Every suite here is a standalone C program named tests/<name>.c, built as
|
||||
# test_<name> and registered with CTest under <name>.
|
||||
set(AKGL_TEST_SUITES
|
||||
actor
|
||||
bitmasks
|
||||
character
|
||||
game
|
||||
heap
|
||||
json_helpers
|
||||
physics
|
||||
registry
|
||||
sprite
|
||||
staticstring
|
||||
tilemap
|
||||
util
|
||||
)
|
||||
|
||||
foreach(suite IN LISTS AKGL_TEST_SUITES)
|
||||
add_executable(test_${suite} tests/${suite}.c)
|
||||
add_test(NAME ${suite} COMMAND test_${suite})
|
||||
endforeach()
|
||||
|
||||
add_test(NAME semver_unit COMMAND test_semver_unit)
|
||||
|
||||
set_tests_properties(
|
||||
actor bitmasks character registry sprite staticstring tilemap util semver_unit
|
||||
${AKGL_TEST_SUITES} semver_unit
|
||||
PROPERTIES WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/tests" TIMEOUT 30
|
||||
)
|
||||
|
||||
@@ -164,8 +171,10 @@ if(AKGL_COVERAGE)
|
||||
--delete
|
||||
)
|
||||
set_tests_properties(coverage_reset PROPERTIES FIXTURES_SETUP akgl_coverage)
|
||||
# Any suite missing from this list runs outside the fixture and has its
|
||||
# counters discarded by coverage_reset.
|
||||
set_tests_properties(
|
||||
actor bitmasks character registry sprite staticstring tilemap util semver_unit
|
||||
${AKGL_TEST_SUITES} semver_unit
|
||||
PROPERTIES FIXTURES_REQUIRED akgl_coverage
|
||||
)
|
||||
|
||||
@@ -198,17 +207,63 @@ target_link_libraries(akgl
|
||||
jansson::jansson
|
||||
)
|
||||
|
||||
target_link_libraries(test_actor PRIVATE akstdlib::akstdlib akerror::akerror akgl SDL3::SDL3 SDL3_ttf::SDL3_ttf SDL3_image::SDL3_image SDL3_mixer::SDL3_mixer jansson::jansson -lm)
|
||||
target_link_libraries(test_bitmasks PRIVATE akstdlib::akstdlib akerror::akerror akgl SDL3::SDL3 SDL3_ttf::SDL3_ttf SDL3_image::SDL3_image SDL3_mixer::SDL3_mixer jansson::jansson -lm)
|
||||
target_link_libraries(test_character PRIVATE akstdlib::akstdlib akerror::akerror akgl SDL3::SDL3 SDL3_ttf::SDL3_ttf SDL3_image::SDL3_image SDL3_mixer::SDL3_mixer jansson::jansson -lm)
|
||||
target_link_libraries(test_registry PRIVATE akstdlib::akstdlib akerror::akerror akgl SDL3::SDL3 SDL3_ttf::SDL3_ttf SDL3_image::SDL3_image SDL3_mixer::SDL3_mixer jansson::jansson -lm)
|
||||
target_link_libraries(test_sprite PRIVATE akstdlib::akstdlib akerror::akerror akgl SDL3::SDL3 SDL3_ttf::SDL3_ttf SDL3_image::SDL3_image SDL3_mixer::SDL3_mixer jansson::jansson -lm)
|
||||
target_link_libraries(test_staticstring PRIVATE akstdlib::akstdlib akerror::akerror akgl SDL3::SDL3 SDL3_ttf::SDL3_ttf SDL3_image::SDL3_image SDL3_mixer::SDL3_mixer jansson::jansson -lm)
|
||||
target_link_libraries(test_tilemap PRIVATE akstdlib::akstdlib akerror::akerror akgl SDL3::SDL3 SDL3_ttf::SDL3_ttf SDL3_image::SDL3_image SDL3_mixer::SDL3_mixer jansson::jansson -lm)
|
||||
target_link_libraries(test_util PRIVATE akstdlib::akstdlib akerror::akerror akgl SDL3::SDL3 SDL3_ttf::SDL3_ttf SDL3_image::SDL3_image SDL3_mixer::SDL3_mixer jansson::jansson -lm)
|
||||
foreach(suite IN LISTS AKGL_TEST_SUITES)
|
||||
target_link_libraries(test_${suite} PRIVATE akstdlib::akstdlib akerror::akerror akgl SDL3::SDL3 SDL3_ttf::SDL3_ttf SDL3_image::SDL3_image SDL3_mixer::SDL3_mixer jansson::jansson -lm)
|
||||
target_include_directories(test_${suite} PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/tests")
|
||||
endforeach()
|
||||
|
||||
target_link_libraries(charviewer PRIVATE akstdlib::akstdlib akerror::akerror akgl SDL3::SDL3 SDL3_ttf::SDL3_ttf SDL3_image::SDL3_image SDL3_mixer::SDL3_mixer jansson::jansson -lm)
|
||||
|
||||
# When the vendored SDL satellite libraries are built in-tree they land in per-
|
||||
# project subdirectories that are not on the loader's default search path, so a
|
||||
# freshly built test aborts before main() with "cannot open shared object file".
|
||||
# Bake those directories into the build-tree RPATH. Installed builds resolve the
|
||||
# same libraries through find_package and need no help.
|
||||
if(CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR)
|
||||
set(AKGL_VENDORED_RPATH
|
||||
"$<TARGET_FILE_DIR:SDL3::SDL3>"
|
||||
"$<TARGET_FILE_DIR:SDL3_image::SDL3_image>"
|
||||
"$<TARGET_FILE_DIR:SDL3_ttf::SDL3_ttf>"
|
||||
"$<TARGET_FILE_DIR:SDL3_mixer::SDL3_mixer>"
|
||||
"$<TARGET_FILE_DIR:akerror::akerror>"
|
||||
"$<TARGET_FILE_DIR:akstdlib::akstdlib>"
|
||||
)
|
||||
foreach(suite IN LISTS AKGL_TEST_SUITES)
|
||||
set_target_properties(test_${suite} PROPERTIES BUILD_RPATH "${AKGL_VENDORED_RPATH}")
|
||||
endforeach()
|
||||
set_target_properties(charviewer akgl PROPERTIES BUILD_RPATH "${AKGL_VENDORED_RPATH}")
|
||||
|
||||
# RPATH alone is not enough: LD_LIBRARY_PATH is searched first, so a developer
|
||||
# who has previously run rebuild.sh has an installed libakgl.so ahead of the
|
||||
# one under test. Prepend the build tree for the CTest run so the suite always
|
||||
# exercises what was just compiled.
|
||||
set(AKGL_TEST_LIBPATH
|
||||
"${CMAKE_CURRENT_BINARY_DIR}"
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/deps/SDL"
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/deps/SDL_image"
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/deps/SDL_ttf"
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/deps/SDL_mixer"
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/deps/libakerror"
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/deps/libakstdlib"
|
||||
)
|
||||
if(CMAKE_VERSION VERSION_GREATER_EQUAL "3.22")
|
||||
set(AKGL_TEST_ENV_MOD "")
|
||||
foreach(dir IN LISTS AKGL_TEST_LIBPATH)
|
||||
list(APPEND AKGL_TEST_ENV_MOD "LD_LIBRARY_PATH=path_list_prepend:${dir}")
|
||||
endforeach()
|
||||
set_tests_properties(
|
||||
${AKGL_TEST_SUITES}
|
||||
PROPERTIES ENVIRONMENT_MODIFICATION "${AKGL_TEST_ENV_MOD}"
|
||||
)
|
||||
else()
|
||||
string(REPLACE ";" ":" AKGL_TEST_LIBPATH_JOINED "${AKGL_TEST_LIBPATH}")
|
||||
set_tests_properties(
|
||||
${AKGL_TEST_SUITES}
|
||||
PROPERTIES ENVIRONMENT "LD_LIBRARY_PATH=${AKGL_TEST_LIBPATH_JOINED}:$ENV{LD_LIBRARY_PATH}"
|
||||
)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Mutation testing copies the repository to scratch space, applies one small
|
||||
# source change at a time, and verifies that the passing tests detect it. The
|
||||
# intentionally failing character test is excluded by the harness.
|
||||
|
||||
Reference in New Issue
Block a user