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
|
|
|
/*
|
|
|
|
|
* Depth-first tree search.
|
|
|
|
|
*
|
|
|
|
|
* Previously this test shared one TreeSearchParams across all three searches
|
|
|
|
|
* without resetting it, so `steps` accumulated (7, then 14, then 21) and the
|
|
|
|
|
* second assertion failed -- `tree` was a red test on every run. Each search
|
|
|
|
|
* now gets its own params.
|
|
|
|
|
*
|
|
|
|
|
* Caveat worth knowing when reading the step counts below: the value is hidden
|
|
|
|
|
* in tree[6], which is the last node visited in pre-, in- and post-order alike,
|
|
|
|
|
* so "7 steps" holds for all three orders and does not actually distinguish
|
|
|
|
|
* them -- nor does it prove that AKERR_ITERATOR_BREAK stopped anything (it does
|
|
|
|
|
* not; see tests/test_tree_iterate_break.c and TODO.md 2.1.3). Visit-order
|
|
|
|
|
* assertions that tell the three traversals apart are TODO.md section 1.8.
|
|
|
|
|
*/
|
2026-06-27 13:13:17 -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
|
|
|
#include "aksl_capture.h"
|
|
|
|
|
|
|
|
|
|
#define MAX_LEAVES 7
|
|
|
|
|
#define HIDDEN_VALUE ((void *)17336)
|
2026-06-27 13:13:17 -04:00
|
|
|
|
|
|
|
|
typedef struct TreeSearchParams
|
|
|
|
|
{
|
|
|
|
|
void *value;
|
|
|
|
|
int steps;
|
|
|
|
|
aksl_TreeNode *node;
|
|
|
|
|
} TreeSearchParams;
|
|
|
|
|
|
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
|
|
|
static akerr_ErrorContext AKERR_NOIGNORE *find_value(aksl_TreeNode *node, void *data)
|
2026-06-27 13:13:17 -04:00
|
|
|
{
|
|
|
|
|
TreeSearchParams *parms = NULL;
|
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
|
|
|
|
2026-06-27 13:13:17 -04:00
|
|
|
PREPARE_ERROR(e);
|
|
|
|
|
FAIL_ZERO_RETURN(e, node, AKERR_NULLPOINTER, "node");
|
|
|
|
|
FAIL_ZERO_RETURN(e, data, AKERR_NULLPOINTER, "data");
|
|
|
|
|
parms = (TreeSearchParams *)data;
|
|
|
|
|
parms->steps += 1;
|
|
|
|
|
if ( node->leaf == parms->value ) {
|
|
|
|
|
parms->node = node;
|
|
|
|
|
FAIL_RETURN(e, AKERR_ITERATOR_BREAK, "stop");
|
|
|
|
|
}
|
|
|
|
|
SUCCEED_RETURN(e);
|
|
|
|
|
}
|
|
|
|
|
|
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
|
|
|
/*
|
|
|
|
|
* Build the 3-level tree used by every case here, with the search value hidden
|
|
|
|
|
* in the bottom-right leaf.
|
|
|
|
|
*
|
|
|
|
|
* LEFT RIGHT
|
|
|
|
|
* TREE[0]
|
|
|
|
|
* +--------^^---------+
|
|
|
|
|
* | |
|
|
|
|
|
* TREE[1] TREE[2]
|
|
|
|
|
* +---^^---+ +---^^---+
|
|
|
|
|
* | | | |
|
|
|
|
|
*TREE[3] TREE[4] TREE[5] TREE[6]
|
|
|
|
|
*/
|
|
|
|
|
static void build_tree(aksl_TreeNode *tree, TreeSearchParams *parms)
|
|
|
|
|
{
|
|
|
|
|
memset((void *)tree, 0x00, sizeof(aksl_TreeNode) * MAX_LEAVES);
|
|
|
|
|
tree[0].left = &tree[1];
|
|
|
|
|
tree[0].right = &tree[2];
|
|
|
|
|
tree[1].left = &tree[3];
|
|
|
|
|
tree[1].right = &tree[4];
|
|
|
|
|
tree[2].left = &tree[5];
|
|
|
|
|
tree[2].right = &tree[6];
|
|
|
|
|
tree[6].leaf = HIDDEN_VALUE;
|
|
|
|
|
|
|
|
|
|
memset((void *)parms, 0x00, sizeof(TreeSearchParams));
|
|
|
|
|
parms->value = HIDDEN_VALUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int search_finds_hidden_value(uint8_t searchmode)
|
|
|
|
|
{
|
|
|
|
|
aksl_TreeNode tree[MAX_LEAVES];
|
|
|
|
|
TreeSearchParams parms;
|
|
|
|
|
|
|
|
|
|
build_tree(tree, &parms);
|
|
|
|
|
|
|
|
|
|
AKSL_CHECK_OK(aksl_tree_iterate(&tree[0], &find_value, NULL, NULL,
|
|
|
|
|
searchmode, &parms, NULL));
|
|
|
|
|
AKSL_CHECK(parms.node == &tree[6]);
|
|
|
|
|
AKSL_CHECK(parms.steps == MAX_LEAVES);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int test_dfs_preorder(void)
|
|
|
|
|
{
|
|
|
|
|
return search_finds_hidden_value(AKSL_TREE_SEARCH_DFS_PREORDER);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int test_dfs_inorder(void)
|
|
|
|
|
{
|
|
|
|
|
return search_finds_hidden_value(AKSL_TREE_SEARCH_DFS_INORDER);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int test_dfs_postorder(void)
|
|
|
|
|
{
|
|
|
|
|
return search_finds_hidden_value(AKSL_TREE_SEARCH_DFS_POSTORDER);
|
|
|
|
|
}
|
|
|
|
|
|
Test the libc wrappers: 52% -> 99% line coverage
Every wrapper outside the list and tree code was untested. Six new test
files close that, following the plan already written in TODO.md 1.2-1.6:
test_stream.c fopen/fread/fwrite/fclose -- happy paths, the round
trip, AKERR_EOF on a short read, AKERR_IO on a stream
opened in the wrong mode, ENOENT, and the NULL guards
test_format.c printf/fprintf/sprintf -- text *and* count asserted
(stdout is pointed at a temp file to check aksl_printf),
all eight NULL guards, EBADF on a read-only stream, and
512 variadic calls in a loop as sanitizer cover for the
missing va_end
test_convert.c ato{i,l,ll,f} happy paths, negatives, leading
whitespace, NULL guards
test_path.c realpath on a file and on a symlink, both compared
against realpath(3) since TMPDIR may itself be a link;
ENOENT, ENOTDIR, NULL path
test_strhash.c djb2 known-answer vectors, len == 0, embedded NUL,
stability, NULL guards
test_convert_strict.c
known-failing (2.1.5): the AKERR_VALUE / ERANGE
contract the ato* family cannot express today
test_tree.c gains the BFS AKERR_NOT_IMPLEMENTED contract, NULL arguments,
and a callback error that is not AKERR_ITERATOR_BREAK propagating out.
Tests deliberately say nothing about behaviour TODO.md records as
defective -- unchecked ptr/mode/resolved_path, short transfers reported as
success, *count left at -1, the djb2 sign extension -- so the eventual fix
does not have to come with a test rewrite. Each failure case in
test_path.c passes a zeroed buffer, because the wrapper's own error path
formats resolved_path with %s (2.1.6).
aksl_capture.h gains aksl_temp_file() with an atexit unlink backstop.
Without it every test that fails before its own unlink leaves temp files
behind -- which is the normal case for a known-failing test, and happens
173 times over in a mutation run.
Coverage on src/stdlib.c: 52.0% -> 99.0% of lines (200/202), 23.6% ->
51.0% of branches, 8/21 -> 21/21 functions. The two uncovered lines are
both `} HANDLE(e, AKERR_ITERATOR_BREAK) {`, where the macro starts with
the `break;` of PROCESS's `case 0:` arm -- reachable only via a non-NULL
error context whose status is zero, the pathology 2.2.1 exists to remove.
Mutation score on src/stdlib.c: 46.8% -> 89.6% (155/173 killed). CI, the
pre-push hook and the docs ratchet from 40 to 80 accordingly, and the 18
survivors are grouped by cause in TODO.md and README.md. A new CI
coverage job gates at 90% lines / 45% branches.
Verified:
ctest --test-dir build # 12/12
ctest --test-dir build-asan # 12/12 under ASan + UBSan
ctest --test-dir build-coverage # 14/14, report attached
ctest --test-dir build -j8 --repeat until-fail:3
gcc -Wall -Wextra -c on all nine test files # no warnings
python3 scripts/mutation_test.py --target src/stdlib.c # 89.6%
No temp files left in /tmp after any of the above.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-30 02:07:08 -04:00
|
|
|
/*
|
|
|
|
|
* Both breadth-first modes are declared in the header but not implemented, and
|
|
|
|
|
* say so through AKERR_NOT_IMPLEMENTED rather than by silently visiting nothing.
|
|
|
|
|
* TODO.md 2.2.10 tracks implementing them; until then this is the contract.
|
|
|
|
|
*/
|
|
|
|
|
static int bfs_reports_not_implemented(uint8_t searchmode)
|
|
|
|
|
{
|
|
|
|
|
aksl_TreeNode tree[MAX_LEAVES];
|
|
|
|
|
TreeSearchParams parms;
|
|
|
|
|
|
|
|
|
|
build_tree(tree, &parms);
|
|
|
|
|
|
|
|
|
|
AKSL_CHECK_STATUS_MSG_CONTAINS(
|
|
|
|
|
aksl_tree_iterate(&tree[0], &find_value, NULL, NULL, searchmode,
|
|
|
|
|
&parms, NULL),
|
|
|
|
|
AKERR_NOT_IMPLEMENTED, "Searchmode");
|
|
|
|
|
AKSL_CHECK(parms.steps == 0);
|
|
|
|
|
AKSL_CHECK(parms.node == NULL);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int test_bfs_is_not_implemented(void)
|
|
|
|
|
{
|
|
|
|
|
return bfs_reports_not_implemented(AKSL_TREE_SEARCH_BFS);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int test_bfs_right_is_not_implemented(void)
|
|
|
|
|
{
|
|
|
|
|
return bfs_reports_not_implemented(AKSL_TREE_SEARCH_BFS_RIGHT);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int test_iterate_null_arguments(void)
|
|
|
|
|
{
|
|
|
|
|
aksl_TreeNode tree[MAX_LEAVES];
|
|
|
|
|
TreeSearchParams parms;
|
|
|
|
|
|
|
|
|
|
build_tree(tree, &parms);
|
|
|
|
|
|
|
|
|
|
AKSL_CHECK_STATUS_MSG_CONTAINS(
|
|
|
|
|
aksl_tree_iterate(NULL, &find_value, NULL, NULL,
|
|
|
|
|
AKSL_TREE_SEARCH_DFS_PREORDER, &parms, NULL),
|
|
|
|
|
AKERR_NULLPOINTER, "root");
|
|
|
|
|
AKSL_CHECK_STATUS_MSG_CONTAINS(
|
|
|
|
|
aksl_tree_iterate(&tree[0], NULL, NULL, NULL,
|
|
|
|
|
AKSL_TREE_SEARCH_DFS_PREORDER, &parms, NULL),
|
|
|
|
|
AKERR_NULLPOINTER, "iter");
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* A callback error that is not AKERR_ITERATOR_BREAK reaches the caller. */
|
|
|
|
|
static int test_iterate_propagates_callback_error(void)
|
|
|
|
|
{
|
|
|
|
|
aksl_TreeNode tree[MAX_LEAVES];
|
|
|
|
|
TreeSearchParams parms;
|
|
|
|
|
|
|
|
|
|
build_tree(tree, &parms);
|
|
|
|
|
/* find_value raises AKERR_NULLPOINTER when it is handed no data. */
|
|
|
|
|
AKSL_CHECK_STATUS_MSG_CONTAINS(
|
|
|
|
|
aksl_tree_iterate(&tree[0], &find_value, NULL, NULL,
|
|
|
|
|
AKSL_TREE_SEARCH_DFS_PREORDER, NULL, NULL),
|
|
|
|
|
AKERR_NULLPOINTER, "data");
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2026-06-27 13:13:17 -04:00
|
|
|
int main(void)
|
|
|
|
|
{
|
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
|
|
|
int failures = 0;
|
|
|
|
|
|
|
|
|
|
akerr_init();
|
|
|
|
|
|
|
|
|
|
AKSL_RUN(failures, test_dfs_preorder);
|
|
|
|
|
AKSL_RUN(failures, test_dfs_inorder);
|
|
|
|
|
AKSL_RUN(failures, test_dfs_postorder);
|
|
|
|
|
|
Test the libc wrappers: 52% -> 99% line coverage
Every wrapper outside the list and tree code was untested. Six new test
files close that, following the plan already written in TODO.md 1.2-1.6:
test_stream.c fopen/fread/fwrite/fclose -- happy paths, the round
trip, AKERR_EOF on a short read, AKERR_IO on a stream
opened in the wrong mode, ENOENT, and the NULL guards
test_format.c printf/fprintf/sprintf -- text *and* count asserted
(stdout is pointed at a temp file to check aksl_printf),
all eight NULL guards, EBADF on a read-only stream, and
512 variadic calls in a loop as sanitizer cover for the
missing va_end
test_convert.c ato{i,l,ll,f} happy paths, negatives, leading
whitespace, NULL guards
test_path.c realpath on a file and on a symlink, both compared
against realpath(3) since TMPDIR may itself be a link;
ENOENT, ENOTDIR, NULL path
test_strhash.c djb2 known-answer vectors, len == 0, embedded NUL,
stability, NULL guards
test_convert_strict.c
known-failing (2.1.5): the AKERR_VALUE / ERANGE
contract the ato* family cannot express today
test_tree.c gains the BFS AKERR_NOT_IMPLEMENTED contract, NULL arguments,
and a callback error that is not AKERR_ITERATOR_BREAK propagating out.
Tests deliberately say nothing about behaviour TODO.md records as
defective -- unchecked ptr/mode/resolved_path, short transfers reported as
success, *count left at -1, the djb2 sign extension -- so the eventual fix
does not have to come with a test rewrite. Each failure case in
test_path.c passes a zeroed buffer, because the wrapper's own error path
formats resolved_path with %s (2.1.6).
aksl_capture.h gains aksl_temp_file() with an atexit unlink backstop.
Without it every test that fails before its own unlink leaves temp files
behind -- which is the normal case for a known-failing test, and happens
173 times over in a mutation run.
Coverage on src/stdlib.c: 52.0% -> 99.0% of lines (200/202), 23.6% ->
51.0% of branches, 8/21 -> 21/21 functions. The two uncovered lines are
both `} HANDLE(e, AKERR_ITERATOR_BREAK) {`, where the macro starts with
the `break;` of PROCESS's `case 0:` arm -- reachable only via a non-NULL
error context whose status is zero, the pathology 2.2.1 exists to remove.
Mutation score on src/stdlib.c: 46.8% -> 89.6% (155/173 killed). CI, the
pre-push hook and the docs ratchet from 40 to 80 accordingly, and the 18
survivors are grouped by cause in TODO.md and README.md. A new CI
coverage job gates at 90% lines / 45% branches.
Verified:
ctest --test-dir build # 12/12
ctest --test-dir build-asan # 12/12 under ASan + UBSan
ctest --test-dir build-coverage # 14/14, report attached
ctest --test-dir build -j8 --repeat until-fail:3
gcc -Wall -Wextra -c on all nine test files # no warnings
python3 scripts/mutation_test.py --target src/stdlib.c # 89.6%
No temp files left in /tmp after any of the above.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-30 02:07:08 -04:00
|
|
|
AKSL_RUN(failures, test_bfs_is_not_implemented);
|
|
|
|
|
AKSL_RUN(failures, test_bfs_right_is_not_implemented);
|
|
|
|
|
AKSL_RUN(failures, test_iterate_null_arguments);
|
|
|
|
|
AKSL_RUN(failures, test_iterate_propagates_callback_error);
|
|
|
|
|
|
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
|
|
|
AKSL_REPORT(failures);
|
2026-06-27 13:13:17 -04:00
|
|
|
}
|