Skip to content
Snippets Groups Projects
Commit a2c07253 authored by Florian Burgener's avatar Florian Burgener
Browse files

Done unit testing for both insertion and deletion

parent a6e9ca9e
No related branches found
No related tags found
No related merge requests found
......@@ -304,7 +304,7 @@ static bool _BPTree_delete(BPTreeNode *root, uint64_t key, BPTreeNode *parent) {
root->keys->items[index] = find_smallest_key(root->children->items[index + 1]);
}
if (parent == NULL && root->keys->size == 0) {
if (parent == NULL && !root->is_leaf && root->keys->size == 0) {
shrink(root);
}
......
......@@ -22,13 +22,13 @@ $(TARGET): $(OBJECTS)
# TESTS_BEGIN
unity.o: tests/unity.c tests/unity.h
Unity.o: tests/Unity/unity.c tests/Unity/unity.h
$(CC) $(CFLAGS) -c $< -o $@
testtest.o: tests/testtest.c
BPTreeTests.o: tests/BPTreeTests.c
$(CC) $(CFLAGS) -c $< -o $@
make_run_tests: unity.o testtest.o Array.o
make_run_tests: Unity.o BPTreeTests.o Array.o BPTree.o
$(CC) $^ $(CFLAGS) $(LIBS) -o tests_exec
./tests_exec || true
......
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include "../Array.h"
#include "../BPTree.h"
#include "Unity/unity.h"
#define RANDOM_MIN 0
#define RANDOM_MAX 1000
BPTreeNode *tree;
void setUp(void) {
}
void tearDown(void) {
if (tree != NULL) {
BPTree_destroy(&tree);
}
}
// BEGIN : Compliance with B+ Tree rules
static bool check_if_BPTree_is_compliant_with_the_rules(BPTreeNode *root);
static bool check_if_the_leaves_are_all_at_the_same_depth(BPTreeNode *root);
static int compute_first_leaf_depth(BPTreeNode *root);
static bool _check_if_the_leaves_are_all_at_the_same_depth(BPTreeNode *root, int expected_depth, int depth);
static bool check_if_all_internal_nodes_have_no_data(BPTreeNode *root);
static bool check_if_all_leaf_nodes_have_as_much_data_as_keys(BPTreeNode *root);
static bool check_if_the_keys_are_sorted_in_all_nodes(BPTreeNode *root);
static bool check_if_the_array_is_sorted(IntegerArray *array);
static bool check_if_all_nodes_except_the_root_have_not_less_keys_than_the_minimum(BPTreeNode *root, BPTreeNode *parent);
static bool check_if_all_nodes_have_no_more_keys_than_the_maximum(BPTreeNode *root);
static bool check_in_all_internal_nodes_there_is_1_child_more_than_the_number_of_keys(BPTreeNode *root);
static bool check_if_the_keys_are_inserted_in_the_right_place(BPTreeNode *root);
static bool check_if_the_keys_are_inserted_in_the_right_place_with_range(BPTreeNode *root, uint64_t left, uint64_t right);
static bool check_if_BPTree_is_compliant_with_the_rules(BPTreeNode *root) {
bool is_compliant = true;
is_compliant &= check_if_the_leaves_are_all_at_the_same_depth(root);
is_compliant &= check_if_all_internal_nodes_have_no_data(root);
is_compliant &= check_if_all_leaf_nodes_have_as_much_data_as_keys(root);
is_compliant &= check_if_the_keys_are_sorted_in_all_nodes(root);
is_compliant &= check_if_all_nodes_except_the_root_have_not_less_keys_than_the_minimum(root, NULL);
is_compliant &= check_if_all_nodes_have_no_more_keys_than_the_maximum(root);
is_compliant &= check_in_all_internal_nodes_there_is_1_child_more_than_the_number_of_keys(root);
is_compliant &= check_if_the_keys_are_inserted_in_the_right_place(root);
// TODO : check if linked list is ok
return is_compliant;
}
static bool check_if_the_leaves_are_all_at_the_same_depth(BPTreeNode *root) {
int expected_depth = compute_first_leaf_depth(root);
return _check_if_the_leaves_are_all_at_the_same_depth(root, expected_depth, 0);
}
static int compute_first_leaf_depth(BPTreeNode *root) {
if (root->is_leaf) {
return 0;
}
return compute_first_leaf_depth(root->children->items[0]) + 1;
}
static bool _check_if_the_leaves_are_all_at_the_same_depth(BPTreeNode *root, int expected_depth, int depth) {
if (root->is_leaf) {
return depth == expected_depth;
}
for (int i = 0; i < root->children->size; i++) {
if (!_check_if_the_leaves_are_all_at_the_same_depth(root->children->items[i], expected_depth, depth + 1)) {
return false;
}
}
return true;
}
static bool check_if_all_internal_nodes_have_no_data(BPTreeNode *root) {
if (root->is_leaf) {
return true;
}
for (int i = 0; i < root->children->size; i++) {
if (!check_if_all_internal_nodes_have_no_data(root->children->items[i])) {
return false;
}
}
return root->data->size == 0;
}
static bool check_if_all_leaf_nodes_have_as_much_data_as_keys(BPTreeNode *root) {
if (root->is_leaf) {
return root->keys->size == root->data->size;
}
for (int i = 0; i < root->children->size; i++) {
if (!check_if_all_leaf_nodes_have_as_much_data_as_keys(root->children->items[i])) {
return false;
}
}
return true;
}
static bool check_if_the_keys_are_sorted_in_all_nodes(BPTreeNode *root) {
for (int i = 0; i < root->children->size; i++) {
if (!check_if_the_keys_are_sorted_in_all_nodes(root->children->items[i])) {
return false;
}
}
return check_if_the_array_is_sorted(root->keys);
}
static bool check_if_the_array_is_sorted(IntegerArray *array) {
for (int i = 0; i < array->size - 1; i++) {
if (array->items[i] > array->items[i + 1]) {
return false;
}
}
return true;
}
static bool check_if_all_nodes_except_the_root_have_not_less_keys_than_the_minimum(BPTreeNode *root, BPTreeNode *parent) {
for (int i = 0; i < root->children->size; i++) {
if (!check_if_all_nodes_except_the_root_have_not_less_keys_than_the_minimum(root->children->items[i], root)) {
return false;
}
}
if (parent == NULL) {
return true;
}
return root->keys->size >= root->order;
}
static bool check_if_all_nodes_have_no_more_keys_than_the_maximum(BPTreeNode *root) {
for (int i = 0; i < root->children->size; i++) {
if (!check_if_all_nodes_have_no_more_keys_than_the_maximum(root->children->items[i])) {
return false;
}
}
return root->keys->size <= 2 * root->order;
}
static bool check_in_all_internal_nodes_there_is_1_child_more_than_the_number_of_keys(BPTreeNode *root) {
if (root->is_leaf) {
return true;
}
for (int i = 0; i < root->children->size; i++) {
if (!check_in_all_internal_nodes_there_is_1_child_more_than_the_number_of_keys(root->children->items[i])) {
return false;
}
}
return root->children->size == root->keys->size + 1;
}
static bool check_if_the_keys_are_inserted_in_the_right_place(BPTreeNode *root) {
if (root->is_leaf) {
return true;
}
for (int i = 0; i < root->children->size; i++) {
if (i == 0) {
if (!check_if_the_keys_are_inserted_in_the_right_place_with_range(root->children->items[i], 0, root->keys->items[i])) {
return false;
}
} else if (i == root->children->size - 1) {
if (!check_if_the_keys_are_inserted_in_the_right_place_with_range(root->children->items[i], root->keys->items[i - 1], 18446744073709551615LLU)) {
return false;
}
} else {
if (!check_if_the_keys_are_inserted_in_the_right_place_with_range(root->children->items[i], root->keys->items[i - 1], root->keys->items[i])) {
return false;
}
}
}
for (int i = 0; i < root->children->size; i++) {
if (!check_if_the_keys_are_inserted_in_the_right_place(root->children->items[i])) {
return false;
}
}
return true;
}
static bool check_if_the_keys_are_inserted_in_the_right_place_with_range(BPTreeNode *root, uint64_t left, uint64_t right) {
for (int i = 0; i < root->keys->size; i++) {
if (root->keys->items[i] < left || root->keys->items[i] >= right) {
return false;
}
}
for (int i = 0; i < root->children->size; i++) {
if (!check_if_the_keys_are_inserted_in_the_right_place_with_range(root->children->items[i], left, right)) {
return false;
}
}
return true;
}
// END : BPTree Compliance
/**
* @brief Performs a linear search for an item in an array.
*
* @param array The array in which the search is to be performed.
* @param item The item searched for.
* @return true The item has been found.
* @return false The item was not found.
*/
static bool IntegerArray_search(IntegerArray *array, uint64_t item) {
for (int i = 0; i < array->size; i++) {
if (array->items[i] == item) {
return true;
}
}
return false;
}
/**
* @brief Generates an array of random numbers.
*
* @param size The number of numbers to generate.
* @param random_min The smallest random value.
* @param random_max The greatest random value.
* @return IntegerArray* The random number array.
*/
static IntegerArray *generate_random_numbers_array(int size, int random_min, int random_max) {
IntegerArray *array = IntegerArray_init(size);
for (int i = 0; i < size; i++) {
uint64_t number;
// While the generated random nomber already exists in the array.
do {
number = random_min + rand() % (random_max - random_min);
} while (IntegerArray_search(array, number));
IntegerArray_append(array, number);
}
return array;
}
static uint64_t transform_key_to_data(uint64_t key) {
return key * 10000;
}
// BEGIN : Tests
// **** BEGIN : test_BPTree_insert
static void test_BPTree_insert_should_comply_with_BPTree_rules_using_BPTree_of_given_order(BPTreeNode **root, int order) {
int size = 1;
// Test 10 times, variable i being the seed.
for (int i = 0; i < 10; i++) {
srand(i);
// Test with seed "i" 8 array size, at each end of loop the size variable is multiplied by 2, the array of random keys
// will have the size of 1 then 2, 4, 8, 16, 32, ...
for (int j = 0; j < 8; j++) {
IntegerArray *keys = generate_random_numbers_array(size, RANDOM_MIN, RANDOM_MAX);
*root = BPTree_init(order);
for (int i = 0; i < keys->size; i++) {
BPTree_insert(*root, keys->items[i], transform_key_to_data(keys->items[i]));
// After each insertion is verified that the B+ Tree is compliant with the rules.
TEST_ASSERT(check_if_BPTree_is_compliant_with_the_rules(*root));
}
IntegerArray_destroy(&keys);
BPTree_destroy(root);
size *= 2;
}
size = 1;
}
}
void test_BPTree_insert_should_comply_with_BPTree_rules_using_BPTree_of_order_1() {
test_BPTree_insert_should_comply_with_BPTree_rules_using_BPTree_of_given_order(&tree, 1);
}
void test_BPTree_insert_should_comply_with_BPTree_rules_using_BPTree_of_order_2() {
test_BPTree_insert_should_comply_with_BPTree_rules_using_BPTree_of_given_order(&tree, 2);
}
void test_BPTree_insert_should_comply_with_BPTree_rules_using_BPTree_of_order_3() {
test_BPTree_insert_should_comply_with_BPTree_rules_using_BPTree_of_given_order(&tree, 3);
}
void test_BPTree_insert_should_comply_with_BPTree_rules_using_BPTree_of_order_4() {
test_BPTree_insert_should_comply_with_BPTree_rules_using_BPTree_of_given_order(&tree, 4);
}
void test_BPTree_insert_should_comply_with_BPTree_rules_using_BPTree_of_order_8() {
test_BPTree_insert_should_comply_with_BPTree_rules_using_BPTree_of_given_order(&tree, 8);
}
void test_BPTree_insert_should_comply_with_BPTree_rules_using_BPTree_of_order_16() {
test_BPTree_insert_should_comply_with_BPTree_rules_using_BPTree_of_given_order(&tree, 16);
}
// **** END : test_BPTree_insert
// **** BEGIN : test_BPTree_delete
void test_BPTree_delete_should_comply_with_BPTree_rules_using_BPTree_of_given_order(BPTreeNode **root, int order) {
int size = 1;
// Test 10 times, variable i being the seed.
for (int i = 0; i < 10; i++) {
srand(i);
// Test with seed "i" 8 array size, at each end of loop the size variable is multiplied by 2, the array of random keys
// will have the size of 1 then 2, 4, 8, 16, 32, ...
for (int j = 0; j < 8; j++) {
IntegerArray *keys = generate_random_numbers_array(size, RANDOM_MIN, RANDOM_MAX);
*root = BPTree_init(order);
for (int i = 0; i < keys->size; i++) {
BPTree_insert(*root, keys->items[i], transform_key_to_data(keys->items[i]));
}
while (keys->size > 0) {
int index = rand() % keys->size;
BPTree_delete(*root, keys->items[index]);
IntegerArray_delete_at_index(keys, index);
}
IntegerArray_destroy(&keys);
BPTree_destroy(&(*root));
size *= 2;
}
size = 1;
}
}
void test_BPTree_delete_should_comply_with_BPTree_rules_using_BPTree_of_order_1() {
test_BPTree_delete_should_comply_with_BPTree_rules_using_BPTree_of_given_order(&tree, 1);
}
void test_BPTree_delete_should_comply_with_BPTree_rules_using_BPTree_of_order_2() {
test_BPTree_delete_should_comply_with_BPTree_rules_using_BPTree_of_given_order(&tree, 2);
}
void test_BPTree_delete_should_comply_with_BPTree_rules_using_BPTree_of_order_3() {
test_BPTree_delete_should_comply_with_BPTree_rules_using_BPTree_of_given_order(&tree, 3);
}
void test_BPTree_delete_should_comply_with_BPTree_rules_using_BPTree_of_order_4() {
test_BPTree_delete_should_comply_with_BPTree_rules_using_BPTree_of_given_order(&tree, 4);
}
void test_BPTree_delete_should_comply_with_BPTree_rules_using_BPTree_of_order_8() {
test_BPTree_delete_should_comply_with_BPTree_rules_using_BPTree_of_given_order(&tree, 8);
}
void test_BPTree_delete_should_comply_with_BPTree_rules_using_BPTree_of_order_16() {
test_BPTree_delete_should_comply_with_BPTree_rules_using_BPTree_of_given_order(&tree, 16);
}
// **** END : test_BPTree_delete
// END : Tests
int main(void) {
UNITY_BEGIN();
RUN_TEST(test_BPTree_insert_should_comply_with_BPTree_rules_using_BPTree_of_order_1);
RUN_TEST(test_BPTree_insert_should_comply_with_BPTree_rules_using_BPTree_of_order_2);
RUN_TEST(test_BPTree_insert_should_comply_with_BPTree_rules_using_BPTree_of_order_3);
RUN_TEST(test_BPTree_insert_should_comply_with_BPTree_rules_using_BPTree_of_order_4);
RUN_TEST(test_BPTree_insert_should_comply_with_BPTree_rules_using_BPTree_of_order_8);
RUN_TEST(test_BPTree_insert_should_comply_with_BPTree_rules_using_BPTree_of_order_16);
RUN_TEST(test_BPTree_delete_should_comply_with_BPTree_rules_using_BPTree_of_order_1);
RUN_TEST(test_BPTree_delete_should_comply_with_BPTree_rules_using_BPTree_of_order_2);
RUN_TEST(test_BPTree_delete_should_comply_with_BPTree_rules_using_BPTree_of_order_3);
RUN_TEST(test_BPTree_delete_should_comply_with_BPTree_rules_using_BPTree_of_order_4);
RUN_TEST(test_BPTree_delete_should_comply_with_BPTree_rules_using_BPTree_of_order_8);
RUN_TEST(test_BPTree_delete_should_comply_with_BPTree_rules_using_BPTree_of_order_16);
return UNITY_END();
}
File moved
File moved
File moved
#include "../Array.h"
#include "unity.h"
IntegerArray *array;
void setUp(void) {
array = IntegerArray_init(4);
}
void tearDown(void) {
IntegerArray_destroy(&array);
}
void test_function_should_doAlsoDoBlah(void) {
IntegerArray_append(array, 10);
TEST_ASSERT_EQUAL_INT(1, array->size);
TEST_ASSERT_EQUAL_INT(11, array->items[0]);
}
int main(void) {
UNITY_BEGIN();
RUN_TEST(test_function_should_doAlsoDoBlah);
return UNITY_END();
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment