/*
* RBTreeTest.cc
*
* Created on: Mar 22, 2017
* Author: Michal Simon
*
************************************************************************
* EOS - the CERN Disk Storage System *
* Copyright (C) 2016 CERN/Switzerland *
* *
* This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation, either version 3 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see .*
************************************************************************/
#include "gtest/gtest.h"
#include
#include
#include "fusex/data/rbtree.hh"
class RBTreeTest
{
public:
static void Populate(rbtree& tree)
{
srand(time(NULL));
for (int i = 0; i < 1000; ++i) {
int k = rand() % 1000 + 1;
std::stringstream ss;
ss << k;
tree.insert(k, ss.str());
}
for (int i = 0; i < 200; ++i) {
int k = rand() % 1000 + 1;
tree.erase(k);
}
}
static std::pair TestRBInvariant(const rbtree&
tree)
{
return TestRBInvariant(tree.tree_root);
}
static std::pair TestRBInvariant(const
std::unique_ptr< node_t >& root)
{
// base case
if (!root) {
return std::make_pair(true, 0);
}
int black = 0;
if (root->colour == RED) {
// RED node cannot have RED children
if ((root->left && root->left->colour == RED) || (root->right &&
root->right->colour == RED)) {
return std::make_pair(false, -1);
}
} else {
black += 1;
}
std::pair l = TestRBInvariant(root->left);
std::pair r = TestRBInvariant(root->right);
// both sub trees have to be valid red-black trees
if (!l.first || !r.first) {
return std::make_pair(false, -1);
}
// the 'black' high of both sub-trees has to be the same
if (l.second != r.second) {
return std::make_pair(false, -1);
}
return std::make_pair(true, l.second + black);
}
static std::pair GetMax(const
std::unique_ptr< node_t >& root)
{
if (!root) {
return std::make_pair(false, 0);
}
node_t* node = root.get();
while (node->right) {
node = node->right.get();
}
return std::make_pair(true, node->key);
}
static std::pair GetMin(const
std::unique_ptr< node_t >& root)
{
if (!root) {
return std::make_pair(false, 0);
}
node_t* node = root.get();
while (node->left) {
node = node->left.get();
}
return std::make_pair(true, node->key);
}
static bool TestBSTInvariant(const rbtree& tree)
{
return TestBSTInvariant(tree.tree_root);
}
static bool TestBSTInvariant(const std::unique_ptr< node_t >&
root)
{
if (!root) {
return true;
}
if (!TestBSTInvariant(root->left) || !TestBSTInvariant(root->right)) {
return false;
}
auto right_min = GetMin(root->right);
// check if the right-sub tree exists
if (right_min.first)
// all the items in right sub-tree have to be greater than root
if (right_min.second <= root->key) {
return false;
}
auto left_max = GetMax(root->left);
// check if the left sub-tree exists
if (left_max.first)
// all the items in left sub-tree have to be smaller than root
if (left_max.second >= root->key) {
return false;
}
return true;
}
};
TEST(RBTree, TestInvariant)
{
rbtree tree;
RBTreeTest::Populate(tree);
auto ret = RBTreeTest::TestRBInvariant(tree);
ASSERT_TRUE(ret.first);
}
TEST(RBTree, TestBSTInvariant)
{
rbtree tree;
RBTreeTest::Populate(tree);
ASSERT_TRUE(RBTreeTest::TestBSTInvariant(tree));
}
TEST(RBTree, TestIterator)
{
rbtree tree;
tree.insert(1, "1");
tree.insert(2, "2");
tree.insert(3, "3");
tree.insert(4, "4");
tree.insert(5, "5");
tree.insert(6, "6");
tree.insert(7, "7");
tree.insert(8, "8");
tree.insert(9, "9");
int i = 1;
rbtree::iterator itr;
for (itr = tree.begin(); itr != tree.end(); ++itr) {
ASSERT_EQ(itr->key, i);
++i;
}
}