test(tree): validation function to use in testing
ci/woodpecker/pr/lint Pipeline was successful Details
ci/woodpecker/pr/test Pipeline failed Details
ci/woodpecker/pr/test-mem unknown status Details

pull/5/head
Jef Roosens 2023-01-28 19:27:40 +01:00
parent 89d1c9cdca
commit 3fb027715c
Signed by: Jef Roosens
GPG Key ID: B75D4F293C7052DB
5 changed files with 74 additions and 3 deletions

View File

@ -1,4 +1,4 @@
#include "vieter_tree.h" #include "vieter_tree_internal.h"
#include "vieter_tree_node.h" #include "vieter_tree_node.h"
struct vieter_tree { struct vieter_tree {
@ -98,3 +98,23 @@ void vieter_tree_free(vieter_tree *tree) {
end: end:
free(tree); free(tree);
} }
int vieter_tree_validate(vieter_tree *tree) {
if (tree->size == 0) {
return 0;
}
// DFS to get expected black nodes
uint64_t expected_black_nodes = 0;
vieter_tree_node *node = tree->root;
while (node != NULL) {
if (vieter_tree_node_get(node, vieter_node_black)) {
expected_black_nodes++;
}
node = node->left;
}
return vieter_tree_node_validate(tree->root, 0, expected_black_nodes);
}

View File

@ -1,5 +1,43 @@
#include "vieter_tree_balancing.h" #include "vieter_tree_balancing.h"
int vieter_tree_node_validate(vieter_tree_node *node,
uint64_t passed_black_nodes,
uint64_t expected_black_nodes) {
if (vieter_tree_node_get(node, vieter_node_black)) {
passed_black_nodes++;
} else {
// A red node should have black child nodes
if ((node->left != NULL &&
!vieter_tree_node_get(node->left, vieter_node_black)) ||
(node->right != NULL &&
!vieter_tree_node_get(node->right, vieter_node_black))) {
return 1;
}
}
// All paths to a NULL child should have the same amount of black nodes
if ((node->left == NULL || node->right == NULL) &&
passed_black_nodes != expected_black_nodes) {
return 1;
}
if (node->left != NULL) {
if (vieter_tree_node_validate(node->left, passed_black_nodes,
expected_black_nodes) != 0) {
return 1;
}
}
if (node->right != NULL) {
if (vieter_tree_node_validate(node->right, passed_black_nodes,
expected_black_nodes) != 0) {
return 1;
}
}
return 0;
}
vieter_tree_node *vieter_tree_node_balance(vieter_tree_node *node) { vieter_tree_node *vieter_tree_node_balance(vieter_tree_node *node) {
vieter_tree_node *parent = node->parent; vieter_tree_node *parent = node->parent;
vieter_tree_node *grand_parent = parent->parent; vieter_tree_node *grand_parent = parent->parent;

View File

@ -0,0 +1,8 @@
#include "vieter_tree.h"
/*
* Inspect whether the tree is still a valid red-black-tree.
*
* @return 0 if correct, 1 if not.
*/
int vieter_tree_validate(vieter_tree *tree);

View File

@ -40,4 +40,6 @@ bool vieter_tree_node_get(vieter_tree_node *node, vieter_node_flag flag);
void vieter_tree_node_add_child(vieter_tree_node *parent, uint64_t key, void vieter_tree_node_add_child(vieter_tree_node *parent, uint64_t key,
vieter_tree_node *child); vieter_tree_node *child);
int vieter_tree_node_validate(vieter_tree_node *node, uint64_t passed_black_nodes, uint64_t expected_black_nodes);
#endif #endif

View File

@ -1,5 +1,5 @@
#include "acutest.h" #include "acutest.h"
#include "vieter_tree.h" #include "vieter_tree_internal.h"
#define TEST_SIZE(tree, size) \ #define TEST_SIZE(tree, size) \
TEST_CHECK(vieter_tree_size(tree) == size); \ TEST_CHECK(vieter_tree_size(tree) == size); \
@ -18,6 +18,7 @@ void test_insert() {
for (uint64_t i = 0; i < 250; i++) { for (uint64_t i = 0; i < 250; i++) {
TEST_CHECK(vieter_tree_insert(tree, i, NULL) == vieter_tree_ok); TEST_CHECK(vieter_tree_insert(tree, i, NULL) == vieter_tree_ok);
TEST_SIZE(tree, i + 1); TEST_SIZE(tree, i + 1);
TEST_CHECK(vieter_tree_validate(tree) == 0);
} }
void *out; void *out;
@ -36,13 +37,15 @@ void test_remove() {
for (uint64_t i = 0; i < 250; i++) { for (uint64_t i = 0; i < 250; i++) {
TEST_CHECK(vieter_tree_insert(tree, i, NULL) == vieter_tree_ok); TEST_CHECK(vieter_tree_insert(tree, i, NULL) == vieter_tree_ok);
TEST_CHECK(vieter_tree_validate(tree) == 0);
} }
void *out; void *out;
for (uint64_t i = 0; i < 250; i++) { for (uint64_t i = 0; i < 25; i++) {
TEST_CHECK(vieter_tree_search(&out, tree, i) == vieter_tree_ok); TEST_CHECK(vieter_tree_search(&out, tree, i) == vieter_tree_ok);
TEST_CHECK(vieter_tree_remove(&out, tree, i) == vieter_tree_ok); TEST_CHECK(vieter_tree_remove(&out, tree, i) == vieter_tree_ok);
TEST_CHECK(vieter_tree_validate(tree) == 0);
TEST_CHECK(vieter_tree_search(&out, tree, i) == vieter_tree_not_present); TEST_CHECK(vieter_tree_search(&out, tree, i) == vieter_tree_not_present);
TEST_SIZE(tree, 250 - i - 1); TEST_SIZE(tree, 250 - i - 1);
} }