Code sample
START_TEST(test_START_EMPTY_TREE_TREEBASE_PRINT_FREETREE_TEST) {
printf("_________START_EMPTY_TREE/TREEBASE_PRINT/FREETREE_TEST__________\n");
fflush(stdout);
int *ptr;
for (int i = 0; i < arr_size; i++) {
ptr = malloc(sizeof(int));
memcpy(ptr, (int_arr_ptr + i), sizeof(int));
insert(ptr_tree_base_int_1, ptr);
}
// should print tree
printf("!!!Next lines has to be tree printed out\n");
fflush(stdout);
ck_assert_int_eq(printTree(ptr_tree_base_int_1), true);
printf("_____________________\n");
fflush(stdout);
// No output
ck_assert_int_eq(freeTree(ptr_tree_base_int_1), true);
// should print cannot free empty tree
printf("!!!Next line has to be:\"cannot free empty tree\"\n");
fflush(stdout);
ck_assert_int_eq(freeTree(ptr_tree_base_int_1), true);
// should print cannot print empty tree
printf("!!!Next line has to be:\"cannot print empty tree\"\n");
fflush(stdout);
ck_assert_int_eq(printTree(ptr_tree_base_int_1), false);
printf("_____________________\n");
fflush(stdout);
ptr_tree_base_int_1 = NULL;
free(ptr_tree_base_int_1);
// should print cannot free empty tree base
printf("!!!Next line has to be:\"cannot free empty tree base\"\n");
fflush(stdout);
ck_assert_int_eq(freeTree(ptr_tree_base_int_1), true);
// should print cannot print empty tree base
printf("!!!Next line has to be:\"cannot print empty tree base\"\n");
fflush(stdout);
ck_assert_int_eq(printTree(ptr_tree_base_int_1), false);
printf("_____________________\n");
fflush(stdout);
free(int_arr_ptr);
int_arr_ptr = NULL;
printf("freeing the array...\n");
fflush(stdout);
printf("________END_____________\n");
fflush(stdout);
ck_assert_int_eq(ptr_tree_base_int_1->size, 0);
} END_TEST
PrintTree function
bool printTree(TreeBase *tree){
void *previous = NULL;
int cnt_tasks = 0;
if (!tree) {
printf("PRINT: Cannot print empty tree base\n");
fflush(stdout);
return false;
}
/* set current to root of binary tree */
TreeNode *current_node = tree->base;
if (!(tree->base)) {
printf("PRINT: Cannot print empty tree\n");
fflush(stdout);
return false;
}
StackNode *stack = NULL;
while (true) {
if(current_node) {
push(&stack, current_node);
current_node = current_node->left;
} else {
if (stack) {
current_node = pop(&stack);
if (cnt_tasks > 1) {
if (tree->comp(previous, current_node->value) != -1) {
printf("PRINTTREE: Invalid BST\n");
fflush(stdout);
assert(NULL);
}
}
previous = current_node->value;
tree->print(current_node->value);
cnt_tasks++;
current_node = current_node->right;
} else {
return (cnt_tasks == tree->size);
}
}
}
}
tree->print function
void print_ints(void *p){
printf("%d\n", *(int*)p);
fflush(stdout);
}
Sample output
FREETREE: Cant free empty tree
!!!Next line has to be:"cannot free empty tree"
FREETREE: Cant free empty tree
FREETREE: Cant free empty tree
!!!Next line has to be:"cannot print empty tree"
PRINT: Cannot print empty tree
PRINT: Cannot print empty tree
_____________________
That is a lot of code, Main point is after !!! there should be one line but two printed
printf("PRINT: Cannot print empty tree\n");
fflush(stdout);
return false;
^^ This line prints twice
For comments: what is "Macros"? and this is from the API
#define ck_assert_int_eq(X, Y) _ck_assert_int(X, ==, Y)
The ck_assert_int_eq
macro introduced in version 0.9.6 of the Check unit testing framework was defined as:
#define _ck_assert_int(X, O, Y) ck_assert_msg((X) O (Y), \
"Assertion '"#X#O#Y"' failed: "#X"==%d, "#Y"==%d", X, Y)
#define ck_assert_int_eq(X, Y) _ck_assert_int(X, ==, Y)
As can be seen, the arguments appear twice in the macro definition: one time for the actual equality check (the (X) O (Y)
part), and another as the last arguments to ck_assert_msg(..., X, Y)
for the purpose of logging a message in case of failure. Looking at a specific part of your code:
// should print cannot print empty tree
printf("!!!Next line has to be:\"cannot print empty tree\"\n");
fflush(stdout);
ck_assert_int_eq(printTree(ptr_tree_base_int_1), false);
the C-preprocessor would correspondingly expand the macro to code equivalent to:
// should print cannot free empty tree
printf("!!!Next line has to be:\"cannot free empty tree\"\n");
fflush(stdout);
ck_assert_msg((printTree(ptr_tree_base_int_1)) == (false),
"Assertion '"#X#O#Y"' failed: "#X"==%d, "#Y"==%d",
printTree(ptr_tree_base_int_1), false);
The printTree
function is thus called twice with all the associated side effects, including printing the line "PRINT: Cannot print empty tree"
twice.
One way to protect yourself against this kind of error is to make sure arguments to macros have no possible side effects. This can be accomplished in your case, by moving the call to printTree
outside the macro:
bool printTreeResult;
printTreeResult = printTree(ptr_tree_base_int_1);
ck_assert_int_eq(printTreeResult, false);
Note that since this kind of macro is generally error prone (as you've just experienced), the definition of the ck_assert_int_eq
was improved in version 0.9.9 to:
#define _ck_assert_int(X, OP, Y) do { \
int _ck_x = (X); \
int _ck_y = (Y); \
ck_assert_msg(_ck_x OP _ck_y, \
"Assertion '"#X#OP#Y"' failed: "#X"==%d, "#Y"==%d", _ck_x, _ck_y); \
} while (0)
#define ck_assert_int_eq(X, Y) _ck_assert_int(X, ==, Y)
Correspondingly, another way to fix the problem with duplicated output lines would be to upgrade your installation of the Check unit testing framework to a more recent version (i.e. at least 0.9.9), if that's an option.