Add mutation testing to validate the test suite
Introduce a self-contained mutation testing harness that verifies the unit tests actually catch bugs: it makes small deliberate breakages to the library (flip comparisons, delete statements, swap true/false, etc.), rebuilds, and runs the whole CTest suite against each mutant. Tests that still pass reveal a gap; tests that fail "kill" the mutant. - scripts/mutation_test.py: the engine (stdlib only, no LLVM/clang deps). Operators ROR/LCR/BCR/AOR/ICR/SDL over src/error.c and the macro header. Mutates a scratch copy, never the working tree. Supports --target, --list, --max-mutants sampling, --threshold gating, --timeout. - CMakeLists.txt: 'mutation' custom target (cmake --build build --target mutation). - .gitea/workflows/ci.yaml: gated mutation job on src/error.c (threshold 65%). - tests/MUTATION.md: how to run, interpret survivors, and known equivalents. Close the real gaps the harness found in src/error.c (score 53% -> 71%): - err_error_names: the AKERR_* codes have their names registered by akerr_init - err_release_clears: releasing a context wipes it before reuse - err_pool_exhaust: akerr_next_error returns NULL when the pool is full and always hands back the lowest free slot Also surfaced (documented, not fixed): AKERR_MAX_ERR_VALUE (+15) is below AKERR_NOT_IMPLEMENTED (+16) and AKERR_BADEXC (+17), so those codes can never have a name registered. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
39
tests/err_pool_exhaust.c
Normal file
39
tests/err_pool_exhaust.c
Normal file
@@ -0,0 +1,39 @@
|
||||
#include "akerror.h"
|
||||
#include "err_capture.h"
|
||||
|
||||
/*
|
||||
* The error pool is a fixed array of AKERR_MAX_ARRAY_ERROR slots. When every
|
||||
* slot is checked out, akerr_next_error() must return NULL rather than run off
|
||||
* the end of the array; and it must always hand back the lowest free slot.
|
||||
* Mutation testing showed both the terminating "return NULL" and the scan
|
||||
* bounds could be broken without any test noticing.
|
||||
*/
|
||||
|
||||
int main(void)
|
||||
{
|
||||
akerr_init();
|
||||
|
||||
akerr_ErrorContext *slots[AKERR_MAX_ARRAY_ERROR];
|
||||
|
||||
/* Check out every slot. */
|
||||
for ( int i = 0; i < AKERR_MAX_ARRAY_ERROR; i++ ) {
|
||||
slots[i] = akerr_next_error();
|
||||
AKERR_CHECK(slots[i] != NULL);
|
||||
slots[i]->refcount = 1;
|
||||
}
|
||||
|
||||
/* Pool is fully exhausted: the next request must fail cleanly. */
|
||||
AKERR_CHECK(akerr_next_error() == NULL);
|
||||
|
||||
/* Free exactly the first slot; the scan must find and return it. */
|
||||
slots[0]->refcount = 0;
|
||||
AKERR_CHECK(akerr_next_error() == slots[0]);
|
||||
|
||||
/* Tidy up. */
|
||||
for ( int i = 0; i < AKERR_MAX_ARRAY_ERROR; i++ ) {
|
||||
slots[i]->refcount = 0;
|
||||
}
|
||||
|
||||
fprintf(stderr, "err_pool_exhaust ok\n");
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user