mirror of https://github.com/coolaj86/fizzbuzz.git
369 lines
8.7 KiB
C++
Executable File
369 lines
8.7 KiB
C++
Executable File
#include <string>
|
|
#include <iostream>
|
|
#include <set>
|
|
#include <list>
|
|
#include <algorithm>
|
|
#include <vector>
|
|
#include <time.h>
|
|
|
|
#include "tut/tut.hpp"
|
|
#include "BST.h"
|
|
|
|
#define NULL_NODE (static_cast<BSTNode*>(NULL))
|
|
|
|
using namespace std;
|
|
|
|
bool gDoRemove = false;
|
|
extern std::string gCurrentTest;
|
|
|
|
string generateKey();
|
|
void CheckSubTreeOrder(BSTNode * bNode, bool isLeftLess);
|
|
void CheckBSTOrder(BST & bst);
|
|
void CompareSubTrees(BSTNode* subTree1, BSTNode* subTree2);
|
|
void CompareTrees(BST & bst1, BST & bst2);
|
|
|
|
struct BSTTest
|
|
{
|
|
public:
|
|
BSTTest() : BSTTestSize(6379)
|
|
{
|
|
}
|
|
|
|
void initBST(BST& bst)
|
|
{
|
|
for(int i = 0; i < BSTTestSize; ++i)
|
|
{
|
|
string key = generateKey();
|
|
if(chosen.find(key) != chosen.end())
|
|
{
|
|
--i;
|
|
}
|
|
else
|
|
{
|
|
chosen.insert(key);
|
|
BSTNode * curNode = bst.Insert(key);
|
|
tut::ensure("Insert() - Return NULL when the value was not in the tree", curNode != NULL);
|
|
tut::ensure_equals("Insert() - Returned a value which was different from the one entered", curNode->GetValue(), key);
|
|
tut::ensure_equals("Insert() - The size of the BST is not the size of the elements inserted", bst.GetSize(), (int)chosen.size());
|
|
|
|
curNode = bst.Insert(key);
|
|
tut::ensure_equals("Instert() - Did not return NULL when the value was in the tree", curNode, NULL_NODE);
|
|
tut::ensure_equals("Insert() - Size incremented on duplicate insertion", bst.GetSize(), (int)chosen.size());
|
|
}
|
|
}
|
|
}
|
|
|
|
std::string generateKey()
|
|
{
|
|
char key[9];
|
|
int digit = '9'-'0'+1;
|
|
int upCase = 'Z'-'A'+digit+1;
|
|
int top = 'z'-'a'+upCase+1;
|
|
for(int i = 0; i < 9; i++){
|
|
int val = rand()%top;
|
|
if(val < digit){
|
|
key[i] = val + '0';
|
|
}
|
|
else if(val < upCase){
|
|
key[i] = val - digit + 'A';
|
|
}
|
|
else{
|
|
key[i] = val - upCase + 'a';
|
|
}
|
|
}//end for i
|
|
string result(key);
|
|
return result;
|
|
}
|
|
|
|
const int BSTTestSize;
|
|
set<string> chosen;
|
|
};
|
|
|
|
|
|
void CheckSubTreeOrder(BSTNode * bNode, bool isLeftLess){
|
|
if(bNode != NULL){
|
|
string val = bNode->GetValue();
|
|
BSTNode * lNode = bNode->GetLeft();
|
|
BSTNode * rNode = bNode->GetRight();
|
|
if(isLeftLess){
|
|
if(lNode != NULL){
|
|
tut::ensure("The left node had a greater value when it should have been less", lNode->GetValue() <= val);
|
|
CheckSubTreeOrder(lNode, isLeftLess);
|
|
}
|
|
if(rNode != NULL){
|
|
tut::ensure("The right node had a lesser value when it should have been less", rNode->GetValue() >= val);
|
|
CheckSubTreeOrder(rNode, isLeftLess);
|
|
}
|
|
}
|
|
else{
|
|
if(lNode != NULL){
|
|
tut::ensure("The left node had a lesser value when it should have been less", lNode->GetValue() >= val);
|
|
CheckSubTreeOrder(lNode, isLeftLess);
|
|
}
|
|
if(rNode != NULL){
|
|
tut::ensure("The right node had a greater value when it should have been less", rNode->GetValue() <= val);
|
|
CheckSubTreeOrder(rNode, isLeftLess);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void CheckBSTOrder(BST & bst){
|
|
BSTNode * bNode = bst.GetRoot();
|
|
if(bNode != NULL){
|
|
bool isLeftLess = true;
|
|
BSTNode * left = bNode->GetLeft();
|
|
if(left != NULL){
|
|
if(left->GetValue() > bNode->GetValue()){
|
|
isLeftLess = false;
|
|
}
|
|
}
|
|
else{
|
|
BSTNode * right = bNode->GetRight();
|
|
if(right != NULL){
|
|
if(right->GetValue() < bNode->GetValue()){
|
|
isLeftLess = false;
|
|
}
|
|
}
|
|
}
|
|
CheckSubTreeOrder(bNode->GetLeft(), isLeftLess);
|
|
CheckSubTreeOrder(bNode->GetRight(), isLeftLess);
|
|
}
|
|
}
|
|
|
|
void CompareSubTrees(BSTNode* subTree1, BSTNode* subTree2){
|
|
tut::ensure_not("SubTrees are not equal", (subTree1 && !subTree2) || (subTree2 && !subTree1));
|
|
if(subTree1 != NULL){
|
|
tut::ensure_not("Nodes point to the same memory", subTree1 == subTree2 || subTree1 == subTree2);
|
|
tut::ensure_equals("Node values are not equal", subTree1->GetValue(), subTree2->GetValue());
|
|
CompareSubTrees(subTree1->GetLeft(),subTree2->GetLeft());
|
|
CompareSubTrees(subTree1->GetRight(),subTree2->GetRight());
|
|
}
|
|
}
|
|
|
|
void CompareTrees(BST & bst1, BST & bst2){
|
|
tut::ensure_equals("Sizes of the two trees are not equal", bst1.GetSize(), bst2.GetSize());
|
|
CompareSubTrees(bst1.GetRoot(), bst2.GetRoot());
|
|
}
|
|
|
|
namespace tut
|
|
{
|
|
namespace
|
|
{
|
|
typedef tut::test_group<BSTTest> tGroup;
|
|
typedef tGroup::object tObject;
|
|
tGroup group("BST");
|
|
}
|
|
|
|
template<>
|
|
template<>
|
|
void tObject::test<1> ()
|
|
{
|
|
set_test_name("Default Constructor");
|
|
gCurrentTest = get_test_name();
|
|
BST bst;
|
|
|
|
// Root should be NULL
|
|
tut::ensure_equals("Default Constructor - Root is not NULL", bst.GetRoot(), NULL_NODE);
|
|
|
|
// Size should be 0
|
|
tut::ensure_equals("Default Constructor - Size is not 0", bst.GetSize(), 0);
|
|
tut::ensure("Default Constructor - Says it's not empty", bst.IsEmpty());
|
|
}
|
|
|
|
template<>
|
|
template<>
|
|
void tObject::test<2> ()
|
|
{
|
|
set_test_name("Insert");
|
|
gCurrentTest = get_test_name();
|
|
BST bst;
|
|
initBST(bst);
|
|
|
|
CheckBSTOrder(bst);
|
|
}
|
|
|
|
template<>
|
|
template<>
|
|
void tObject::test<3> ()
|
|
{
|
|
set_test_name("GetSize");
|
|
gCurrentTest = get_test_name();
|
|
BST bst;
|
|
initBST(bst);
|
|
tut::ensure_equals("GetSize() - The size of the BST is not the size of the elements inserted", bst.GetSize(), static_cast<int>(chosen.size()));
|
|
}
|
|
|
|
template<>
|
|
template<>
|
|
void tObject::test<4> ()
|
|
{
|
|
set_test_name("Find");
|
|
gCurrentTest = get_test_name();
|
|
BST bst;
|
|
initBST(bst);
|
|
|
|
set<string>::iterator iter;
|
|
for(iter = chosen.begin(); iter != chosen.end(); iter++){
|
|
BSTNode * curNode = bst.Find(*iter);
|
|
tut::ensure("Find() - Node not found when it should have been", curNode != NULL);
|
|
tut::ensure_equals("Find() - Returned a node with the wrong value", curNode->GetValue(), *iter);
|
|
}
|
|
|
|
for(int i = 0; i < BSTTestSize; i++){
|
|
string key = generateKey();
|
|
if(chosen.find(key) == chosen.end()){
|
|
BSTNode * curNode = bst.Find(key);
|
|
tut::ensure("Find() - Returned a node when the value was not in the tree", curNode == NULL);
|
|
}
|
|
else{
|
|
--i;
|
|
}
|
|
}
|
|
}
|
|
|
|
template<>
|
|
template<>
|
|
void tObject::test<5> ()
|
|
{
|
|
set_test_name("Copy Constructor");
|
|
gCurrentTest = get_test_name();
|
|
BST bst;
|
|
BST emptyCopyBst(bst);
|
|
initBST(bst);
|
|
|
|
BST fullCopyBst(bst);
|
|
CompareTrees(bst,fullCopyBst);
|
|
}
|
|
|
|
template<>
|
|
template<>
|
|
void tObject::test<6> ()
|
|
{
|
|
set_test_name("Assignment Operator");
|
|
gCurrentTest = get_test_name();
|
|
BST bst;
|
|
|
|
//Assign empty to empty
|
|
BST emptyBst;
|
|
emptyBst = bst;
|
|
CompareTrees(bst,emptyBst);
|
|
|
|
//Return type check
|
|
tut::ensure ("Assignment Operator: Testing return value", &emptyBst == &(emptyBst = bst));
|
|
|
|
//Assign empty to full
|
|
initBST(bst);
|
|
BST fullBst;
|
|
fullBst = bst;
|
|
CompareTrees(bst,fullBst);
|
|
|
|
//Assign to self
|
|
fullBst = fullBst;
|
|
|
|
//Assign full to empty
|
|
BST& nowEmpty = fullBst;
|
|
nowEmpty = emptyBst;
|
|
CompareTrees(emptyBst, nowEmpty);
|
|
}
|
|
|
|
template<>
|
|
template<>
|
|
void tObject::test<7> ()
|
|
{
|
|
set_test_name("Clear");
|
|
gCurrentTest = get_test_name();
|
|
BST bst;
|
|
initBST(bst);
|
|
|
|
BST bst2(bst);
|
|
|
|
BST bst3;
|
|
bst3 = bst;
|
|
|
|
bst.Clear();
|
|
CompareTrees(bst3, bst2);
|
|
bst3.Clear();
|
|
|
|
BSTNode* curNode = bst.GetRoot();
|
|
tut::ensure_equals("GetRoot() - Returned a node after the tree was cleared", curNode, NULL_NODE);
|
|
}
|
|
|
|
template<>
|
|
template<>
|
|
void tObject::test<8> ()
|
|
{
|
|
set_test_name ("IsEmpty");
|
|
gCurrentTest = get_test_name();
|
|
BST bst;
|
|
initBST(bst);
|
|
|
|
BST bst2(bst);
|
|
bst = bst2;
|
|
BST bst3;
|
|
bst3 = bst;
|
|
bst.Clear();
|
|
bst3.Clear();
|
|
|
|
tut::ensure_not("IsEmpty() - The Tree is not empty", bst2.IsEmpty());
|
|
bst = bst2; //for the remove stage
|
|
bst2.Clear();
|
|
tut::ensure("IsEmpty() - The Tree is Empty", bst2.IsEmpty());
|
|
tut::ensure_equals("GetSize() - The Tree returned a non 0 size after it was cleared", bst2.GetSize(), 0);
|
|
}
|
|
|
|
#if TEST_BST_REMOVE
|
|
template<>
|
|
template<>
|
|
void tObject::test<9> ()
|
|
{
|
|
set_test_name ("Remove");
|
|
gCurrentTest = get_test_name();
|
|
if(!gDoRemove)
|
|
return;
|
|
|
|
set<string>::iterator iter;
|
|
BSTNode * curNode;
|
|
|
|
BST bst;
|
|
initBST(bst);
|
|
|
|
BST bst2(bst);
|
|
bst = bst2;
|
|
BST bst3;
|
|
bst3 = bst;
|
|
bst.Clear();
|
|
bst3.Clear();
|
|
|
|
bst = bst2;
|
|
bst2.Clear();
|
|
|
|
for(int i = 0; i < BSTTestSize; i++){
|
|
string key = generateKey();
|
|
if(chosen.find(key) == chosen.end()){
|
|
ensure_not("Remove() - Returned true when the value was not in the tree", bst.Remove(key));
|
|
}
|
|
else{
|
|
--i;
|
|
}
|
|
}
|
|
|
|
BSTNode * root = bst.GetRoot();
|
|
chosen.erase(root->GetValue());
|
|
bst.Remove(root->GetValue());
|
|
root = NULL;
|
|
|
|
vector<string> randomv(chosen.begin(), chosen.end());
|
|
random_shuffle(randomv.begin(), randomv.end());
|
|
|
|
for(vector<string>::iterator vIter = randomv.begin(); vIter != randomv.end(); vIter++){
|
|
ensure("Remove() - Returned false whe nthe value was in the tree", bst.Remove(*vIter));
|
|
ensure_not("Remove() - Returned true when the value was not in the tree", bst.Remove(*vIter));
|
|
|
|
}
|
|
ensure_equals("Remove() - Size of tree is not 0 after removing all values", bst.GetSize(), 0);
|
|
ensure_equals("GetRoot() - Did not return NULL after removing all values", bst.GetRoot(), NULL_NODE);
|
|
}
|
|
#endif
|
|
}
|