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>
This commit is contained in:
89
tests/test_tree_iterate_break.c
Normal file
89
tests/test_tree_iterate_break.c
Normal file
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
* KNOWN FAILING -- TODO.md section 2.1.3
|
||||
*
|
||||
* AKERR_ITERATOR_BREAK does not abort a tree traversal. aksl_tree_iterate
|
||||
* recurses into itself, and the frame in which the callback raises the break
|
||||
* handles it in its own PROCESS/HANDLE(e, AKERR_ITERATOR_BREAK) block and
|
||||
* returns *success*. The parent frame's PASS therefore sees no error at all and
|
||||
* carries straight on into the sibling subtree, so the traversal runs to
|
||||
* completion.
|
||||
*
|
||||
* The 7-node tree below is walked pre-order (0, 1, 3, 4, 2, 5, 6) with the
|
||||
* callback breaking on tree[3], the third node visited. A working break stops
|
||||
* the walk at 3 visits; today the callback is invoked all 7 times.
|
||||
*
|
||||
* tests/test_tree.c cannot catch this: it hides its value in tree[6], which is
|
||||
* the last node visited in all three depth-first orders, so a break that never
|
||||
* fires is indistinguishable from one that fires on the final node.
|
||||
*
|
||||
* Registered in AKSL_KNOWN_FAILING_TESTS (WILL_FAIL). When the break semantics
|
||||
* are fixed, CTest reports this as unexpectedly passing -- move it into
|
||||
* AKSL_TESTS then.
|
||||
*/
|
||||
|
||||
#include "aksl_capture.h"
|
||||
|
||||
#define MAX_LEAVES 7
|
||||
|
||||
typedef struct BreakParams
|
||||
{
|
||||
aksl_TreeNode *stop_at;
|
||||
int visits;
|
||||
} BreakParams;
|
||||
|
||||
static akerr_ErrorContext AKERR_NOIGNORE *break_at_node(aksl_TreeNode *node, void *data)
|
||||
{
|
||||
BreakParams *parms = NULL;
|
||||
|
||||
PREPARE_ERROR(e);
|
||||
FAIL_ZERO_RETURN(e, node, AKERR_NULLPOINTER, "node");
|
||||
FAIL_ZERO_RETURN(e, data, AKERR_NULLPOINTER, "data");
|
||||
parms = (BreakParams *)data;
|
||||
parms->visits += 1;
|
||||
if ( node == parms->stop_at ) {
|
||||
FAIL_RETURN(e, AKERR_ITERATOR_BREAK, "stop");
|
||||
}
|
||||
SUCCEED_RETURN(e);
|
||||
}
|
||||
|
||||
static int test_break_aborts_the_whole_traversal(void)
|
||||
{
|
||||
aksl_TreeNode tree[MAX_LEAVES];
|
||||
BreakParams parms;
|
||||
|
||||
memset((void *)tree, 0x00, sizeof(tree));
|
||||
memset((void *)&parms, 0x00, sizeof(parms));
|
||||
|
||||
/*
|
||||
* TREE[0]
|
||||
* +--------^^---------+
|
||||
* | |
|
||||
* TREE[1] TREE[2]
|
||||
* +---^^---+ +---^^---+
|
||||
* | | | |
|
||||
*TREE[3] TREE[4] TREE[5] TREE[6]
|
||||
*/
|
||||
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];
|
||||
|
||||
parms.stop_at = &tree[3];
|
||||
|
||||
AKSL_CHECK_OK(aksl_tree_iterate(&tree[0], &break_at_node, NULL, NULL,
|
||||
AKSL_TREE_SEARCH_DFS_PREORDER, &parms, NULL));
|
||||
/* Pre-order visits 0, 1, 3 -- the break on tree[3] must stop the walk there. */
|
||||
AKSL_CHECK(parms.visits == 3);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
int failures = 0;
|
||||
|
||||
akerr_init();
|
||||
AKSL_RUN(failures, test_break_aborts_the_whole_traversal);
|
||||
AKSL_REPORT(failures);
|
||||
}
|
||||
Reference in New Issue
Block a user