179 lines
4.0 KiB
C
179 lines
4.0 KiB
C
#include <malloc.h>
|
|
#include <stdbool.h>
|
|
#include <stdint.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#include "test-util.h"
|
|
#include "tree.h"
|
|
|
|
#define NODE_COUNT 1000
|
|
static_assert(NODE_COUNT <= RAND_MAX, "NODE_COUNT too high");
|
|
|
|
typedef void (*test_op_t)(tree_t* tree, uintptr_t key);
|
|
|
|
static size_t count_subtree(const tree_node_t* node) {
|
|
if (node == NULL)
|
|
return 0;
|
|
else
|
|
return 1 + count_subtree(node->left) + count_subtree(node->right);
|
|
}
|
|
|
|
static size_t count_tree(const tree_t* tree) {
|
|
return count_subtree(tree_root(tree));
|
|
}
|
|
|
|
static size_t check_subtree_structure(const tree_node_t* node) {
|
|
size_t black_height_left;
|
|
size_t black_height_right;
|
|
|
|
if (!node)
|
|
return 0;
|
|
|
|
black_height_left = check_subtree_structure(node->left);
|
|
black_height_right = check_subtree_structure(node->right);
|
|
check(black_height_left == black_height_right);
|
|
|
|
if (node->red) {
|
|
check(!node->left || !node->left->red);
|
|
check(!node->right || !node->right->red);
|
|
return black_height_left;
|
|
} else {
|
|
return black_height_left + 1;
|
|
}
|
|
}
|
|
|
|
static void check_tree_structure(const tree_t* tree) {
|
|
check_subtree_structure(tree_root(tree));
|
|
}
|
|
|
|
static void check_tree_count(const tree_t* tree, size_t expected_count) {
|
|
size_t count = count_tree(tree);
|
|
check(count == expected_count);
|
|
}
|
|
|
|
static void keys_increasing(tree_t* tree, test_op_t op) {
|
|
uintptr_t i;
|
|
for (i = 0; i < NODE_COUNT; i++)
|
|
op(tree, i);
|
|
}
|
|
|
|
static void keys_decreasing(tree_t* tree, test_op_t op) {
|
|
intptr_t i;
|
|
for (i = NODE_COUNT - 1; i >= 0; i--)
|
|
op(tree, (uintptr_t) i);
|
|
}
|
|
|
|
static void keys_random(tree_t* tree, test_op_t op) {
|
|
uintptr_t keys[NODE_COUNT];
|
|
uintptr_t index, key;
|
|
intptr_t left;
|
|
|
|
for (index = 0; index < NODE_COUNT; index++)
|
|
keys[index] = index;
|
|
|
|
for (left = NODE_COUNT - 1; left >= 0; left--) {
|
|
index = left == 0 ? 0 : (uintptr_t)(rand() % left);
|
|
key = keys[index];
|
|
keys[index] = keys[left];
|
|
op(tree, key);
|
|
}
|
|
}
|
|
|
|
static void add(tree_t* tree, uintptr_t key) {
|
|
tree_node_t* node;
|
|
size_t before_count;
|
|
int r;
|
|
|
|
before_count = count_tree(tree);
|
|
|
|
node = malloc(sizeof *node);
|
|
check(node != NULL);
|
|
tree_node_init(node);
|
|
|
|
r = tree_add(tree, node, key);
|
|
check(r == 0);
|
|
check(node->key == key);
|
|
|
|
check_tree_structure(tree);
|
|
check_tree_count(tree, before_count + 1);
|
|
}
|
|
|
|
static void add_error(tree_t* tree, uintptr_t key) {
|
|
tree_node_t node;
|
|
size_t before_count;
|
|
int r;
|
|
|
|
before_count = count_tree(tree);
|
|
|
|
tree_node_init(&node);
|
|
r = tree_add(tree, &node, key);
|
|
check(r == -1);
|
|
|
|
check_tree_structure(tree);
|
|
check_tree_count(tree, before_count);
|
|
}
|
|
|
|
static void find_del(tree_t* tree, uintptr_t key) {
|
|
tree_node_t* node;
|
|
size_t before_count;
|
|
|
|
before_count = count_tree(tree);
|
|
|
|
node = tree_find(tree, key);
|
|
check(node != NULL);
|
|
check(node->key == key);
|
|
|
|
tree_del(tree, node);
|
|
free(node);
|
|
|
|
check_tree_structure(tree);
|
|
check_tree_count(tree, before_count - 1);
|
|
}
|
|
|
|
static void find_error(tree_t* tree, uintptr_t key) {
|
|
tree_node_t* node;
|
|
size_t before_count;
|
|
|
|
before_count = count_tree(tree);
|
|
|
|
node = tree_find(tree, key);
|
|
check(node == NULL);
|
|
|
|
check_tree_structure(tree);
|
|
check_tree_count(tree, before_count);
|
|
}
|
|
|
|
int main(void) {
|
|
tree_t tree;
|
|
tree_init(&tree);
|
|
|
|
keys_increasing(&tree, add);
|
|
check_tree_count(&tree, NODE_COUNT);
|
|
keys_increasing(&tree, add_error);
|
|
keys_increasing(&tree, find_del);
|
|
check_tree_count(&tree, 0);
|
|
keys_increasing(&tree, find_error);
|
|
|
|
keys_decreasing(&tree, add);
|
|
check_tree_count(&tree, NODE_COUNT);
|
|
keys_decreasing(&tree, add_error);
|
|
keys_decreasing(&tree, find_del);
|
|
check_tree_count(&tree, 0);
|
|
keys_decreasing(&tree, find_error);
|
|
|
|
keys_random(&tree, add);
|
|
check_tree_count(&tree, NODE_COUNT);
|
|
keys_random(&tree, add_error);
|
|
keys_random(&tree, find_del);
|
|
check_tree_count(&tree, 0);
|
|
keys_random(&tree, find_error);
|
|
|
|
keys_random(&tree, add);
|
|
check_tree_count(&tree, NODE_COUNT);
|
|
keys_increasing(&tree, add_error);
|
|
keys_decreasing(&tree, find_del);
|
|
check_tree_count(&tree, 0);
|
|
keys_random(&tree, find_error);
|
|
}
|