Skip to content
Snippets Groups Projects
Commit 38e5b116 authored by knizhnik's avatar knizhnik
Browse files

Add unit tests for R-Tree

parent 95ddb007
No related branches found
No related tags found
No related merge requests found
#include <stdlib.h>
#include <stdint.h>
#include <stdio.h>
#include <stdbool.h>
#include <inttypes.h>
#include "unit.h"
#include "rtree.h"
static int page_count = 0;
static void *
page_alloc()
{
page_count++;
return malloc(RTREE_PAGE_SIZE);
}
static void
page_free(void *page)
{
page_count--;
free(page);
}
static void
simple_check()
{
rectangle_t r;
R_tree_iterator iterator;
const size_t rounds = 2000;
header();
R_tree tree(page_alloc, page_free);
printf("Insert 1..X, remove 1..X\n");
for (size_t i = 1; i <= rounds; i++) {
record_t rec = (record_t)i;
r.boundary[0] = r.boundary[1] = i;
r.boundary[2] = r.boundary[3] = i + 0.5;
if (tree.search(r, SOP_EQUALS, iterator)) {
fail("element already in tree (1)", "true");
}
tree.insert(r, rec);
}
if (tree.number_of_records() != rounds) {
fail("Tree count mismatch (1)", "true");
}
for (size_t i = 1; i <= rounds; i++) {
record_t rec = (record_t)i;
r.boundary[0] = r.boundary[1] = i;
r.boundary[2] = r.boundary[3] = i + 0.5;
if (!tree.search(r, SOP_EQUALS, iterator)) {
fail("element in tree (1)", "false");
}
if (iterator.next() != rec) {
fail("right search result (1)", "true");
}
if (iterator.next()) {
fail("single search result (1)", "true");
}
if (!tree.remove(r, rec)) {
fail("delete element in tree (1)", "false");
}
if (tree.search(r, SOP_EQUALS, iterator)) {
fail("element still in tree (1)", "true");
}
}
if (tree.number_of_records() != 0) {
fail("Tree count mismatch (1)", "true");
}
printf("Insert 1..X, remove X..1\n");
for (size_t i = 1; i <= rounds; i++) {
record_t rec = (record_t)i;
r.boundary[0] = r.boundary[1] = i;
r.boundary[2] = r.boundary[3] = i + 0.5;
if (tree.search(r, SOP_OVERLAPS, iterator)) {
fail("element already in tree (2)", "true");
}
tree.insert(r, rec);
}
if (tree.number_of_records() != rounds) {
fail("Tree count mismatch (2)", "true");
}
for (size_t i = rounds; i != 0; i--) {
record_t rec = (record_t)i;
r.boundary[0] = r.boundary[1] = i;
r.boundary[2] = r.boundary[3] = i + 0.5;
if (!tree.search(r, SOP_OVERLAPS, iterator)) {
fail("element in tree (2)", "false");
}
if (iterator.next() != rec) {
fail("right search result (2)", "true");
}
if (iterator.next()) {
fail("single search result (2)", "true");
}
if (!tree.remove(r, rec)) {
fail("delete element in tree (2)", "false");
}
if (tree.search(r, SOP_OVERLAPS, iterator)) {
fail("element still in tree (2)", "true");
}
}
if (tree.number_of_records() != 0) {
fail("Tree count mismatch (2)", "true");
}
printf("Insert X..1, remove 1..X\n");
for (size_t i = rounds; i != 0; i--) {
record_t rec = (record_t)i;
r.boundary[0] = r.boundary[1] = i;
r.boundary[2] = r.boundary[3] = i + 0.5;
if (tree.search(r, SOP_BELONGS, iterator)) {
fail("element already in tree (3)", "true");
}
tree.insert(r, rec);
}
if (tree.number_of_records() != rounds) {
fail("Tree count mismatch (3)", "true");
}
for (size_t i = 1; i <= rounds; i++) {
record_t rec = (record_t)i;
r.boundary[0] = r.boundary[1] = i;
r.boundary[2] = r.boundary[3] = i + 0.5;
if (!tree.search(r, SOP_BELONGS, iterator)) {
fail("element in tree (3)", "false");
}
if (iterator.next() != rec) {
fail("right search result (3)", "true");
}
if (iterator.next()) {
fail("single search result (3)", "true");
}
if (!tree.remove(r, rec)) {
fail("delete element in tree (3)", "false");
}
if (tree.search(r, SOP_BELONGS, iterator)) {
fail("element still in tree (3)", "true");
}
}
if (tree.number_of_records() != 0) {
fail("Tree count mismatch (3)", "true");
}
printf("Insert X..1, remove X..1\n");
for (size_t i = rounds; i != 0; i--) {
record_t rec = (record_t)i;
r.boundary[0] = r.boundary[1] = i;
r.boundary[2] = r.boundary[3] = i + 0.5;
if (tree.search(r, SOP_CONTAINS, iterator)) {
fail("element already in tree (4)", "true");
}
tree.insert(r, rec);
}
if (tree.number_of_records() != rounds) {
fail("Tree count mismatch (4)", "true");
}
for (size_t i = rounds; i != 0; i--) {
record_t rec = (record_t)i;
r.boundary[0] = r.boundary[1] = i;
r.boundary[2] = r.boundary[3] = i + 0.5;
if (!tree.search(r, SOP_CONTAINS, iterator)) {
fail("element in tree (4)", "false");
}
if (iterator.next() != rec) {
fail("right search result (4)", "true");
}
if (iterator.next()) {
fail("single search result (4)", "true");
}
if (!tree.remove(r, rec)) {
fail("delete element in tree (4)", "false");
}
if (tree.search(r, SOP_CONTAINS, iterator)) {
fail("element still in tree (4)", "true");
}
}
if (tree.number_of_records() != 0) {
fail("Tree count mismatch (4)", "true");
}
tree.purge();
footer();
}
static void
rtree_test_build(R_tree& tree, rectangle_t* arr, int count)
{
for (size_t i = 0; i < count; i++) {
record_t rec = (record_t)(i + 1);
tree.insert(arr[i], rec);
}
}
static void
neighbor_test()
{
header();
const int test_count = 1000;
R_tree_iterator iterator;
rectangle_t arr[test_count];
static rectangle_t basis;
for (size_t i = 0; i < test_count; i++) {
arr[i].boundary[0] = arr[i].boundary[1] = i;
arr[i].boundary[2] = arr[i].boundary[3] = i+1;
}
for (size_t i = 0; i <= test_count; i++) {
R_tree tree(page_alloc, page_free);
rtree_test_build(tree, arr, i);
if (!tree.search(basis, SOP_NEIGHBOR, iterator) && i != 0) {
fail("search is successful", "true");
}
for (size_t j = 0; j < i; j++) {
record_t rec = iterator.next();
if (rec != record_t(j+1)) {
fail("wrong search result", "true");
}
}
}
footer();
}
int
main(void)
{
simple_check();
neighbor_test();
if (page_count != 0) {
fail("memory leak!", "true");
}
}
*** simple_check ***
Insert 1..X, remove 1..X
Insert 1..X, remove X..1
Insert X..1, remove 1..X
Insert X..1, remove X..1
*** simple_check: done ***
*** neighbor_test ***
*** neighbor_test: done ***
\ No newline at end of file
#include <stdlib.h>
#include <stdint.h>
#include <stdio.h>
#include <stdbool.h>
#include "unit.h"
#include "rtree.h"
static int page_count = 0;
static void *
page_alloc()
{
page_count++;
return malloc(RTREE_PAGE_SIZE);
}
static void
page_free(void *page)
{
page_count--;
free(page);
}
static void
itr_check()
{
header();
R_tree tree(page_alloc, page_free);
/* Filling tree */
const size_t count1 = 10000;
const size_t count2 = 5;
rectangle_t r;
size_t count = 0;
record_t rec;
R_tree_iterator iterator;
for (size_t i = 0; i < count1; i++) {
r.boundary[0] = r.boundary[1] = i * 2 * count2; /* note that filled with even numbers */
for (size_t j = 0; j < count2; j++) {
r.boundary[2] = r.boundary[3] = r.boundary[0] + j;
tree.insert(r, record_t(++count));
}
}
printf("Test tree size: %d\n", (int)tree.number_of_records());
/* Test that tree filled ok */
for (size_t i = 0; i < count1; i++) {
for (size_t j = 0; j < count2; j++) {
r.boundary[0] = r.boundary[1] = i * 2 * count2;
r.boundary[2] = r.boundary[3] = r.boundary[0] + j;
if (!tree.search(r, SOP_BELONGS, iterator)) {
fail("Integrity check failed (1)", "false");
}
for (size_t k = 0; k <= j; k++) {
if (!iterator.next()) {
fail("Integrity check failed (2)", "false");
}
}
if (iterator.next()) {
fail("Integrity check failed (3)", "true");
}
r.boundary[0] = r.boundary[1] = (i * 2 + 1) * count2;
r.boundary[2] = r.boundary[3] = r.boundary[0] + j;
if (tree.search(r, SOP_BELONGS, iterator)) {
fail("Integrity check failed (4)", "true");
}
}
}
/* Print 7 elems closest to coordinate basis */
{
static rectangle_t basis;
printf("--> ");
if (!tree.search(basis, SOP_NEIGHBOR, iterator)) {
fail("Integrity check failed (5)", "false");
}
for (int i = 0; i < 7; i++) {
rec = iterator.next();
if (rec == 0) {
fail("Integrity check failed (6)", "false");
}
printf("%p ", rec);
}
printf("\n");
}
/* Print 7 elems closest to the point [(count1-1)*count2*2, (count1-1)*count2*2] */
{
printf("<-- ");
r.boundary[0] = r.boundary[1] = r.boundary[2] = r.boundary[3] = (count1-1)*count2*2;
if (!tree.search(r, SOP_NEIGHBOR, iterator)) {
fail("Integrity check failed (5)", "false");
}
for (int i = 0; i < 7; i++) {
rec = iterator.next();
if (rec == 0) {
fail("Integrity check failed (6)", "false");
}
printf("%p ", rec);
}
printf("\n");
}
/* Test strict besize_ts */
for (size_t i = 0; i < count1; i++) {
for (size_t j = 0; j < count2; j++) {
r.boundary[0] = r.boundary[1] = i * 2 * count2;
r.boundary[2] = r.boundary[3] = r.boundary[0] + j;
if (!tree.search(r, SOP_STRICT_BELONGS, iterator) && j != 0) {
fail("Integrity check failed (7)", "false");
}
for (size_t k = 0; k < j; k++) {
if (!iterator.next()) {
fail("Integrity check failed (8)", "false");
}
}
if (iterator.next()) {
fail("Integrity check failed (9)", "true");
}
r.boundary[0] = r.boundary[1] = (i * 2 + 1) * count2;
r.boundary[2] = r.boundary[3] = r.boundary[0] + j;
if (tree.search(r, SOP_STRICT_BELONGS, iterator)) {
fail("Integrity check failed (10)", "true");
}
}
}
/* Test strict contains */
for (size_t i = 0; i < count1; i++) {
for (size_t j = 0; j < count2; j++) {
r.boundary[0] = r.boundary[1] = i * 2 * count2;
r.boundary[2] = r.boundary[3] = r.boundary[0] + j;
if (!tree.search(r, SOP_STRICT_CONTAINS, iterator) && j != count2-1) {
fail("Integrity check failed (11)", "false");
}
for (size_t k = j; k < count2-1; k++) {
if (!iterator.next()) {
fail("Integrity check failed (12)", "false");
}
}
if (iterator.next()) {
fail("Integrity check failed (13)", "true");
}
r.boundary[0] = r.boundary[1] = (i * 2 + 1) * count2;
r.boundary[2] = r.boundary[3] = r.boundary[0] + j;
if (tree.search(r, SOP_STRICT_CONTAINS, iterator)) {
fail("Integrity check failed (14)", "true");
}
}
}
tree.purge();
footer();
}
static void
itr_invalidate_check()
{
header();
const size_t test_size = 300;
const size_t max_delete_count = 100;
const size_t max_insert_count = 200;
const size_t attempt_count = 100;
struct R_tree_iterator iterators[test_size];
R_tree tree(page_alloc, page_free);
rectangle_t r;
/* invalidation during deletion */
srand(0);
for (size_t attempt = 0; attempt < attempt_count; attempt++) {
size_t del_pos = rand() % test_size;
size_t del_cnt = rand() % max_delete_count + 1;
if (del_pos + del_cnt > test_size) {
del_cnt = test_size - del_pos;
}
R_tree tree(page_alloc, page_free);
for (size_t i = 0; i < test_size; i++) {
r.boundary[0] = r.boundary[1] = r.boundary[2] = r.boundary[3] = i;
tree.insert(r, record_t(i+1));
}
r.boundary[0] = r.boundary[1] = 0;
r.boundary[2] = r.boundary[3] = test_size;
tree.search(r, SOP_BELONGS, iterators[0]);
if (!iterators[0].next()) {
fail("Integrity check failed (15)", "false");
}
for (size_t i = 1; i < test_size; i++) {
iterators[i] = iterators[i - 1];
if (!iterators[i].next()) {
fail("Integrity check failed (16)", "false");
}
}
for (size_t i = del_pos; i < del_pos + del_cnt; i++) {
r.boundary[0] = r.boundary[1] = r.boundary[2] = r.boundary[3] = i;
if (!tree.remove(r, record_t(i+1))) {
fail("Integrity check failed (17)", "false");
}
}
for (size_t i = 0; i < test_size; i++) {
if (iterators[i].next()) {
fail("Iterator was not invalidated (18)", "true");
}
}
}
/* invalidation during insertion */
srand(0);
for (size_t attempt = 0; attempt < attempt_count; attempt++) {
size_t ins_pos = rand() % test_size;
size_t ins_cnt = rand() % max_insert_count + 1;
R_tree tree(page_alloc, page_free);
for (size_t i = 0; i < test_size; i++) {
r.boundary[0] = r.boundary[1] = r.boundary[2] = r.boundary[3] = i;
tree.insert(r, record_t(i+1));
}
r.boundary[0] = r.boundary[1] = 0;
r.boundary[2] = r.boundary[3] = test_size;
tree.search(r, SOP_BELONGS, iterators[0]);
if (!iterators[0].next()) {
fail("Integrity check failed (19)", "false");
}
for (size_t i = 1; i < test_size; i++) {
iterators[i] = iterators[i - 1];
if (!iterators[0].next()) {
fail("Integrity check failed (20)", "false");
}
}
for (size_t i = ins_pos; i < ins_pos + ins_cnt; i++) {
r.boundary[0] = r.boundary[1] = r.boundary[2] = r.boundary[3] = i;
tree.insert(r, record_t(test_size + i - ins_pos + 1));
}
for (size_t i = 0; i < test_size; i++) {
if (iterators[i].next()) {
fail("Iterator was not invalidated (22)", "true");
}
}
}
footer();
}
int
main(void)
{
itr_check();
itr_invalidate_check();
if (page_count != 0) {
fail("memory leak!", "false");
}
}
*** itr_check ***
Test tree size: 50000
--> 0x5 0x4 0x3 0x2 0x1 0xa 0x9
<-- 0xc34c 0xc34d 0xc34e 0xc34f 0xc350 0xc34b 0xc34a
*** itr_check: done ***
*** itr_invalidate_check ***
*** itr_invalidate_check: done ***
\ No newline at end of file
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