2026-05-10 00:00:31 -04:00
|
|
|
cmake_minimum_required(VERSION 3.10)
|
|
|
|
|
project(akstdlib LANGUAGES C)
|
|
|
|
|
|
2026-06-27 12:11:27 -04:00
|
|
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -ggdb -pg")
|
|
|
|
|
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -g -ggdb -pg")
|
|
|
|
|
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -g -ggdb -pg")
|
|
|
|
|
|
Build a real test harness (TODO.md section 1.0)
The suite could not fail and did not run. test_linkedlist.c asserted nothing
at all -- it printed node names and returned 0 -- so every confirmed list
defect passed it. test_tree.c was red on every run because parms.steps was
never reset between its three searches, and four libakerror tests registered
but never built, reporting Not Run. CI, meanwhile, was not fetching the
submodule, so configure failed before reaching any of it.
- tests/aksl_capture.h: AKSL_CHECK (NDEBUG-proof), AKSL_CHECK_STATUS/_OK to
run an akerror-returning call, assert its status and release the context,
a capturing akerr_log_method, aksl_slots_in_use(), and an AKSL_RUN driver
that fails any test leaking an error-pool slot.
- test_linkedlist.c: rewritten as 15 assertion cases over the append,
iterate and pop behaviour that is correct today.
- test_tree.c: each search builds its own tree and params.
- Registration driven by AKSL_TESTS, plus AKSL_WILL_FAIL_TESTS (aborts by
design) and AKSL_KNOWN_FAILING_TESTS, which marks WILL_FAIL the three new
tests asserting correct behaviour for the confirmed defects in TODO.md
2.1.1-2.1.3. Fixing a defect flips its test to "unexpectedly passed",
which is the cue to promote it into AKSL_TESTS.
- add_test/set_tests_properties are shadowed across the libakerror
add_subdirectory call: CMake cannot un-register a test and
set_tests_properties cannot cross directory scopes. The dependency has
its own CI.
- AKSL_SANITIZE=ON builds library, tests and dependency with ASan+UBSan.
- scripts/mutation_test.py ported and retargeted at src/stdlib.c; wired to
a manual `mutation` target, not a CI gate until 1.1-1.9 exist.
- CI: checkout with submodules: recursive, and ctest --output-on-failure.
ctest is now 5/5 green in both the default and sanitizer builds.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-28 12:39:54 -04:00
|
|
|
# Sanitizer build, off by default:
|
|
|
|
|
# cmake -S . -B build-asan -DAKSL_SANITIZE=ON && ctest --test-dir build-asan
|
|
|
|
|
# Set before the dependency is added so libakerror is instrumented too --
|
|
|
|
|
# several of the defects in TODO.md section 2 (the uninitialised %s in
|
|
|
|
|
# aksl_realpath, the unbounded vsprintf in aksl_sprintf, the missing va_end in
|
|
|
|
|
# the printf family) only show up under ASan/UBSan.
|
|
|
|
|
option(AKSL_SANITIZE "Build the library and its tests with ASan + UBSan" OFF)
|
|
|
|
|
if(AKSL_SANITIZE)
|
|
|
|
|
set(AKSL_SANITIZE_FLAGS "-fsanitize=address,undefined -fno-omit-frame-pointer -fno-sanitize-recover=all")
|
|
|
|
|
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${AKSL_SANITIZE_FLAGS}")
|
|
|
|
|
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${AKSL_SANITIZE_FLAGS}")
|
|
|
|
|
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${AKSL_SANITIZE_FLAGS}")
|
|
|
|
|
message(STATUS "AKSL_SANITIZE=ON: building with ASan + UBSan")
|
|
|
|
|
endif()
|
|
|
|
|
|
2026-05-12 21:29:20 -04:00
|
|
|
if(TARGET akerror::akerror)
|
|
|
|
|
message(STATUS "FOUND akerror::akerror")
|
|
|
|
|
else()
|
|
|
|
|
message(STATUS "MISSING akerror::akerror")
|
|
|
|
|
endif()
|
|
|
|
|
|
2026-05-10 00:00:31 -04:00
|
|
|
include(CTest)
|
|
|
|
|
include(GNUInstallDirs)
|
|
|
|
|
include(CMakePackageConfigHelpers)
|
|
|
|
|
|
2026-06-27 12:11:27 -04:00
|
|
|
if(CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR)
|
Build a real test harness (TODO.md section 1.0)
The suite could not fail and did not run. test_linkedlist.c asserted nothing
at all -- it printed node names and returned 0 -- so every confirmed list
defect passed it. test_tree.c was red on every run because parms.steps was
never reset between its three searches, and four libakerror tests registered
but never built, reporting Not Run. CI, meanwhile, was not fetching the
submodule, so configure failed before reaching any of it.
- tests/aksl_capture.h: AKSL_CHECK (NDEBUG-proof), AKSL_CHECK_STATUS/_OK to
run an akerror-returning call, assert its status and release the context,
a capturing akerr_log_method, aksl_slots_in_use(), and an AKSL_RUN driver
that fails any test leaking an error-pool slot.
- test_linkedlist.c: rewritten as 15 assertion cases over the append,
iterate and pop behaviour that is correct today.
- test_tree.c: each search builds its own tree and params.
- Registration driven by AKSL_TESTS, plus AKSL_WILL_FAIL_TESTS (aborts by
design) and AKSL_KNOWN_FAILING_TESTS, which marks WILL_FAIL the three new
tests asserting correct behaviour for the confirmed defects in TODO.md
2.1.1-2.1.3. Fixing a defect flips its test to "unexpectedly passed",
which is the cue to promote it into AKSL_TESTS.
- add_test/set_tests_properties are shadowed across the libakerror
add_subdirectory call: CMake cannot un-register a test and
set_tests_properties cannot cross directory scopes. The dependency has
its own CI.
- AKSL_SANITIZE=ON builds library, tests and dependency with ASan+UBSan.
- scripts/mutation_test.py ported and retargeted at src/stdlib.c; wired to
a manual `mutation` target, not a CI gate until 1.1-1.9 exist.
- CI: checkout with submodules: recursive, and ctest --output-on-failure.
ctest is now 5/5 green in both the default and sanitizer builds.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-28 12:39:54 -04:00
|
|
|
# libakerror registers its own CTest entries unconditionally, and because we
|
|
|
|
|
# pull it in EXCLUDE_FROM_ALL its test binaries are never built -- so every
|
|
|
|
|
# one of them used to show up in our suite as "Not Run" and fail. CMake has no
|
|
|
|
|
# way to un-register a test, and set_tests_properties cannot reach across
|
|
|
|
|
# directory scopes, so add_test() is shadowed for the duration of the
|
|
|
|
|
# add_subdirectory() call. The dependency has its own CI; this project's suite
|
|
|
|
|
# should only contain this project's tests.
|
|
|
|
|
set(AKSL_SUPPRESS_ADD_TEST TRUE)
|
|
|
|
|
function(add_test)
|
|
|
|
|
if(NOT AKSL_SUPPRESS_ADD_TEST)
|
|
|
|
|
_add_test(${ARGV})
|
|
|
|
|
endif()
|
|
|
|
|
endfunction()
|
|
|
|
|
# libakerror also marks two of those tests WILL_FAIL, which would now be
|
|
|
|
|
# setting properties on tests that no longer exist, so suppress that too.
|
|
|
|
|
function(set_tests_properties)
|
|
|
|
|
if(NOT AKSL_SUPPRESS_ADD_TEST)
|
|
|
|
|
_set_tests_properties(${ARGV})
|
|
|
|
|
endif()
|
|
|
|
|
endfunction()
|
|
|
|
|
|
2026-06-27 12:11:27 -04:00
|
|
|
add_subdirectory(deps/libakerror EXCLUDE_FROM_ALL)
|
Build a real test harness (TODO.md section 1.0)
The suite could not fail and did not run. test_linkedlist.c asserted nothing
at all -- it printed node names and returned 0 -- so every confirmed list
defect passed it. test_tree.c was red on every run because parms.steps was
never reset between its three searches, and four libakerror tests registered
but never built, reporting Not Run. CI, meanwhile, was not fetching the
submodule, so configure failed before reaching any of it.
- tests/aksl_capture.h: AKSL_CHECK (NDEBUG-proof), AKSL_CHECK_STATUS/_OK to
run an akerror-returning call, assert its status and release the context,
a capturing akerr_log_method, aksl_slots_in_use(), and an AKSL_RUN driver
that fails any test leaking an error-pool slot.
- test_linkedlist.c: rewritten as 15 assertion cases over the append,
iterate and pop behaviour that is correct today.
- test_tree.c: each search builds its own tree and params.
- Registration driven by AKSL_TESTS, plus AKSL_WILL_FAIL_TESTS (aborts by
design) and AKSL_KNOWN_FAILING_TESTS, which marks WILL_FAIL the three new
tests asserting correct behaviour for the confirmed defects in TODO.md
2.1.1-2.1.3. Fixing a defect flips its test to "unexpectedly passed",
which is the cue to promote it into AKSL_TESTS.
- add_test/set_tests_properties are shadowed across the libakerror
add_subdirectory call: CMake cannot un-register a test and
set_tests_properties cannot cross directory scopes. The dependency has
its own CI.
- AKSL_SANITIZE=ON builds library, tests and dependency with ASan+UBSan.
- scripts/mutation_test.py ported and retargeted at src/stdlib.c; wired to
a manual `mutation` target, not a CI gate until 1.1-1.9 exist.
- CI: checkout with submodules: recursive, and ctest --output-on-failure.
ctest is now 5/5 green in both the default and sanitizer builds.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-28 12:39:54 -04:00
|
|
|
|
|
|
|
|
set(AKSL_SUPPRESS_ADD_TEST FALSE)
|
2026-06-27 12:11:27 -04:00
|
|
|
else()
|
|
|
|
|
if(NOT TARGET akerror::akerror)
|
|
|
|
|
find_package(PkgConfig REQUIRED)
|
|
|
|
|
find_package(akerror REQUIRED)
|
|
|
|
|
endif()
|
2026-05-12 21:29:20 -04:00
|
|
|
endif()
|
2026-05-10 00:00:31 -04:00
|
|
|
|
|
|
|
|
set(akstdlib_install_cmakedir "${CMAKE_INSTALL_LIBDIR}/cmake/akstdlib")
|
|
|
|
|
set(prefix ${CMAKE_INSTALL_PREFIX})
|
|
|
|
|
set(exec_prefix "\${prefix}")
|
|
|
|
|
set(libdir "\${exec_prefix}/lib")
|
|
|
|
|
set(includedir "\${prefix}/include")
|
|
|
|
|
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/akstdlib.pc.in ${CMAKE_CURRENT_BINARY_DIR}/akstdlib.pc @ONLY)
|
|
|
|
|
|
|
|
|
|
add_library(akstdlib SHARED
|
|
|
|
|
src/stdlib.c
|
|
|
|
|
)
|
|
|
|
|
|
2026-05-12 21:29:20 -04:00
|
|
|
add_library(akstdlib::akstdlib ALIAS akstdlib)
|
|
|
|
|
|
2026-05-10 00:00:31 -04:00
|
|
|
# Specify include directories for the library's headers (if applicable)
|
|
|
|
|
target_include_directories(akstdlib PUBLIC
|
|
|
|
|
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
|
|
|
|
|
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}/>
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
target_link_libraries(akstdlib PUBLIC akerror::akerror)
|
|
|
|
|
|
|
|
|
|
set(main_lib_dest "lib/my_library-${MY_LIBRARY_VERSION}")
|
|
|
|
|
install(TARGETS akstdlib
|
|
|
|
|
EXPORT akstdlibTargets
|
|
|
|
|
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
|
|
|
|
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
|
|
|
|
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
|
|
|
|
|
INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
install(FILES "include/akstdlib.h" DESTINATION "include/")
|
|
|
|
|
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/akstdlib.pc DESTINATION "lib/pkgconfig/")
|
|
|
|
|
|
|
|
|
|
|
2026-05-12 21:29:20 -04:00
|
|
|
install(EXPORT akstdlibTargets
|
2026-05-10 00:00:31 -04:00
|
|
|
FILE akstdlibTargets.cmake
|
|
|
|
|
NAMESPACE akstdlib::
|
|
|
|
|
DESTINATION ${akstdlib_install_cmakedir}
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
configure_package_config_file(
|
|
|
|
|
cmake/akstdlib.cmake.in
|
|
|
|
|
"${CMAKE_CURRENT_BINARY_DIR}/akstdlibConfig.cmake"
|
|
|
|
|
INSTALL_DESTINATION ${akstdlib_install_cmakedir}
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
install(FILES
|
|
|
|
|
"${CMAKE_CURRENT_BINARY_DIR}/akstdlibConfig.cmake"
|
|
|
|
|
DESTINATION ${akstdlib_install_cmakedir}
|
|
|
|
|
)
|
|
|
|
|
|
Build a real test harness (TODO.md section 1.0)
The suite could not fail and did not run. test_linkedlist.c asserted nothing
at all -- it printed node names and returned 0 -- so every confirmed list
defect passed it. test_tree.c was red on every run because parms.steps was
never reset between its three searches, and four libakerror tests registered
but never built, reporting Not Run. CI, meanwhile, was not fetching the
submodule, so configure failed before reaching any of it.
- tests/aksl_capture.h: AKSL_CHECK (NDEBUG-proof), AKSL_CHECK_STATUS/_OK to
run an akerror-returning call, assert its status and release the context,
a capturing akerr_log_method, aksl_slots_in_use(), and an AKSL_RUN driver
that fails any test leaking an error-pool slot.
- test_linkedlist.c: rewritten as 15 assertion cases over the append,
iterate and pop behaviour that is correct today.
- test_tree.c: each search builds its own tree and params.
- Registration driven by AKSL_TESTS, plus AKSL_WILL_FAIL_TESTS (aborts by
design) and AKSL_KNOWN_FAILING_TESTS, which marks WILL_FAIL the three new
tests asserting correct behaviour for the confirmed defects in TODO.md
2.1.1-2.1.3. Fixing a defect flips its test to "unexpectedly passed",
which is the cue to promote it into AKSL_TESTS.
- add_test/set_tests_properties are shadowed across the libakerror
add_subdirectory call: CMake cannot un-register a test and
set_tests_properties cannot cross directory scopes. The dependency has
its own CI.
- AKSL_SANITIZE=ON builds library, tests and dependency with ASan+UBSan.
- scripts/mutation_test.py ported and retargeted at src/stdlib.c; wired to
a manual `mutation` target, not a CI gate until 1.1-1.9 exist.
- CI: checkout with submodules: recursive, and ctest --output-on-failure.
ctest is now 5/5 green in both the default and sanitizer builds.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-28 12:39:54 -04:00
|
|
|
# Each test is one source file tests/test_<name>.c, built into the executable
|
|
|
|
|
# test_<name> and registered as the CTest test <name>. Shared helpers live in
|
|
|
|
|
# tests/aksl_capture.h.
|
|
|
|
|
#
|
|
|
|
|
# AKSL_TESTS must exit 0.
|
|
|
|
|
# AKSL_WILL_FAIL_TESTS expected to abort by design (an unhandled error
|
|
|
|
|
# reaching FINISH_NORETURN, a deliberate contract
|
|
|
|
|
# violation), so a non-zero exit is a pass.
|
|
|
|
|
# AKSL_KNOWN_FAILING_TESTS assert the *correct* behaviour of a confirmed
|
|
|
|
|
# defect from TODO.md section 2.1. They fail until
|
|
|
|
|
# the defect is fixed, and are marked WILL_FAIL so
|
|
|
|
|
# the suite stays green and the gap stays visible.
|
|
|
|
|
# When one is fixed CTest reports it as failed with
|
|
|
|
|
# "unexpectedly passed" -- that is the cue to move
|
|
|
|
|
# it up into AKSL_TESTS.
|
|
|
|
|
set(AKSL_TESTS
|
|
|
|
|
linkedlist
|
|
|
|
|
tree
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
set(AKSL_WILL_FAIL_TESTS
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
set(AKSL_KNOWN_FAILING_TESTS
|
|
|
|
|
list_append_chain # TODO.md 2.1.1 -- append truncates lists of 2+ nodes
|
|
|
|
|
list_iterate_head # TODO.md 2.1.2 -- iterate starts at the midpoint
|
|
|
|
|
tree_iterate_break # TODO.md 2.1.3 -- ITERATOR_BREAK does not stop a walk
|
|
|
|
|
)
|
2026-06-02 12:42:21 -04:00
|
|
|
|
Build a real test harness (TODO.md section 1.0)
The suite could not fail and did not run. test_linkedlist.c asserted nothing
at all -- it printed node names and returned 0 -- so every confirmed list
defect passed it. test_tree.c was red on every run because parms.steps was
never reset between its three searches, and four libakerror tests registered
but never built, reporting Not Run. CI, meanwhile, was not fetching the
submodule, so configure failed before reaching any of it.
- tests/aksl_capture.h: AKSL_CHECK (NDEBUG-proof), AKSL_CHECK_STATUS/_OK to
run an akerror-returning call, assert its status and release the context,
a capturing akerr_log_method, aksl_slots_in_use(), and an AKSL_RUN driver
that fails any test leaking an error-pool slot.
- test_linkedlist.c: rewritten as 15 assertion cases over the append,
iterate and pop behaviour that is correct today.
- test_tree.c: each search builds its own tree and params.
- Registration driven by AKSL_TESTS, plus AKSL_WILL_FAIL_TESTS (aborts by
design) and AKSL_KNOWN_FAILING_TESTS, which marks WILL_FAIL the three new
tests asserting correct behaviour for the confirmed defects in TODO.md
2.1.1-2.1.3. Fixing a defect flips its test to "unexpectedly passed",
which is the cue to promote it into AKSL_TESTS.
- add_test/set_tests_properties are shadowed across the libakerror
add_subdirectory call: CMake cannot un-register a test and
set_tests_properties cannot cross directory scopes. The dependency has
its own CI.
- AKSL_SANITIZE=ON builds library, tests and dependency with ASan+UBSan.
- scripts/mutation_test.py ported and retargeted at src/stdlib.c; wired to
a manual `mutation` target, not a CI gate until 1.1-1.9 exist.
- CI: checkout with submodules: recursive, and ctest --output-on-failure.
ctest is now 5/5 green in both the default and sanitizer builds.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-28 12:39:54 -04:00
|
|
|
foreach(_test IN LISTS AKSL_TESTS AKSL_WILL_FAIL_TESTS AKSL_KNOWN_FAILING_TESTS)
|
|
|
|
|
add_executable(test_${_test} tests/test_${_test}.c)
|
|
|
|
|
target_include_directories(test_${_test} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/tests)
|
|
|
|
|
target_link_libraries(test_${_test} PRIVATE akstdlib)
|
|
|
|
|
add_test(NAME ${_test} COMMAND test_${_test})
|
|
|
|
|
endforeach()
|
|
|
|
|
|
|
|
|
|
if(AKSL_WILL_FAIL_TESTS OR AKSL_KNOWN_FAILING_TESTS)
|
|
|
|
|
set_tests_properties(
|
|
|
|
|
${AKSL_WILL_FAIL_TESTS} ${AKSL_KNOWN_FAILING_TESTS}
|
|
|
|
|
PROPERTIES WILL_FAIL TRUE
|
|
|
|
|
)
|
|
|
|
|
endif()
|
|
|
|
|
|
Add mutation testing to the Gitea workflow
A separate mutation_test job runs scripts/mutation_test.py over src/stdlib.c
with a --threshold gate and publishes a JUnit report, mirroring libakerror's
CI. Checkout needs submodules: recursive -- the harness copies the repo and
builds the copy top-level, so deps/libakerror has to be there.
Measured score on the section 1.0 suite is 46.8% (81/173 killed). The gate is
set at 40: a regression ratchet, not a quality bar. Survivors cluster in the
wrappers that have no tests yet (printf family, ato* family, realpath, the
memory and stream wrappers); the list and tree code that section 1.0 does
cover leaves only 5 survivors between them.
Also caps every test with TIMEOUT 30. Measuring the score turned this up: a
mutant deleting `fast = fast->next->next` makes aksl_list_iterate spin
forever, so ctest never returned, the harness killed ctest at its own 120s
timeout, and the orphaned test binary kept burning a core while holding the
pipe open -- the run wedged and needed killing by hand. With a per-test
timeout ctest reaps its own child, those mutants are killed in 30s, and
nothing is left behind. It guards the real suite against the same shape of
bug too.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-29 10:35:46 -04:00
|
|
|
# Cap every test. The list and tree code is full of loops whose termination
|
|
|
|
|
# depends on a single condition, so a plausible bug -- or a mutant from the
|
|
|
|
|
# target below -- turns a test into an infinite loop. Without this, ctest waits
|
|
|
|
|
# forever; the mutation harness then kills ctest at its own timeout and the
|
|
|
|
|
# spinning test binary is left orphaned, holding the pipe open and burning a
|
|
|
|
|
# core. The whole suite runs in well under a second, so 30s is pure headroom.
|
|
|
|
|
set_tests_properties(
|
|
|
|
|
${AKSL_TESTS} ${AKSL_WILL_FAIL_TESTS} ${AKSL_KNOWN_FAILING_TESTS}
|
|
|
|
|
PROPERTIES TIMEOUT 30
|
|
|
|
|
)
|
|
|
|
|
|
Build a real test harness (TODO.md section 1.0)
The suite could not fail and did not run. test_linkedlist.c asserted nothing
at all -- it printed node names and returned 0 -- so every confirmed list
defect passed it. test_tree.c was red on every run because parms.steps was
never reset between its three searches, and four libakerror tests registered
but never built, reporting Not Run. CI, meanwhile, was not fetching the
submodule, so configure failed before reaching any of it.
- tests/aksl_capture.h: AKSL_CHECK (NDEBUG-proof), AKSL_CHECK_STATUS/_OK to
run an akerror-returning call, assert its status and release the context,
a capturing akerr_log_method, aksl_slots_in_use(), and an AKSL_RUN driver
that fails any test leaking an error-pool slot.
- test_linkedlist.c: rewritten as 15 assertion cases over the append,
iterate and pop behaviour that is correct today.
- test_tree.c: each search builds its own tree and params.
- Registration driven by AKSL_TESTS, plus AKSL_WILL_FAIL_TESTS (aborts by
design) and AKSL_KNOWN_FAILING_TESTS, which marks WILL_FAIL the three new
tests asserting correct behaviour for the confirmed defects in TODO.md
2.1.1-2.1.3. Fixing a defect flips its test to "unexpectedly passed",
which is the cue to promote it into AKSL_TESTS.
- add_test/set_tests_properties are shadowed across the libakerror
add_subdirectory call: CMake cannot un-register a test and
set_tests_properties cannot cross directory scopes. The dependency has
its own CI.
- AKSL_SANITIZE=ON builds library, tests and dependency with ASan+UBSan.
- scripts/mutation_test.py ported and retargeted at src/stdlib.c; wired to
a manual `mutation` target, not a CI gate until 1.1-1.9 exist.
- CI: checkout with submodules: recursive, and ctest --output-on-failure.
ctest is now 5/5 green in both the default and sanitizer builds.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-28 12:39:54 -04:00
|
|
|
# Mutation testing: break the library in small ways and confirm the test suite
|
Add mutation testing to the Gitea workflow
A separate mutation_test job runs scripts/mutation_test.py over src/stdlib.c
with a --threshold gate and publishes a JUnit report, mirroring libakerror's
CI. Checkout needs submodules: recursive -- the harness copies the repo and
builds the copy top-level, so deps/libakerror has to be there.
Measured score on the section 1.0 suite is 46.8% (81/173 killed). The gate is
set at 40: a regression ratchet, not a quality bar. Survivors cluster in the
wrappers that have no tests yet (printf family, ato* family, realpath, the
memory and stream wrappers); the list and tree code that section 1.0 does
cover leaves only 5 survivors between them.
Also caps every test with TIMEOUT 30. Measuring the score turned this up: a
mutant deleting `fast = fast->next->next` makes aksl_list_iterate spin
forever, so ctest never returned, the harness killed ctest at its own 120s
timeout, and the orphaned test binary kept burning a core while holding the
pipe open -- the run wedged and needed killing by hand. With a per-test
timeout ctest reaps its own child, those mutants are killed in 30s, and
nothing is left behind. It guards the real suite against the same shape of
bug too.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-29 10:35:46 -04:00
|
|
|
# notices. This is a meta-check on the tests themselves, and it rebuilds and
|
|
|
|
|
# re-runs the whole suite once per mutant, so it is a manual target rather than
|
|
|
|
|
# a CTest test:
|
Build a real test harness (TODO.md section 1.0)
The suite could not fail and did not run. test_linkedlist.c asserted nothing
at all -- it printed node names and returned 0 -- so every confirmed list
defect passed it. test_tree.c was red on every run because parms.steps was
never reset between its three searches, and four libakerror tests registered
but never built, reporting Not Run. CI, meanwhile, was not fetching the
submodule, so configure failed before reaching any of it.
- tests/aksl_capture.h: AKSL_CHECK (NDEBUG-proof), AKSL_CHECK_STATUS/_OK to
run an akerror-returning call, assert its status and release the context,
a capturing akerr_log_method, aksl_slots_in_use(), and an AKSL_RUN driver
that fails any test leaking an error-pool slot.
- test_linkedlist.c: rewritten as 15 assertion cases over the append,
iterate and pop behaviour that is correct today.
- test_tree.c: each search builds its own tree and params.
- Registration driven by AKSL_TESTS, plus AKSL_WILL_FAIL_TESTS (aborts by
design) and AKSL_KNOWN_FAILING_TESTS, which marks WILL_FAIL the three new
tests asserting correct behaviour for the confirmed defects in TODO.md
2.1.1-2.1.3. Fixing a defect flips its test to "unexpectedly passed",
which is the cue to promote it into AKSL_TESTS.
- add_test/set_tests_properties are shadowed across the libakerror
add_subdirectory call: CMake cannot un-register a test and
set_tests_properties cannot cross directory scopes. The dependency has
its own CI.
- AKSL_SANITIZE=ON builds library, tests and dependency with ASan+UBSan.
- scripts/mutation_test.py ported and retargeted at src/stdlib.c; wired to
a manual `mutation` target, not a CI gate until 1.1-1.9 exist.
- CI: checkout with submodules: recursive, and ctest --output-on-failure.
ctest is now 5/5 green in both the default and sanitizer builds.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-28 12:39:54 -04:00
|
|
|
# cmake --build build --target mutation
|
Add mutation testing to the Gitea workflow
A separate mutation_test job runs scripts/mutation_test.py over src/stdlib.c
with a --threshold gate and publishes a JUnit report, mirroring libakerror's
CI. Checkout needs submodules: recursive -- the harness copies the repo and
builds the copy top-level, so deps/libakerror has to be there.
Measured score on the section 1.0 suite is 46.8% (81/173 killed). The gate is
set at 40: a regression ratchet, not a quality bar. Survivors cluster in the
wrappers that have no tests yet (printf family, ato* family, realpath, the
memory and stream wrappers); the list and tree code that section 1.0 does
cover leaves only 5 survivors between them.
Also caps every test with TIMEOUT 30. Measuring the score turned this up: a
mutant deleting `fast = fast->next->next` makes aksl_list_iterate spin
forever, so ctest never returned, the harness killed ctest at its own 120s
timeout, and the orphaned test binary kept burning a core while holding the
pipe open -- the run wedged and needed killing by hand. With a per-test
timeout ctest reaps its own child, those mutants are killed in 30s, and
nothing is left behind. It guards the real suite against the same shape of
bug too.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-29 10:35:46 -04:00
|
|
|
# This target covers both src/stdlib.c and include/akstdlib.h. CI runs the
|
|
|
|
|
# narrower, faster src/stdlib.c set with a --threshold gate; see
|
|
|
|
|
# .gitea/workflows/ci.yaml.
|
Build a real test harness (TODO.md section 1.0)
The suite could not fail and did not run. test_linkedlist.c asserted nothing
at all -- it printed node names and returned 0 -- so every confirmed list
defect passed it. test_tree.c was red on every run because parms.steps was
never reset between its three searches, and four libakerror tests registered
but never built, reporting Not Run. CI, meanwhile, was not fetching the
submodule, so configure failed before reaching any of it.
- tests/aksl_capture.h: AKSL_CHECK (NDEBUG-proof), AKSL_CHECK_STATUS/_OK to
run an akerror-returning call, assert its status and release the context,
a capturing akerr_log_method, aksl_slots_in_use(), and an AKSL_RUN driver
that fails any test leaking an error-pool slot.
- test_linkedlist.c: rewritten as 15 assertion cases over the append,
iterate and pop behaviour that is correct today.
- test_tree.c: each search builds its own tree and params.
- Registration driven by AKSL_TESTS, plus AKSL_WILL_FAIL_TESTS (aborts by
design) and AKSL_KNOWN_FAILING_TESTS, which marks WILL_FAIL the three new
tests asserting correct behaviour for the confirmed defects in TODO.md
2.1.1-2.1.3. Fixing a defect flips its test to "unexpectedly passed",
which is the cue to promote it into AKSL_TESTS.
- add_test/set_tests_properties are shadowed across the libakerror
add_subdirectory call: CMake cannot un-register a test and
set_tests_properties cannot cross directory scopes. The dependency has
its own CI.
- AKSL_SANITIZE=ON builds library, tests and dependency with ASan+UBSan.
- scripts/mutation_test.py ported and retargeted at src/stdlib.c; wired to
a manual `mutation` target, not a CI gate until 1.1-1.9 exist.
- CI: checkout with submodules: recursive, and ctest --output-on-failure.
ctest is now 5/5 green in both the default and sanitizer builds.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-28 12:39:54 -04:00
|
|
|
find_package(Python3 COMPONENTS Interpreter)
|
|
|
|
|
if(Python3_FOUND)
|
|
|
|
|
add_custom_target(mutation
|
|
|
|
|
COMMAND ${Python3_EXECUTABLE}
|
|
|
|
|
${CMAKE_CURRENT_SOURCE_DIR}/scripts/mutation_test.py
|
|
|
|
|
--source-root ${CMAKE_CURRENT_SOURCE_DIR}
|
|
|
|
|
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
|
|
|
|
|
USES_TERMINAL
|
|
|
|
|
COMMENT "Running mutation tests (breaks the library, expects tests to fail)"
|
|
|
|
|
)
|
|
|
|
|
endif()
|
2026-06-27 13:13:17 -04:00
|
|
|
|
2026-06-02 12:42:21 -04:00
|
|
|
|
2026-05-10 00:00:31 -04:00
|
|
|
# pkgconfig
|