90 lines
2.7 KiB
C
90 lines
2.7 KiB
C
|
|
/*
|
||
|
|
* 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);
|
||
|
|
}
|