/* * 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); }