mirror of https://github.com/coolaj86/fizzbuzz.git
added BYU CS240 Linked-List and Binary Search Tree assignments
This commit is contained in:
parent
73e777202d
commit
a3dadf8af0
|
@ -0,0 +1,256 @@
|
|||
#include "BST.h"
|
||||
|
||||
//! BSTNode implements a binary search tree node
|
||||
|
||||
//! Constructor
|
||||
BSTNode::BSTNode(const std::string & v) :
|
||||
value(v), left(NULL), right(NULL)
|
||||
{
|
||||
// Sounds good to me
|
||||
return;
|
||||
}
|
||||
|
||||
//! Copy Constructor DEEP COPY and does not free memory
|
||||
BSTNode::BSTNode(const BSTNode & other):
|
||||
value(other.value), left(NULL), right(NULL)
|
||||
{
|
||||
// Recurse me! Yay!
|
||||
value = other.value;
|
||||
if (other.left)
|
||||
left = new BSTNode(*(other.left));
|
||||
if (other.right)
|
||||
right = new BSTNode(*(other.right));
|
||||
return;
|
||||
}
|
||||
|
||||
//! Delete Destructor frees memory
|
||||
BSTNode::~BSTNode()
|
||||
{
|
||||
Clear();
|
||||
return;
|
||||
}
|
||||
|
||||
void BSTNode::Clear()
|
||||
{
|
||||
if (left) {
|
||||
delete left;
|
||||
left = NULL;
|
||||
}
|
||||
if (right) {
|
||||
delete right;
|
||||
right = NULL;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
void BSTNode::Copy(const BSTNode & other)
|
||||
{
|
||||
// Recurse me! Yay!
|
||||
value = other.value;
|
||||
if (other.left)
|
||||
left = new BSTNode(*(other.left));
|
||||
if (other.right)
|
||||
right = new BSTNode(*(other.right));
|
||||
return;
|
||||
}
|
||||
|
||||
//! Insert string into tree with sort by comparison
|
||||
BSTNode * BSTNode::Insert(const std::string & v)
|
||||
{
|
||||
if (NULL == &v || Find(v))
|
||||
return NULL;
|
||||
|
||||
// Greater to the right
|
||||
if (0 < value.compare(v))
|
||||
if (NULL == right)
|
||||
return right = new BSTNode(v);
|
||||
else
|
||||
return right->Insert(v);
|
||||
// Lesser to the left
|
||||
else if (0 > value.compare(v))
|
||||
if (NULL == left)
|
||||
return left = new BSTNode(v);
|
||||
else
|
||||
return left->Insert(v);
|
||||
// Same??? Can't happen
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//! Find string in tree with sort by comparison
|
||||
BSTNode * BSTNode::Find(const std::string & v)
|
||||
{
|
||||
// Equal means this
|
||||
if (0 == value.compare(v))
|
||||
return this;
|
||||
|
||||
// Greater to the right
|
||||
else if (0 < value.compare(v) && NULL != right)
|
||||
return right->Find(v);
|
||||
|
||||
// Lesser to the left
|
||||
else if (0 > value.compare(v) && NULL != left)
|
||||
return left->Find(v);
|
||||
|
||||
// Nothing matches
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//! Read-only public methods for use by clients of the BST class
|
||||
const std::string & BSTNode::GetValue()
|
||||
{
|
||||
return value;
|
||||
}
|
||||
|
||||
BSTNode * BSTNode::GetLeft()const
|
||||
{
|
||||
return left;
|
||||
}
|
||||
|
||||
BSTNode * BSTNode::GetRight()const
|
||||
{
|
||||
return right;
|
||||
}
|
||||
|
||||
//! Assignment operator makes a DEEP COPY and does not free memory
|
||||
BSTNode & BSTNode::operator=(const BSTNode & other)
|
||||
{
|
||||
if (this == &other)
|
||||
return *this;
|
||||
|
||||
Clear();
|
||||
Copy(other);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
//! BST implements a binary search tree
|
||||
|
||||
//! No-arg constructor. Initializes an empty BST
|
||||
BST::BST() :
|
||||
root(NULL), size(0)
|
||||
{
|
||||
// Empty as can be
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
//! Copy constructor. Makes a complete copy of its argument
|
||||
BST::BST(const BST & other)
|
||||
{
|
||||
Copy(other);
|
||||
return;
|
||||
}
|
||||
|
||||
//! Copy method. Makes a complete copy of its argument
|
||||
void BST::Copy(const BST & other)
|
||||
{
|
||||
if (this == &other)
|
||||
return;
|
||||
|
||||
size = other.GetSize();
|
||||
if(other.root)
|
||||
root = (new BSTNode(*(other.root)));
|
||||
else
|
||||
root=NULL;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
//! Destructor
|
||||
BST::~BST()
|
||||
{
|
||||
Clear();
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
//! Assignment operator. Makes a complete copy of its argument
|
||||
//! @return Reference to oneself
|
||||
BST & BST::operator=(const BST & other)
|
||||
{
|
||||
if (this == &other)
|
||||
return *this;
|
||||
|
||||
Clear();
|
||||
Copy(other);
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
//! @return a pointer to the root node of the tree, or NULL if the tree is empty.
|
||||
//! @note This is useful for BST clients that need to traverse the tree.)
|
||||
BSTNode * BST::GetRoot()const
|
||||
{
|
||||
return root;
|
||||
}
|
||||
|
||||
|
||||
//! @return true if the BST is empty, or false if the BST is not empty
|
||||
bool BST::IsEmpty() const
|
||||
{
|
||||
return (NULL == root);
|
||||
}
|
||||
|
||||
|
||||
//! Removes all values from the BST
|
||||
void BST::Clear()
|
||||
{
|
||||
size = 0;
|
||||
if (root)
|
||||
delete root;
|
||||
root = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
//! @return the number of values in the BST
|
||||
int BST::GetSize() const
|
||||
{
|
||||
return size;
|
||||
}
|
||||
|
||||
|
||||
//! Inserts value v into the BST
|
||||
//!
|
||||
//! @param v The new value being inserted
|
||||
//!
|
||||
//! @return a pointer to the newly inserted node, or NULL if v was already
|
||||
//! in the tree (i.e., NULL is used to indicate a duplicate insertion)
|
||||
BSTNode * BST::Insert(const std::string & v)
|
||||
{
|
||||
if (Find(v))
|
||||
return NULL;
|
||||
|
||||
++size;
|
||||
if (root)
|
||||
return root->Insert(v);
|
||||
else
|
||||
return root = new BSTNode(v);
|
||||
}
|
||||
|
||||
|
||||
//! Searches the tree for value v
|
||||
//!
|
||||
//! @param v The new value being searched for
|
||||
//!
|
||||
//! @return a pointer to the node containing v, or NULL if v is not in the tree
|
||||
BSTNode * BST::Find(const std::string & v) const
|
||||
{
|
||||
if (NULL == root)
|
||||
return NULL;
|
||||
else
|
||||
return root->Find(v);
|
||||
}
|
||||
|
||||
|
||||
//! @NOTE: YOU ARE NOT REQUIRED TO IMPLEMENT THE Remove METHOD BELOW
|
||||
//! (BUT YOU CAN IF YOU WANT TO)
|
||||
//!
|
||||
//! Removes value v from the tree
|
||||
//!
|
||||
//! @param v The value being removed from the tree
|
||||
//!
|
||||
//! @return true if v was removed from the tree, or false if v was not in the tree
|
||||
//bool Remove(const std::string & v);
|
|
@ -0,0 +1,122 @@
|
|||
#ifndef CS240_BST_H
|
||||
#define CS240_BST_H
|
||||
|
||||
#include <string>
|
||||
|
||||
|
||||
//! BSTNode implements a binary search tree node
|
||||
class BSTNode {
|
||||
friend class BST; //!< BST can access private members of BSTNode
|
||||
|
||||
public:
|
||||
|
||||
//! Constructor
|
||||
BSTNode(const std::string &);
|
||||
|
||||
//! Copy Constructor SHALLOW COPY and does not free memory
|
||||
BSTNode(const BSTNode &);
|
||||
|
||||
//! Delete Destructor calls Clear
|
||||
~BSTNode();
|
||||
|
||||
//! Clear recursively deletes nodes
|
||||
void Clear();
|
||||
|
||||
//! Copy recursively copies a node
|
||||
void Copy(const BSTNode &);
|
||||
|
||||
//! Insert sorts on string comparison
|
||||
BSTNode * Insert(const std::string &);
|
||||
|
||||
//! Find does string comparison to find if node exists
|
||||
BSTNode * Find(const std::string &);
|
||||
|
||||
//! Read-only public methods for use by clients of the BST class
|
||||
const std::string & GetValue();
|
||||
|
||||
BSTNode * GetLeft() const;
|
||||
BSTNode * GetRight() const;
|
||||
|
||||
//! Assignment operator makes a SHALLOW COPY and does not free memory
|
||||
//!Feel free to change this function(IE, to a deep copy).
|
||||
BSTNode & operator=(const BSTNode &);
|
||||
|
||||
private:
|
||||
std::string value; //!< value stored in the node
|
||||
BSTNode * left; //!< pointer to the node's left child
|
||||
BSTNode * right; //!< pointer to the node's right child
|
||||
};
|
||||
|
||||
|
||||
//! BST implements a binary search tree
|
||||
class BST {
|
||||
|
||||
public:
|
||||
|
||||
//! No-arg constructor. Initializes an empty BST
|
||||
BST();
|
||||
|
||||
|
||||
//! Copy constructor. Makes a complete copy of its argument
|
||||
BST(const BST &);
|
||||
|
||||
|
||||
//! Destructor
|
||||
~BST();
|
||||
|
||||
//! Copy makes DEEP Copy
|
||||
void Copy(const BST &);
|
||||
|
||||
//! Assignment operator. Makes a complete copy of its argument
|
||||
//! @return Reference to oneself
|
||||
BST& operator =(const BST &);
|
||||
|
||||
|
||||
//! @return a pointer to the root node of the tree, or NULL if the tree is empty.
|
||||
//! @note This is useful for BST clients that need to traverse the tree.)
|
||||
BSTNode * GetRoot()const;
|
||||
|
||||
//! @return true if the BST is empty, or false if the BST is not empty
|
||||
bool IsEmpty() const;
|
||||
|
||||
//! Removes all values from the BST
|
||||
void Clear();
|
||||
|
||||
//! @return the number of values in the BST
|
||||
int GetSize() const;
|
||||
|
||||
|
||||
//! Inserts value v into the BST
|
||||
//!
|
||||
//! @param v The new value being inserted
|
||||
//!
|
||||
//! @return a pointer to the newly inserted node, or NULL if v was already
|
||||
//! in the tree (i.e., NULL is used to indicate a duplicate insertion)
|
||||
BSTNode * Insert(const std::string &);
|
||||
|
||||
|
||||
//! Searches the tree for value v
|
||||
//!
|
||||
//! @param v The new value being searched for
|
||||
//!
|
||||
//! @return a pointer to the node containing v, or NULL if v is not in the tree
|
||||
BSTNode * Find(const std::string &) const;
|
||||
|
||||
|
||||
//! @NOTE: YOU ARE NOT REQUIRED TO IMPLEMENT THE Remove METHOD BELOW
|
||||
//! (BUT YOU CAN IF YOU WANT TO)
|
||||
//!
|
||||
//! Removes value v from the tree
|
||||
//!
|
||||
//! @param v The value being removed from the tree
|
||||
//!
|
||||
//! @return true if v was removed from the tree, or false if v was not in the tree
|
||||
//bool Remove(const std::string & v);
|
||||
|
||||
private:
|
||||
BSTNode * root;
|
||||
int size;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
|
@ -0,0 +1,272 @@
|
|||
#include "LinkedList.h"
|
||||
|
||||
//! LLNode implements a doubly-linked list node
|
||||
//! Constructor
|
||||
LLNode::LLNode(const std::string & v, LLNode * p, LLNode * n) :
|
||||
value(v), prev(p), next(n)
|
||||
{
|
||||
// Good enough
|
||||
return;
|
||||
}
|
||||
|
||||
//! Copy Constructor SHALLOW COPY and does not free memory
|
||||
//!Feel free to change this function(IE, to a deep copy).
|
||||
LLNode::LLNode(const LLNode & other)
|
||||
{
|
||||
if (this == &other)
|
||||
return;
|
||||
|
||||
// It makes sense (in my mind) for this to be shallow and disconnected
|
||||
value = other.value;
|
||||
prev = NULL; //other.prev;
|
||||
next = NULL; //other.next;
|
||||
}
|
||||
|
||||
//! Read-only public methods for use by clients of the LinkedList class
|
||||
const std::string & LLNode::GetValue() const
|
||||
{
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
LLNode * LLNode::GetPrevious() const
|
||||
{
|
||||
return prev;
|
||||
}
|
||||
|
||||
|
||||
LLNode * LLNode::GetNext() const
|
||||
{
|
||||
return next;
|
||||
}
|
||||
|
||||
//! Assignment operator makes a SHALLOW COPY and does not free memory
|
||||
//!Feel free to change this function(IE, to a deep copy).
|
||||
LLNode & LLNode::operator=(const LLNode & other)
|
||||
{
|
||||
if(this != &other)
|
||||
{
|
||||
value = other.value;
|
||||
prev = other.prev;
|
||||
next = other.next;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//! LinkedList implements a doubly-linked list
|
||||
|
||||
//! No-arg constructor. Initializes an empty linked list
|
||||
LinkedList::LinkedList()
|
||||
{
|
||||
length = 0;
|
||||
head = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
//! Copy constructor. Makes a complete copy of its argument
|
||||
LinkedList::LinkedList(const LinkedList & other)
|
||||
{
|
||||
Copy(other);
|
||||
return;
|
||||
}
|
||||
|
||||
//! Copy make a DEEP copy. Makes a complete copy of its argument
|
||||
void LinkedList::Copy(const LinkedList & other)
|
||||
{
|
||||
if (this == &other)
|
||||
return;
|
||||
if (NULL == other.head) {
|
||||
head = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
LLNode * tmpCopy = NULL;
|
||||
LLNode * oHead = NULL;
|
||||
|
||||
length = other.GetSize();
|
||||
oHead = other.head;
|
||||
|
||||
head = new LLNode(*oHead);
|
||||
oHead = oHead->next;
|
||||
tmpCopy = head;
|
||||
while (oHead != NULL) {
|
||||
tmpCopy->next = new LLNode(*oHead);
|
||||
tmpCopy->next->prev = tmpCopy;
|
||||
tmpCopy = tmpCopy->next;
|
||||
oHead = oHead->next;
|
||||
}
|
||||
}
|
||||
|
||||
//! Destructor
|
||||
LinkedList::~LinkedList()
|
||||
{
|
||||
Clear();
|
||||
}
|
||||
|
||||
//! Assignment operator. Makes a complete copy of its argument
|
||||
//! @return A reference to oneself
|
||||
LinkedList& LinkedList::operator =(const LinkedList & other)
|
||||
{
|
||||
if (this == &other)
|
||||
return *this;
|
||||
|
||||
Clear();
|
||||
Copy(other);
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
//! @return true if the list is empty, or false if the list is not empty
|
||||
bool LinkedList::IsEmpty() const
|
||||
{
|
||||
return (0 == length);
|
||||
}
|
||||
|
||||
|
||||
//! Removes all values from the list
|
||||
void LinkedList::Clear() {
|
||||
LLNode * tmpCopy = NULL;
|
||||
if (NULL == head)
|
||||
return;
|
||||
|
||||
///*
|
||||
while (NULL != head) {
|
||||
tmpCopy = head;
|
||||
head = head->next;
|
||||
delete tmpCopy;
|
||||
}//*/
|
||||
|
||||
length = 0;
|
||||
head = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
//! @return the number of values in the list
|
||||
int LinkedList::GetSize() const
|
||||
{
|
||||
return length;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//! @return a pointer to the first node in the list, or NULL if the list is empty
|
||||
LLNode * LinkedList::GetFirst()const
|
||||
{
|
||||
return head;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//! @returns a pointer to the last node in the list, or NULL if the list is empty
|
||||
LLNode * LinkedList::GetLast()const
|
||||
{
|
||||
if (IsEmpty())
|
||||
return NULL;
|
||||
|
||||
LLNode * tail;
|
||||
tail = head;
|
||||
while (NULL != tail->next) {
|
||||
tail = tail->next;
|
||||
}
|
||||
return tail;
|
||||
}
|
||||
|
||||
|
||||
//! Inserts value v into the list after node n
|
||||
//!
|
||||
//! @param v The new value being inserted
|
||||
//! @param n A node that is already in the list after which the new node should
|
||||
//! be inserted.
|
||||
//! If n is NULL, the new node should be inserted at the beginning of the list.
|
||||
//!
|
||||
//! @return a pointer to the newly inserted node
|
||||
LLNode * LinkedList::Insert(const std::string & v, LLNode * n)
|
||||
{
|
||||
if (NULL == &v || Find(v, NULL))
|
||||
return NULL;
|
||||
|
||||
++length;
|
||||
|
||||
LLNode * tmpCopy;
|
||||
|
||||
if (NULL == n) {
|
||||
tmpCopy = new LLNode(v, NULL, NULL);
|
||||
if (NULL != head)
|
||||
head->prev = tmpCopy;
|
||||
tmpCopy->next = head;
|
||||
return head = tmpCopy;
|
||||
}
|
||||
|
||||
tmpCopy = new LLNode(v, n, n->next);
|
||||
if (NULL != n->next)
|
||||
n->next->prev = tmpCopy;
|
||||
tmpCopy->prev = n;
|
||||
tmpCopy->next = n->next;
|
||||
n->next = tmpCopy;
|
||||
|
||||
return tmpCopy;
|
||||
}
|
||||
|
||||
|
||||
//! Searches for the first occurrence of value v that appears in the list
|
||||
//! after node n
|
||||
//!
|
||||
//! @param v The value being searched for
|
||||
//! @param n The node in the list after which the search should begin.
|
||||
//! If n is NULL, the list should be searched from the beginning.
|
||||
//!
|
||||
//! @return a pointer to the node containing v, or NULL if v is not found
|
||||
LLNode * LinkedList::Find(const std::string & v, LLNode * n) const
|
||||
{
|
||||
LLNode * result;
|
||||
if (NULL != n)
|
||||
result = n->next;
|
||||
else
|
||||
result = head;
|
||||
|
||||
while (NULL != result) {
|
||||
if (0 == result->value.compare(v))
|
||||
return result;
|
||||
result = result->next;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
//! Removes node n from the list
|
||||
//!
|
||||
//! @param n The node being removed from the list
|
||||
void LinkedList::Remove(LLNode * n)
|
||||
{
|
||||
if (NULL == n)
|
||||
return;
|
||||
|
||||
--length;
|
||||
|
||||
if (NULL != n->prev)
|
||||
n->prev->next = n->next;
|
||||
else {
|
||||
head = n->next; // Could be NULL
|
||||
if (NULL != head)
|
||||
head->prev = NULL;
|
||||
}
|
||||
if (NULL != n->next)
|
||||
n->next->prev = n->prev;
|
||||
|
||||
delete n;
|
||||
n = NULL;
|
||||
|
||||
return;
|
||||
}
|
||||
|
|
@ -0,0 +1,118 @@
|
|||
#ifndef CS240_LINKED_LIST_H
|
||||
#define CS240_LINKED_LIST_H
|
||||
|
||||
#include <string>
|
||||
|
||||
//! LLNode implements a doubly-linked list node
|
||||
class LLNode {
|
||||
friend class LinkedList; //!< LinkedList can access private members of LLNode
|
||||
public:
|
||||
|
||||
//! Constructor
|
||||
LLNode(const std::string &, LLNode *, LLNode *);
|
||||
|
||||
//! Copy Constructor SHALLOW COPY and does not free memory
|
||||
//!Feel free to change this function(IE, to a deep copy).
|
||||
LLNode(const LLNode &);
|
||||
|
||||
//! Read-only public methods for use by clients of the LinkedList class
|
||||
const std::string & GetValue() const;
|
||||
|
||||
|
||||
LLNode * GetPrevious() const;
|
||||
|
||||
|
||||
LLNode * GetNext() const;
|
||||
|
||||
//! Assignment operator makes a SHALLOW COPY and does not free memory
|
||||
//!Feel free to change this function(IE, to a deep copy).
|
||||
LLNode & operator=(const LLNode &);
|
||||
|
||||
private:
|
||||
std::string value; //!< value stored in the node
|
||||
LLNode * prev; //!< pointer to previous node in the list
|
||||
LLNode * next; //!< pointer to next node in the list
|
||||
};
|
||||
|
||||
|
||||
//! LinkedList implements a doubly-linked list
|
||||
class LinkedList
|
||||
{
|
||||
public:
|
||||
|
||||
//! No-arg constructor. Initializes an empty linked list
|
||||
LinkedList();
|
||||
|
||||
|
||||
//! Copy constructor. Makes a complete copy of its argument
|
||||
LinkedList(const LinkedList & other);
|
||||
|
||||
|
||||
//! Destructor
|
||||
~LinkedList();
|
||||
|
||||
//! Copy make a DEEP copy. Makes a complete copy of its argument
|
||||
void Copy(const LinkedList &);
|
||||
|
||||
//! Assignment operator. Makes a complete copy of its argument
|
||||
//! @return A reference to oneself
|
||||
LinkedList& operator =(const LinkedList & other);
|
||||
|
||||
|
||||
//! @return true if the list is empty, or false if the list is not empty
|
||||
bool IsEmpty() const;
|
||||
|
||||
|
||||
//! Removes all values from the list
|
||||
void Clear();
|
||||
|
||||
|
||||
//! @return the number of values in the list
|
||||
int GetSize() const;
|
||||
|
||||
|
||||
|
||||
//! @return a pointer to the first node in the list, or NULL if the list is empty
|
||||
LLNode * GetFirst() const;
|
||||
|
||||
|
||||
|
||||
//! @returns a pointer to the last node in the list, or NULL if the list is empty
|
||||
LLNode * GetLast() const;
|
||||
|
||||
|
||||
//! Inserts value v into the list after node n
|
||||
//!
|
||||
//! @param v The new value being inserted
|
||||
//! @param n A node that is already in the list after which the new node should
|
||||
//! be inserted.
|
||||
//! If n is NULL, the new node should be inserted at the beginning of the list.
|
||||
//!
|
||||
//! @return a pointer to the newly inserted node
|
||||
LLNode * Insert(const std::string & v, LLNode * n);
|
||||
|
||||
|
||||
//! Searches for the first occurrence of value v that appears in the list
|
||||
//! after node n
|
||||
//!
|
||||
//! @param v The value being searched for
|
||||
//! @param n The node in the list after which the search should begin.
|
||||
//! If n is NULL, the list should be searched from the beginning.
|
||||
//!
|
||||
//! @return a pointer to the node containing v, or NULL if v is not found
|
||||
LLNode * Find(const std::string & v, LLNode * n) const;
|
||||
|
||||
|
||||
//! Removes node n from the list
|
||||
//!
|
||||
//! @param n The node being removed from the list
|
||||
void Remove(LLNode * n);
|
||||
|
||||
private:
|
||||
int length;
|
||||
LLNode * head;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
all: test
|
||||
|
||||
bst: obj/BST.o
|
||||
obj/BST.o: BST.h BST.cpp
|
||||
g++ -c -o obj/BST.o BST.cpp
|
||||
|
||||
ll: obj/LinkedList.o LinkedList.h LinkedList.cpp
|
||||
g++ -c -o obj/LinkedList.o LinkedList.cpp
|
||||
|
||||
test: bst ll colexp passoff
|
||||
./colexp part2
|
||||
|
||||
clean:
|
||||
rm *.o obj/*.o -rf
|
|
@ -0,0 +1,12 @@
|
|||
About
|
||||
====
|
||||
|
||||
I wrote `LinkedList.cpp` and `BST.cpp`. Parts of the `*.h` were provided by BYU as the documentation for the project.
|
||||
|
||||
The test program was created by BYU, but I don't see a copyright so I assume I'm safe to include it.
|
||||
|
||||
Build on Ubuntu 10.04
|
||||
====
|
||||
|
||||
sudo apt-get install libboost-all-dev valgrind
|
||||
make
|
|
@ -0,0 +1,3 @@
|
|||
#!/usr/bin/env sh
|
||||
echo "Running the Collections Test Passoff"
|
||||
make -f ./passoff/Makefile $@
|
|
@ -0,0 +1,153 @@
|
|||
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
||||
<html><head>
|
||||
|
||||
|
||||
|
||||
<meta name="generator" content="HTML Tidy for Linux/x86 (vers 6 November 2007), see www.w3.org"><title>Collections Part I and II</title>
|
||||
|
||||
|
||||
<meta http-equiv="content-type" content="text/html; charset=us-ascii">
|
||||
<meta http-equiv="content-style-type" content="text/css">
|
||||
<link rel="stylesheet" type="text/css" media="screen,projection" href="collections_files/style.css"></head><body>
|
||||
<div class="box">
|
||||
<h1>Computer Science 240 :: Advanced Programming</h1>
|
||||
</div>
|
||||
|
||||
<div class="main">
|
||||
<div class="center">
|
||||
<h2>Collections</h2>
|
||||
</div>
|
||||
<hr>
|
||||
|
||||
<p><b>NOTE: This project is divided into two parts (Part I and
|
||||
Part II). For the Programming Exam you only need to complete
|
||||
Part I. Part II will be completed after the Programming
|
||||
Exam.</b></p>
|
||||
|
||||
<h3>Overview</h3>
|
||||
|
||||
<p>Most non-trivial programs use data structures to store and
|
||||
access information. Common examples are lists, stacks, queues,
|
||||
trees, etc. Data structures are also called "collections"
|
||||
because they are used to manage groups (or collections) of
|
||||
objects. For this assignment you will write two collection
|
||||
classes in C++. You will write a class named
|
||||
<tt>LinkedList</tt> that implements a doubly-linked list and a
|
||||
class named <tt>BST</tt> that implements a binary search tree.
|
||||
Unlike the previous projects, you will not be asked to deliver
|
||||
a complete running program. Rather, the deliverables for this
|
||||
project are just the <tt>LinkedList</tt> and <tt>BST</tt>
|
||||
classes. To pass off your project, we will take your classes
|
||||
and compile and link them with a test program that will
|
||||
exercise your code and verify that it works. It is your
|
||||
responsibility to test your code and make sure that it works
|
||||
before passing off.</p>
|
||||
|
||||
<h3>Project Files</h3>
|
||||
|
||||
<p>Header files for the <tt>LinkedList</tt> and <tt>BST</tt>
|
||||
classes are provided at the following links:</p>
|
||||
|
||||
<p><a href="http://students.cs.byu.edu/%7Ecs240ta/winter2008/projects/collections/LinkedList.h">LinkedList.h</a></p>
|
||||
|
||||
<p><a href="http://students.cs.byu.edu/%7Ecs240ta/winter2008/projects/collections/BST.h">BST.h</a></p>
|
||||
|
||||
<p>Your task is to implement all of the methods on the
|
||||
<span style="font-family: "Courier New";">LinkedList</span> and
|
||||
<span style="font-family: "Courier New";">BST</span> classes
|
||||
according to the comments in the header files. You should place
|
||||
your <span style="font-family: "Courier New";">LinkedList</span>
|
||||
and <span style="font-family: "Courier New";">BST</span>
|
||||
implementations in files named <span style="font-family: "Courier New";">LinkedList.cpp</span> and
|
||||
<span style="font-family: "Courier New";">BST.cpp</span>,
|
||||
respectively. You should not modify the public interfaces of
|
||||
the classes. If you do, the test program that will be used to
|
||||
pass off your code will not compile. You may (and probably
|
||||
should) modify the <span style="font-family: "Courier New";">.h</span> files to add private
|
||||
method and variable declarations, but your method bodies should
|
||||
go in the <span style="font-family: "Courier New";">.cpp</span>
|
||||
files.</p>
|
||||
|
||||
<p>The test program will assume that your files are named
|
||||
<span style="font-family: "Courier New";">LinkedList.h</span>,
|
||||
<span style="font-family: "Courier New";">LinkedList.cpp</span>,
|
||||
<span style="font-family: "Courier New";">BST.h</span>, and
|
||||
<span style="font-family: "Courier New";">BST.cpp</span> Since
|
||||
Linux file names are case sensitive, capitalization does
|
||||
matter.</p>
|
||||
|
||||
<h3>Restrictions</h3>
|
||||
|
||||
<p>For this project you <u>are</u> allowed to use the C++
|
||||
string class defined in the <span style="font-family: "Courier New";"><string></span> header file
|
||||
(in fact, you must use it to make your code work).</p>
|
||||
|
||||
<p>You <u>are not</u> allowed to use the classes and functions
|
||||
from the Standard Template Library (vector, list, map, set,
|
||||
etc.). Specifically, the following header files may not be
|
||||
used:</p>
|
||||
|
||||
<ul>
|
||||
<li><algorithm></li>
|
||||
|
||||
<li><deque></li>
|
||||
|
||||
<li><list></li>
|
||||
|
||||
<li><map></li>
|
||||
|
||||
<li><queue></li>
|
||||
|
||||
<li><set></li>
|
||||
|
||||
<li><stack></li>
|
||||
|
||||
<li><vector></li>
|
||||
</ul>
|
||||
|
||||
<h3>Part I</h3>
|
||||
|
||||
<p>Implement all of the methods on the <span style="font-family: "Courier New";">LinkedList</span> and <span style="font-family: "Courier New";">BST</span> classes.</p>
|
||||
|
||||
<p>For Part I your code will not be tested for memory
|
||||
management errors. That will come in Part II.</p>
|
||||
|
||||
<h3>Part II</h3>
|
||||
|
||||
<p>Ensure that your code does not contain any memory management
|
||||
errors, as described in the <i>Memory Management Errors</i>
|
||||
section of the Project I specification. The TAs will use
|
||||
<span style="font-family: "Courier New";">valgrind</span> to
|
||||
check your code for memory-related errors when you pass off.
|
||||
You should run <span style="font-family: "Courier New";">valgrind</span> on your code and
|
||||
fix any reported bugs before attempting to pass off.</p>
|
||||
|
||||
<p>Not all memory errors are your fault and there are cases of false positives. We offer a <a href="http://students.cs.byu.edu/%7Ecs240ta/util_docs/string.supp">file</a> to suppress these for you.</p>
|
||||
</div>
|
||||
<div class="menu">
|
||||
<div class="nav">
|
||||
<div>Main Menu</div>
|
||||
<dl>
|
||||
<dd><a href="http://students.cs.byu.edu/%7Ecs240ta/winter2008/">Home Page</a></dd>
|
||||
</dl><dl>
|
||||
<dt><a>Class Information</a></dt>
|
||||
<dd><a href="http://students.cs.byu.edu/%7Ecs240ta/winter2008/info/policies.php">Policies</a></dd>
|
||||
<dd><a href="http://students.cs.byu.edu/%7Ecs240ta/winter2008/info/schedule.php">Schedule</a></dd>
|
||||
<dd><a href="http://students.cs.byu.edu/%7Ecs240ta/winter2008/projects/">Projects</a></dd>
|
||||
<dd><a href="http://students.cs.byu.edu/%7Ecs240ta/winter2008/tutorials/">Tutorials</a></dd>
|
||||
<dd><a href="http://students.cs.byu.edu/%7Ecs240ta/winter2008/TA/">TA Schedule</a></dd>
|
||||
</dl><dl>
|
||||
<dt><a>Help</a></dt>
|
||||
<dd><a href="http://gotapi.com/ccpp" target="_blank">C++ API</a></dd>
|
||||
<dd><a href="http://boost.org/libs/libraries.htm" target="_blank">Boost API</a></dd>
|
||||
<dd><a href="http://students.cs.byu.edu/%7Ecs240ta/winter2008/tutorials/boost.php">Boost?</a></dd>
|
||||
<dd><a href="http://students.cs.byu.edu/%7Ecs240ta/util_docs/" target="_blank">CS 240 Utils API</a></dd>
|
||||
<dd><a href="http://students.cs.byu.edu/%7Ecs240ta/winter2008/resources/">Resources</a></dd>
|
||||
</dl><dl>
|
||||
<dt><a>Contact</a></dt>
|
||||
<dd><a href="http://blackboard.byu.edu/">CS 240 TA's</a></dd>
|
||||
<dd><a href="mailto:rodham@cs.byu.edu">Dr. Ken Rodham</a></dd>
|
||||
<dd><a href="mailto:egbert@cs.byu.edu">Dr. Parris Egbert</a></dd>
|
||||
</dl>
|
||||
</div>
|
||||
</div></body></html>
|
|
@ -0,0 +1,522 @@
|
|||
@charset "iso-8859-1";
|
||||
body {
|
||||
margin: 2ex;
|
||||
color: #000;
|
||||
font-family: tahoma, verdana, sans, arial, helvetica, sans-serif;
|
||||
background: #e8e8e8;
|
||||
max-width: 120ex;
|
||||
}
|
||||
.box {
|
||||
font-size: 90%;
|
||||
background: #7f97b0 url(../images/hr.png) repeat-x;
|
||||
margin-left: 26ex;
|
||||
|
||||
color: white;
|
||||
border-color: black;
|
||||
border-style: solid;
|
||||
border-width: 1px 1px 1px 1px;
|
||||
height: 5ex;
|
||||
}
|
||||
.box h1 {
|
||||
font-weight: normal;
|
||||
font-size: 150%;
|
||||
float: left;
|
||||
margin: 0px 1ex;
|
||||
padding: .5ex 0ex 0ex 0ex;
|
||||
letter-spacing: 1px;
|
||||
}
|
||||
.box div {
|
||||
font-weight: normal;
|
||||
font-size: 108%;
|
||||
height: 3.5ex;
|
||||
text-align: right;
|
||||
padding: 1.2ex 1ex 0ex 0ex;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.hr_1 {
|
||||
font-size: 90%;
|
||||
background: url(../images/hr_3.png) #446 repeat-x;
|
||||
color: inherit;
|
||||
margin-left: 26ex;
|
||||
margin-top: -1px;
|
||||
height: 2ex;
|
||||
border-color: #000;
|
||||
border-width: 1px 1px 1px 1px;
|
||||
border-style: solid;
|
||||
}
|
||||
.nav div.hr_2 {
|
||||
border-top-width: 0;
|
||||
font-size: 90%;
|
||||
background: url(../images/hr_3.png) #446 repeat-x;
|
||||
color: inherit;
|
||||
margin: 0ex 0ex 2ex;
|
||||
height: 2ex;
|
||||
}
|
||||
|
||||
.menu {
|
||||
background: #fff url(../images/back.png) repeat-y;
|
||||
color: inherit;
|
||||
left: 2ex;
|
||||
padding-bottom: 0.5ex;
|
||||
width: 22ex;
|
||||
border: black 1px solid;
|
||||
position: absolute;
|
||||
top: 6.6ex;
|
||||
}
|
||||
|
||||
[class="menu"]{
|
||||
position: fixed;
|
||||
}
|
||||
|
||||
.nav {
|
||||
margin: 0;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.nav span {
|
||||
display: none
|
||||
}
|
||||
|
||||
.nav div {
|
||||
font-weight: bold;
|
||||
font-size: 90%;
|
||||
background: url(../images/hr_2.png) #7f97b0 repeat-x;
|
||||
margin: 0ex 0px 0.5ex;
|
||||
color: #fff;
|
||||
text-align: center;
|
||||
border-style: solid;
|
||||
border-color: #000;
|
||||
border-width: 0px 0px 1px;
|
||||
}
|
||||
|
||||
.nav a {
|
||||
padding-right: 5px;
|
||||
display: block;
|
||||
padding-left: 5px;
|
||||
font-size: 80%;
|
||||
text-align: left;
|
||||
text-decoration: none;
|
||||
color: #000;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.menu .nav a:link, .menu .nav a:visited {
|
||||
padding-right: 5px;
|
||||
display: block;
|
||||
padding-left: 5px;
|
||||
font-size: 80%;
|
||||
text-align: left;
|
||||
text-decoration: none;
|
||||
color: #339;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.nav dt {
|
||||
font-weight: bold;
|
||||
padding-right: 5px;
|
||||
display: block;
|
||||
padding-left: 5px;
|
||||
font-size: 80%;
|
||||
text-align: left;
|
||||
text-decoration: none;
|
||||
color: #339;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.nav dd {
|
||||
margin-left: 0px;
|
||||
padding-left: 0px;
|
||||
}
|
||||
|
||||
.nav dl {
|
||||
margin-top: 0px;
|
||||
margin-bottom: 0.5ex;
|
||||
}
|
||||
|
||||
.menu .nav a:hover {
|
||||
background: url(../images/menuhover.png) repeat-y;
|
||||
text-decoration: none;
|
||||
color: #339;
|
||||
}
|
||||
|
||||
.nav dd a:before {
|
||||
content: " ";
|
||||
}
|
||||
|
||||
.nav dl.links dd a:before {
|
||||
content: "";
|
||||
}
|
||||
|
||||
.nav a.indent {
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
.nav a.indent:before {
|
||||
content: " ";
|
||||
}
|
||||
|
||||
.nav span.menuspace {
|
||||
display: block;
|
||||
border-width: 0;
|
||||
height: .4em;
|
||||
}
|
||||
|
||||
.nav a.selected {
|
||||
background: url(../images/menuhover.png) repeat-y;
|
||||
color: #000;
|
||||
}
|
||||
|
||||
.main {
|
||||
font-size: 90%;
|
||||
min-height: 61ex;
|
||||
background: #fff;
|
||||
color: inherit;
|
||||
margin: 0ex 0ex 0ex 26ex;
|
||||
border-color: black;
|
||||
border-style: solid;
|
||||
padding: 1ex 2ex 0ex;
|
||||
border-width: 0px 1px 1px 1px;
|
||||
}
|
||||
|
||||
/*.main ul li a:before {
|
||||
content: " ";
|
||||
}*/
|
||||
|
||||
.main ul li p a:before {
|
||||
content: "";
|
||||
}
|
||||
|
||||
img {
|
||||
border-width: 0;
|
||||
vertical-align: bottom;
|
||||
}
|
||||
|
||||
img.screenshot {
|
||||
margin: 0.5em 0em 0.5em 0em;
|
||||
}
|
||||
|
||||
img.down {
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
}
|
||||
|
||||
div.logo {
|
||||
float: right;
|
||||
margin: 15px 0px 0px 10px;
|
||||
}
|
||||
|
||||
div.screenshot-right, div.screenshot-left {
|
||||
border: 1px solid #caccd3;
|
||||
background: #f2f2f8;
|
||||
color: black;
|
||||
padding: 3px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
div.screenshot-right {
|
||||
float: right;
|
||||
margin: 0px 0px 0px 10px;
|
||||
}
|
||||
|
||||
div.screenshot-left {
|
||||
float: left;
|
||||
margin: 0px 10px 5px 0px;
|
||||
}
|
||||
|
||||
div.right {
|
||||
float: right;
|
||||
margin: 0px 0px 0px 10px;
|
||||
}
|
||||
|
||||
div.center {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
|
||||
p.justify {
|
||||
text-align: justify;
|
||||
}
|
||||
|
||||
div.screenshot-left p, div.screenshot-right p {
|
||||
margin-top: 2px;
|
||||
margin-bottom: 0px;
|
||||
font-size: 80%;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
div.logo {
|
||||
margin-top: -2em;
|
||||
}
|
||||
|
||||
a:link, a:visited, a:active {
|
||||
color: #833;
|
||||
/*text-decoration: none;*/
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
color: #c00;
|
||||
background: transparent;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
a.blue {
|
||||
color: #00f;
|
||||
background: transparent;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
hr {
|
||||
border: 0px;
|
||||
border-top: 2px solid #ccccff;
|
||||
height: 0;
|
||||
clear: both;
|
||||
}
|
||||
|
||||
h2.headline {
|
||||
font-size: 130%;
|
||||
margin-bottom: 0.25em;
|
||||
color: #009;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
p {
|
||||
line-height: 1.3em;
|
||||
margin-bottom: 1em;
|
||||
margin-top: 0em;
|
||||
}
|
||||
|
||||
p a, ul.disc a {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-weight: normal;
|
||||
font-size: 150%;
|
||||
color: #7c98a6;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-weight: normal;
|
||||
font-size: 110%;
|
||||
margin-bottom: 0.5em;
|
||||
border-bottom: 1px solid #cccccc;
|
||||
color: #009;
|
||||
background: transparent;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.clear {
|
||||
clear: both;
|
||||
}
|
||||
|
||||
h4 {
|
||||
font-size: 100%;
|
||||
margin-bottom: 1ex;
|
||||
color: #337;
|
||||
background: transparent;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
h5 {
|
||||
margin-bottom: 0.25em;
|
||||
}
|
||||
|
||||
div.indent {
|
||||
margin-left: 3ex;
|
||||
}
|
||||
|
||||
ol {
|
||||
margin-left: 0px;
|
||||
padding-left: 25px;
|
||||
}
|
||||
|
||||
ul {
|
||||
padding-left: 25px;
|
||||
margin-left: 0px;
|
||||
|
||||
font-size: inherit;
|
||||
}
|
||||
|
||||
ul.disc {
|
||||
list-style-type: disc;
|
||||
}
|
||||
|
||||
.strike {
|
||||
text-decoration: line-through;
|
||||
}
|
||||
|
||||
div.rightside {
|
||||
background: #f7f6fb;
|
||||
color: inherit;
|
||||
float: right;
|
||||
padding: 1ex;
|
||||
margin-top: 3ex;
|
||||
width: 30%;
|
||||
border: #9999cc 1px solid;
|
||||
font-size: 90%;
|
||||
}
|
||||
|
||||
div.rightside h3 {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
div.rightside:first-child p {
|
||||
margin-bottom: 0;
|
||||
text-align: justify;
|
||||
}
|
||||
|
||||
table {
|
||||
background-color: #666699;
|
||||
border: gray 0px solid;
|
||||
border-spacing: 1px;
|
||||
color: inherit;
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
|
||||
td {
|
||||
padding-right: 12px;
|
||||
padding-left: 6px;
|
||||
font-size: 90%;
|
||||
background-color: #fff;
|
||||
vertical-align: top;
|
||||
color: #000;
|
||||
}
|
||||
|
||||
th {
|
||||
font-weight: bold;
|
||||
background-color: #666;
|
||||
text-align: left;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.code, kbd, pre, tt, var {
|
||||
font-family: "courier new", "courier", monospace;
|
||||
}
|
||||
|
||||
.keyword {
|
||||
font-style: italic;
|
||||
color: #009;
|
||||
}
|
||||
|
||||
em {
|
||||
font-weight: bold;
|
||||
font-style: normal;
|
||||
color: #C00;
|
||||
}
|
||||
|
||||
pre, .code {
|
||||
background: #f5f8fb;
|
||||
font-weight: bold;
|
||||
color: black;
|
||||
border: 1px dashed #e5e8eb;
|
||||
text-align: left;
|
||||
padding: 0.5ex;
|
||||
display: block;
|
||||
margin: 1em 0em 1em 0em;
|
||||
}
|
||||
|
||||
fieldset {
|
||||
font-size: 90%;
|
||||
border: 1px solid gray;
|
||||
}
|
||||
|
||||
fieldset.left {
|
||||
width: 47%;
|
||||
}
|
||||
|
||||
fieldset.right {
|
||||
float: right;
|
||||
width: 47%;
|
||||
}
|
||||
|
||||
abbr, span.credits {
|
||||
border-bottom: 1px dashed #6666cc;
|
||||
cursor: help;
|
||||
}
|
||||
|
||||
li.newsection {
|
||||
margin-top: 1ex;
|
||||
|
||||
}
|
||||
|
||||
div.downloadinfo {
|
||||
margin-bottom: 1em;
|
||||
background: #f7f6fb;
|
||||
color: inherit;
|
||||
float: right;
|
||||
padding: 1ex;
|
||||
width: 37%;
|
||||
border: #9999cc 1px solid;
|
||||
}
|
||||
|
||||
div.downloadinfo p {
|
||||
text-align: justify;
|
||||
margin-top: 0ex;
|
||||
margin-bottom: 0.6ex;
|
||||
}
|
||||
|
||||
div.news {
|
||||
border-left: 0.8ex #e2e1e6 solid;
|
||||
border-bottom: 1px #d6d5da solid;
|
||||
border-top: 1px #e2e1e6 solid;
|
||||
border-right: 1px #d2d1d6 solid;
|
||||
|
||||
padding-left: 1ex;
|
||||
padding-right: 1ex;
|
||||
margin-bottom: 1ex;
|
||||
margin-top: 2ex;
|
||||
padding-top: 0px;
|
||||
padding-bottom: 2ex;
|
||||
background: #ffffff;
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
div.news h4 {
|
||||
margin-top: 1ex;
|
||||
}
|
||||
|
||||
div.news div.category1 {
|
||||
float: right;
|
||||
font-size: 80%;
|
||||
background: #f8f7fc;
|
||||
color: #666699;
|
||||
|
||||
margin-top: -1ex;
|
||||
padding: 0px 2px 1px 2px;
|
||||
border-width: 1px;
|
||||
border-style: solid;
|
||||
border-color: #eeedf2;
|
||||
}
|
||||
|
||||
div.news p.info {
|
||||
float:left;
|
||||
border-top: 1px solid #e2e1e6;
|
||||
font-size: 80%;
|
||||
width: 42ex;
|
||||
color: #333366;
|
||||
background: transparent;
|
||||
margin-top: -1ex;
|
||||
padding-top: 0px;
|
||||
}
|
||||
|
||||
div.news p.info a:link, div.news p.info a:visited {
|
||||
color: #333366;
|
||||
background: transparent;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
p.newsarchive {
|
||||
text-align: right; font-size: 80%; margin-top: -1ex; padding-top: 0px;
|
||||
}
|
||||
|
||||
div.downloadicon {
|
||||
background: transparent url("../images/download.png") no-repeat top right;
|
||||
min-height: 200px;
|
||||
}
|
||||
|
||||
div.optionsicon {
|
||||
background: transparent url("../images/options.png") no-repeat top right;
|
||||
min-height: 200px;
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
#include "BST.h"
|
||||
#include <cstdlib>
|
||||
#include <iostream>
|
||||
#include <stdlib.h>
|
||||
#include <string>
|
||||
#include <cstring>
|
||||
|
||||
int main(int argc, char * argv[]) {
|
||||
std::string str;
|
||||
str.append("AJ");
|
||||
std::cout << "okay" << std::endl;
|
||||
BST * bst = new BST();
|
||||
bst->Insert(str);
|
||||
std::cout << bst->GetRoot()->GetValue() << std::endl;
|
||||
BST * bstCopy = new BST(*bst);
|
||||
std::cout << bstCopy->GetRoot()->GetValue() << std::endl;
|
||||
}
|
|
@ -0,0 +1,65 @@
|
|||
SUPPRESIONS=./passoff/coll.supp
|
||||
PASSOFF_DIR=./passoff
|
||||
STUDENT_DIR = .
|
||||
|
||||
CC = g++
|
||||
CFLAGS = -I./ -Wall -Winit-self -Wmissing-include-dirs -Wextra -Wfloat-equal -c -ggdb
|
||||
LFLAGS = -o
|
||||
LIB = -lboost_program_options -lboost_filesystem -lboost_iostreams
|
||||
|
||||
TESTR_BIN = $(STUDENT_DIR)/test_runner
|
||||
TESTR_SRC = $(PASSOFF_DIR)/test_runner.cpp $(PASSOFF_DIR)/test_ll.cpp $(PASSOFF_DIR)/test_bst.cpp
|
||||
TESTR_OBJ = $(foreach obj, $(TESTR_SRC:.cpp=.o), $(addprefix $(STUDENT_DIR)/,$(shell basename $(obj))))
|
||||
|
||||
STUDENT_SRC = $(STUDENT_DIR)/LinkedList.cpp $(STUDENT_DIR)/BST.cpp
|
||||
STUDENT_OBJ = $(STUDENT_SRC:.cpp=.o)
|
||||
|
||||
all: help
|
||||
|
||||
help:
|
||||
@ echo -e "Accepted Targets"
|
||||
@ echo -e "\tpart1 - Test with no memory check, auto-cleans"
|
||||
@ echo -e "\tpart2 - Test with memory check, auto-cleans"
|
||||
@ echo -e ""
|
||||
@ echo -e "\tnomem - Test with no memory check"
|
||||
@ echo -e "\tmem - Test with memory check"
|
||||
@ echo -e "\tdebug - Run the test with gdb"
|
||||
@ echo -e "\t$(TESTR_BIN) - Compile the executable"
|
||||
@ echo -e "\tclean - Clean the build"
|
||||
|
||||
part1: nomem clean
|
||||
|
||||
part2: mem clean
|
||||
|
||||
mem: $(TESTR_BIN)
|
||||
- time valgrind --tool=memcheck --leak-check=yes --show-reachable=yes --suppressions=$(SUPPRESIONS) $(TESTR_BIN)
|
||||
|
||||
|
||||
nomem: $(TESTR_BIN)
|
||||
- time $(TESTR_BIN)
|
||||
|
||||
debug: $(TESTR_BIN)
|
||||
gdb $(TESTR_BIN)
|
||||
|
||||
|
||||
clean:
|
||||
rm -f $(TESTR_BIN)
|
||||
rm -f $(STUDENT_OBJ)
|
||||
rm -f $(TESTR_OBJ)
|
||||
|
||||
$(TESTR_BIN): $(TESTR_OBJ) $(STUDENT_OBJ)
|
||||
$(CC) $(TESTR_OBJ) $(STUDENT_OBJ) $(LIB) $(LFLAGS) $(TESTR_BIN)
|
||||
|
||||
#Makefile Debugging
|
||||
#Target to print any variable, can be added to the dependencies of any other target
|
||||
#Userfule flags for make, -d, -p, -n
|
||||
print-%: ; @$(error $* is $($*) ($(value $*)) (from $(origin $*)))
|
||||
|
||||
#Support
|
||||
%.o: $(PASSOFF_DIR)/%.cpp
|
||||
$(CC) $(CFLAGS) $< $(LFLAGS) $@
|
||||
|
||||
%.o: %.cpp
|
||||
$(CC) $(CFLAGS) $< $(LFLAGS) $@
|
||||
|
||||
# DO NOT DELETE THIS LINE --
|
|
@ -0,0 +1,661 @@
|
|||
{
|
||||
Dynamic Linker Bug
|
||||
Memcheck:Cond
|
||||
fun:_dl_relocate_object
|
||||
fun:dl_main
|
||||
fun:_dl_sysdep_start
|
||||
fun:_dl_start
|
||||
obj:/lib/ld-2.6.so
|
||||
}
|
||||
{
|
||||
<insert a suppression name here>
|
||||
Memcheck:Cond
|
||||
fun:strlen
|
||||
fun:_ZNSsC1EPKcRKSaIcE
|
||||
fun:_Z11generateKeyv
|
||||
fun:_Z14TestLinkedListb
|
||||
fun:main
|
||||
}
|
||||
{
|
||||
<insert a suppression name here>
|
||||
Memcheck:Cond
|
||||
fun:_ZNKSs7compareERKSs
|
||||
fun:_ZStneIcSt11char_traitsIcESaIcEEbRKSbIT_T0_T1_ES8_
|
||||
fun:_Z14TestLinkedListb
|
||||
fun:main
|
||||
}
|
||||
{
|
||||
<insert a suppression name here>
|
||||
Memcheck:Cond
|
||||
fun:_ZNKSs7compareERKSs
|
||||
fun:_ZStneIcSt11char_traitsIcESaIcEEbRKSbIT_T0_T1_ES8_
|
||||
fun:_Z14TestLinkedListb
|
||||
fun:main
|
||||
}
|
||||
{
|
||||
<insert a suppression name here>
|
||||
Memcheck:Cond
|
||||
fun:_ZNKSs7compareERKSs
|
||||
fun:_ZStneIcSt11char_traitsIcESaIcEEbRKSbIT_T0_T1_ES8_
|
||||
fun:_Z12CompareListsRK10LinkedListRSt4listISsSaISsEE
|
||||
fun:_Z14TestLinkedListb
|
||||
fun:main
|
||||
}
|
||||
{
|
||||
<insert a suppression name here>
|
||||
Memcheck:Cond
|
||||
fun:_ZNKSs7compareERKSs
|
||||
fun:_ZStneIcSt11char_traitsIcESaIcEEbRKSbIT_T0_T1_ES8_
|
||||
fun:_Z12CompareListsRK10LinkedListRSt4listISsSaISsEE
|
||||
fun:_Z14TestLinkedListb
|
||||
fun:main
|
||||
}
|
||||
{
|
||||
<insert a suppression name here>
|
||||
Memcheck:Cond
|
||||
fun:_ZNKSs7compareERKSs
|
||||
fun:_ZStneIcSt11char_traitsIcESaIcEEbRKSbIT_T0_T1_ES8_
|
||||
fun:_Z12CompareListsRK10LinkedListRSt4listISsSaISsEE
|
||||
fun:_Z14TestLinkedListb
|
||||
fun:main
|
||||
}
|
||||
{
|
||||
<insert a suppression name here>
|
||||
Memcheck:Cond
|
||||
fun:_ZNKSs7compareERKSs
|
||||
fun:_ZStneIcSt11char_traitsIcESaIcEEbRKSbIT_T0_T1_ES8_
|
||||
fun:_Z12CompareListsRK10LinkedListRSt4listISsSaISsEE
|
||||
fun:_Z14TestLinkedListb
|
||||
fun:main
|
||||
}
|
||||
{
|
||||
<insert a suppression name here>
|
||||
Memcheck:Cond
|
||||
fun:_ZNKSs7compareERKSs
|
||||
fun:_ZStneIcSt11char_traitsIcESaIcEEbRKSbIT_T0_T1_ES8_
|
||||
fun:_Z12CompareListsRK10LinkedListRSt4listISsSaISsEE
|
||||
fun:_Z14TestLinkedListb
|
||||
fun:main
|
||||
}
|
||||
{
|
||||
<insert a suppression name here>
|
||||
Memcheck:Cond
|
||||
fun:_ZNKSs7compareERKSs
|
||||
fun:_ZSteqIcSt11char_traitsIcESaIcEEbRKSbIT_T0_T1_ES8_
|
||||
fun:_ZNK10LinkedList4FindERKSsP6LLNode
|
||||
fun:_Z14TestLinkedListb
|
||||
fun:main
|
||||
}
|
||||
{
|
||||
<insert a suppression name here>
|
||||
Memcheck:Cond
|
||||
fun:_ZNKSs7compareERKSs
|
||||
fun:_ZStneIcSt11char_traitsIcESaIcEEbRKSbIT_T0_T1_ES8_
|
||||
fun:_Z14TestLinkedListb
|
||||
fun:main
|
||||
}
|
||||
{
|
||||
<insert a suppression name here>
|
||||
Memcheck:Cond
|
||||
fun:_ZNKSs7compareERKSs
|
||||
fun:_ZSteqIcSt11char_traitsIcESaIcEEbRKSbIT_T0_T1_ES8_
|
||||
fun:_ZNK10LinkedList4FindERKSsP6LLNode
|
||||
fun:_Z14TestLinkedListb
|
||||
fun:main
|
||||
}
|
||||
{
|
||||
<insert a suppression name here>
|
||||
Memcheck:Cond
|
||||
fun:strlen
|
||||
fun:_ZNSsC1EPKcRKSaIcE
|
||||
fun:_Z11generateKeyv
|
||||
fun:_Z14TestLinkedListb
|
||||
fun:main
|
||||
}
|
||||
{
|
||||
<insert a suppression name here>
|
||||
Memcheck:Cond
|
||||
fun:_ZNKSs7compareERKSs
|
||||
fun:_ZSteqIcSt11char_traitsIcESaIcEEbRKSbIT_T0_T1_ES8_
|
||||
fun:_ZNK10LinkedList4FindERKSsP6LLNode
|
||||
fun:_Z14TestLinkedListb
|
||||
fun:main
|
||||
}
|
||||
{
|
||||
<insert a suppression name here>
|
||||
Memcheck:Cond
|
||||
fun:_ZNKSs7compareERKSs
|
||||
fun:_ZSteqIcSt11char_traitsIcESaIcEEbRKSbIT_T0_T1_ES8_
|
||||
fun:_ZSt6__findISt14_List_iteratorISsESsET_S2_S2_RKT0_St18input_iterator_tag
|
||||
fun:_ZSt4findISt14_List_iteratorISsESsET_S2_S2_RKT0_
|
||||
fun:_Z14TestLinkedListb
|
||||
fun:main
|
||||
}
|
||||
{
|
||||
<insert a suppression name here>
|
||||
Memcheck:Cond
|
||||
fun:_ZNKSs7compareERKSs
|
||||
fun:_ZStneIcSt11char_traitsIcESaIcEEbRKSbIT_T0_T1_ES8_
|
||||
fun:_Z14TestLinkedListb
|
||||
fun:main
|
||||
}
|
||||
{
|
||||
<insert a suppression name here>
|
||||
Memcheck:Cond
|
||||
fun:_ZNKSs7compareERKSs
|
||||
fun:_ZSteqIcSt11char_traitsIcESaIcEEbRKSbIT_T0_T1_ES8_
|
||||
fun:_ZNK10LinkedList4FindERKSsP6LLNode
|
||||
fun:_Z14TestLinkedListb
|
||||
fun:main
|
||||
}
|
||||
{
|
||||
<insert a suppression name here>
|
||||
Memcheck:Cond
|
||||
fun:strlen
|
||||
fun:_ZNSsC1EPKcRKSaIcE
|
||||
fun:_Z11generateKeyv
|
||||
fun:_Z7TestBSTb
|
||||
fun:main
|
||||
}
|
||||
{
|
||||
<insert a suppression name here>
|
||||
Memcheck:Cond
|
||||
fun:_ZNKSs7compareERKSs
|
||||
fun:_ZStneIcSt11char_traitsIcESaIcEEbRKSbIT_T0_T1_ES8_
|
||||
fun:_Z7TestBSTb
|
||||
fun:main
|
||||
}
|
||||
{
|
||||
<insert a suppression name here>
|
||||
Memcheck:Cond
|
||||
fun:_ZNKSs7compareERKSs
|
||||
fun:_ZSteqIcSt11char_traitsIcESaIcEEbRKSbIT_T0_T1_ES8_
|
||||
}
|
||||
{
|
||||
<insert a suppression name here>
|
||||
Memcheck:Cond
|
||||
fun:_ZNKSs7compareERKSs
|
||||
fun:_ZSteqIcSt11char_traitsIcESaIcEEbRKSbIT_T0_T1_ES8_
|
||||
}
|
||||
{
|
||||
<insert a suppression name here>
|
||||
Memcheck:Cond
|
||||
fun:_ZNKSs7compareERKSs
|
||||
fun:_ZStneIcSt11char_traitsIcESaIcEEbRKSbIT_T0_T1_ES8_
|
||||
fun:_Z7TestBSTb
|
||||
fun:main
|
||||
}
|
||||
{
|
||||
<insert a suppression name here>
|
||||
Memcheck:Cond
|
||||
fun:strlen
|
||||
fun:_ZNSsC1EPKcRKSaIcE
|
||||
fun:_Z11generateKeyv
|
||||
fun:_Z7TestBSTb
|
||||
fun:main
|
||||
}
|
||||
{
|
||||
<insert a suppression name here>
|
||||
Memcheck:Cond
|
||||
fun:_ZNKSs7compareERKSs
|
||||
fun:_ZStneIcSt11char_traitsIcESaIcEEbRKSbIT_T0_T1_ES8_
|
||||
}
|
||||
{
|
||||
<insert a suppression name here>
|
||||
Memcheck:Cond
|
||||
fun:strlen
|
||||
fun:_ZNSsC1EPKcRKSaIcE
|
||||
}
|
||||
{
|
||||
<insert a suppression name here>
|
||||
Memcheck:Cond
|
||||
fun:_ZNKSs7compareERKSs
|
||||
fun:_ZStltIcSt11char_traitsIcESaIcEEbRKSbIT_T0_T1_ES8_
|
||||
}
|
||||
{
|
||||
<insert a suppression name here>
|
||||
Memcheck:Cond
|
||||
fun:_ZNKSs7compareERKSs
|
||||
fun:_ZStltIcSt11char_traitsIcESaIcEEbRKSbIT_T0_T1_ES8_
|
||||
}
|
||||
{
|
||||
<insert a suppression name here>
|
||||
Memcheck:Cond
|
||||
fun:_ZNKSs7compareERKSs
|
||||
}
|
||||
{
|
||||
<insert a suppression name here>
|
||||
Memcheck:Cond
|
||||
fun:strlen
|
||||
fun:_ZNSsC1EPKcRKSaIcE
|
||||
fun:_Z11generateKeyv
|
||||
fun:_Z14TestLinkedListb
|
||||
fun:main
|
||||
}
|
||||
{
|
||||
<insert a suppression name here>
|
||||
Memcheck:Cond
|
||||
fun:_ZNKSs7compareERKSs
|
||||
fun:_ZStneIcSt11char_traitsIcESaIcEEbRKSbIT_T0_T1_ES8_
|
||||
fun:_Z14TestLinkedListb
|
||||
fun:main
|
||||
}
|
||||
{
|
||||
<insert a suppression name here>
|
||||
Memcheck:Cond
|
||||
fun:_ZNKSs7compareERKSs
|
||||
fun:_ZStneIcSt11char_traitsIcESaIcEEbRKSbIT_T0_T1_ES8_
|
||||
fun:_Z14TestLinkedListb
|
||||
fun:main
|
||||
}
|
||||
{
|
||||
<insert a suppression name here>
|
||||
Memcheck:Cond
|
||||
fun:_ZNKSs7compareERKSs
|
||||
fun:_ZStneIcSt11char_traitsIcESaIcEEbRKSbIT_T0_T1_ES8_
|
||||
fun:_Z12CompareListsRK10LinkedListRSt4listISsSaISsEE
|
||||
fun:_Z14TestLinkedListb
|
||||
fun:main
|
||||
}
|
||||
{
|
||||
<insert a suppression name here>
|
||||
Memcheck:Cond
|
||||
fun:_ZNKSs7compareERKSs
|
||||
fun:_ZStneIcSt11char_traitsIcESaIcEEbRKSbIT_T0_T1_ES8_
|
||||
fun:_Z12CompareListsRK10LinkedListRSt4listISsSaISsEE
|
||||
fun:_Z14TestLinkedListb
|
||||
fun:main
|
||||
}
|
||||
{
|
||||
<insert a suppression name here>
|
||||
Memcheck:Cond
|
||||
fun:_ZNKSs7compareERKSs
|
||||
fun:_ZStneIcSt11char_traitsIcESaIcEEbRKSbIT_T0_T1_ES8_
|
||||
fun:_Z12CompareListsRK10LinkedListRSt4listISsSaISsEE
|
||||
fun:_Z14TestLinkedListb
|
||||
fun:main
|
||||
}
|
||||
{
|
||||
<insert a suppression name here>
|
||||
Memcheck:Cond
|
||||
fun:_ZNKSs7compareERKSs
|
||||
fun:_ZStneIcSt11char_traitsIcESaIcEEbRKSbIT_T0_T1_ES8_
|
||||
fun:_Z12CompareListsRK10LinkedListRSt4listISsSaISsEE
|
||||
fun:_Z14TestLinkedListb
|
||||
fun:main
|
||||
}
|
||||
{
|
||||
<insert a suppression name here>
|
||||
Memcheck:Cond
|
||||
fun:_ZNKSs7compareERKSs
|
||||
fun:_ZStneIcSt11char_traitsIcESaIcEEbRKSbIT_T0_T1_ES8_
|
||||
}
|
||||
{
|
||||
<insert a suppression name here>
|
||||
Memcheck:Cond
|
||||
fun:_ZNKSs7compareERKSs
|
||||
fun:_ZNK10LinkedList4FindERKSsP6LLNode
|
||||
fun:_Z14TestLinkedListb
|
||||
fun:main
|
||||
}
|
||||
{
|
||||
<insert a suppression name here>
|
||||
Memcheck:Cond
|
||||
fun:_ZNKSs7compareERKSs
|
||||
fun:_ZStneIcSt11char_traitsIcESaIcEEbRKSbIT_T0_T1_ES8_
|
||||
fun:_Z14TestLinkedListb
|
||||
fun:main
|
||||
}
|
||||
{
|
||||
<insert a suppression name here>
|
||||
Memcheck:Cond
|
||||
fun:_ZNKSs7compareERKSs
|
||||
fun:_ZNK10LinkedList4FindERKSsP6LLNode
|
||||
fun:_Z14TestLinkedListb
|
||||
fun:main
|
||||
}
|
||||
{
|
||||
<insert a suppression name here>
|
||||
Memcheck:Cond
|
||||
fun:strlen
|
||||
fun:_ZNSsC1EPKcRKSaIcE
|
||||
fun:_Z11generateKeyv
|
||||
fun:_Z14TestLinkedListb
|
||||
fun:main
|
||||
}
|
||||
{
|
||||
<insert a suppression name here>
|
||||
Memcheck:Cond
|
||||
fun:_ZNKSs7compareERKSs
|
||||
}
|
||||
{
|
||||
<insert a suppression name here>
|
||||
Memcheck:Cond
|
||||
fun:_ZNKSs7compareERKSs
|
||||
fun:_ZSteqIcSt11char_traitsIcESaIcEEbRKSbIT_T0_T1_ES8_
|
||||
}
|
||||
{
|
||||
<insert a suppression name here>
|
||||
Memcheck:Cond
|
||||
fun:_ZNKSs7compareERKSs
|
||||
fun:_ZStneIcSt11char_traitsIcESaIcEEbRKSbIT_T0_T1_ES8_
|
||||
fun:_Z14TestLinkedListb
|
||||
fun:main
|
||||
}
|
||||
{
|
||||
<insert a suppression name here>
|
||||
Memcheck:Cond
|
||||
fun:_ZNKSs7compareERKSs
|
||||
fun:_ZNK10LinkedList4FindERKSsP6LLNode
|
||||
fun:_Z14TestLinkedListb
|
||||
fun:main
|
||||
}
|
||||
{
|
||||
<insert a suppression name here>
|
||||
Memcheck:Cond
|
||||
fun:strlen
|
||||
fun:_ZNSsC1EPKcRKSaIcE
|
||||
fun:_Z11generateKeyv
|
||||
fun:_Z7TestBSTb
|
||||
fun:main
|
||||
}
|
||||
{
|
||||
<insert a suppression name here>
|
||||
Memcheck:Cond
|
||||
fun:_ZNKSs7compareERKSs
|
||||
fun:_ZStneIcSt11char_traitsIcESaIcEEbRKSbIT_T0_T1_ES8_
|
||||
fun:_Z7TestBSTb
|
||||
fun:main
|
||||
}
|
||||
{
|
||||
<insert a suppression name here>
|
||||
Memcheck:Cond
|
||||
fun:_ZNKSs7compareERKSs
|
||||
}
|
||||
{
|
||||
<insert a suppression name here>
|
||||
Memcheck:Cond
|
||||
fun:_ZNKSs7compareERKSs
|
||||
}
|
||||
{
|
||||
<insert a suppression name here>
|
||||
Memcheck:Cond
|
||||
fun:_ZNKSs7compareERKSs
|
||||
}
|
||||
{
|
||||
<insert a suppression name here>
|
||||
Memcheck:Cond
|
||||
fun:_ZNKSs7compareERKSs
|
||||
}
|
||||
{
|
||||
<insert a suppression name here>
|
||||
Memcheck:Cond
|
||||
fun:_ZNKSs7compareERKSs
|
||||
fun:_ZStneIcSt11char_traitsIcESaIcEEbRKSbIT_T0_T1_ES8_
|
||||
fun:_Z7TestBSTb
|
||||
fun:main
|
||||
}
|
||||
{
|
||||
<insert a suppression name here>
|
||||
Memcheck:Cond
|
||||
fun:strlen
|
||||
fun:_ZNSsC1EPKcRKSaIcE
|
||||
fun:_Z11generateKeyv
|
||||
fun:_Z7TestBSTb
|
||||
fun:main
|
||||
}
|
||||
{
|
||||
<insert a suppression name here>
|
||||
Memcheck:Cond
|
||||
fun:_ZNKSs7compareERKSs
|
||||
fun:_ZStneIcSt11char_traitsIcESaIcEEbRKSbIT_T0_T1_ES8_
|
||||
}
|
||||
{
|
||||
<insert a suppression name here>
|
||||
Memcheck:Cond
|
||||
fun:strlen
|
||||
fun:_ZNSsC1EPKcRKSaIcE
|
||||
fun:_Z11generateKeyv
|
||||
fun:_Z7TestBSTb
|
||||
fun:main
|
||||
}
|
||||
{
|
||||
<insert a suppression name here>
|
||||
Memcheck:Cond
|
||||
fun:_ZNKSs7compareERKSs
|
||||
}
|
||||
{
|
||||
<insert a suppression name here>
|
||||
Memcheck:Cond
|
||||
fun:_ZNKSs7compareERKSs
|
||||
fun:_ZStltIcSt11char_traitsIcESaIcEEbRKSbIT_T0_T1_ES8_
|
||||
}
|
||||
{
|
||||
<insert a suppression name here>
|
||||
Memcheck:Cond
|
||||
fun:_ZNKSs7compareERKSs
|
||||
}
|
||||
{
|
||||
<insert a suppression name here>
|
||||
Memcheck:Cond
|
||||
fun:_ZNKSs7compareERKSs
|
||||
}
|
||||
{
|
||||
<insert a suppression name here>
|
||||
Memcheck:Cond
|
||||
fun:strlen
|
||||
fun:_ZNSsC1EPKcRKSaIcE
|
||||
fun:_Z11generateKeyv
|
||||
fun:_Z14TestLinkedListb
|
||||
fun:main
|
||||
}
|
||||
{
|
||||
<insert a suppression name here>
|
||||
Memcheck:Cond
|
||||
fun:_ZNKSs7compareERKSs
|
||||
fun:_ZStneIcSt11char_traitsIcESaIcEEbRKSbIT_T0_T1_ES8_
|
||||
fun:_Z14TestLinkedListb
|
||||
fun:main
|
||||
}
|
||||
{
|
||||
<insert a suppression name here>
|
||||
Memcheck:Cond
|
||||
fun:_ZNKSs7compareERKSs
|
||||
fun:_ZStneIcSt11char_traitsIcESaIcEEbRKSbIT_T0_T1_ES8_
|
||||
fun:_Z14TestLinkedListb
|
||||
fun:main
|
||||
}
|
||||
{
|
||||
<insert a suppression name here>
|
||||
Memcheck:Cond
|
||||
fun:_ZNKSs7compareERKSs
|
||||
fun:_ZStneIcSt11char_traitsIcESaIcEEbRKSbIT_T0_T1_ES8_
|
||||
fun:_Z12CompareListsRK10LinkedListRSt4listISsSaISsEE
|
||||
fun:_Z14TestLinkedListb
|
||||
fun:main
|
||||
}
|
||||
{
|
||||
<insert a suppression name here>
|
||||
Memcheck:Cond
|
||||
fun:_ZNKSs7compareERKSs
|
||||
fun:_ZStneIcSt11char_traitsIcESaIcEEbRKSbIT_T0_T1_ES8_
|
||||
fun:_Z12CompareListsRK10LinkedListRSt4listISsSaISsEE
|
||||
fun:_Z14TestLinkedListb
|
||||
fun:main
|
||||
}
|
||||
{
|
||||
<insert a suppression name here>
|
||||
Memcheck:Cond
|
||||
fun:_ZNKSs7compareERKSs
|
||||
fun:_ZStneIcSt11char_traitsIcESaIcEEbRKSbIT_T0_T1_ES8_
|
||||
fun:_Z12CompareListsRK10LinkedListRSt4listISsSaISsEE
|
||||
fun:_Z14TestLinkedListb
|
||||
fun:main
|
||||
}
|
||||
{
|
||||
<insert a suppression name here>
|
||||
Memcheck:Cond
|
||||
fun:_ZNKSs7compareERKSs
|
||||
fun:_ZStneIcSt11char_traitsIcESaIcEEbRKSbIT_T0_T1_ES8_
|
||||
fun:_Z12CompareListsRK10LinkedListRSt4listISsSaISsEE
|
||||
fun:_Z14TestLinkedListb
|
||||
fun:main
|
||||
}
|
||||
{
|
||||
<insert a suppression name here>
|
||||
Memcheck:Cond
|
||||
fun:_ZNKSs7compareERKSs
|
||||
fun:_ZStneIcSt11char_traitsIcESaIcEEbRKSbIT_T0_T1_ES8_
|
||||
fun:_Z12CompareListsRK10LinkedListRSt4listISsSaISsEE
|
||||
fun:_Z14TestLinkedListb
|
||||
fun:main
|
||||
}
|
||||
{
|
||||
<insert a suppression name here>
|
||||
Memcheck:Cond
|
||||
fun:_ZNKSs7compareERKSs
|
||||
fun:_ZSteqIcSt11char_traitsIcESaIcEEbRKSbIT_T0_T1_ES8_
|
||||
}
|
||||
{
|
||||
<insert a suppression name here>
|
||||
Memcheck:Cond
|
||||
fun:_ZNKSs7compareERKSs
|
||||
fun:_ZStneIcSt11char_traitsIcESaIcEEbRKSbIT_T0_T1_ES8_
|
||||
fun:_Z14TestLinkedListb
|
||||
fun:main
|
||||
}
|
||||
{
|
||||
<insert a suppression name here>
|
||||
Memcheck:Cond
|
||||
fun:_ZNKSs7compareERKSs
|
||||
fun:_ZSteqIcSt11char_traitsIcESaIcEEbRKSbIT_T0_T1_ES8_
|
||||
}
|
||||
{
|
||||
<insert a suppression name here>
|
||||
Memcheck:Cond
|
||||
fun:strlen
|
||||
fun:_ZNSsC1EPKcRKSaIcE
|
||||
fun:_Z11generateKeyv
|
||||
fun:_Z14TestLinkedListb
|
||||
fun:main
|
||||
}
|
||||
{
|
||||
<insert a suppression name here>
|
||||
Memcheck:Cond
|
||||
fun:_ZNKSs7compareERKSs
|
||||
fun:_ZSteqIcSt11char_traitsIcESaIcEEbRKSbIT_T0_T1_ES8_
|
||||
}
|
||||
{
|
||||
<insert a suppression name here>
|
||||
Memcheck:Cond
|
||||
fun:_ZNKSs7compareERKSs
|
||||
fun:_ZSteqIcSt11char_traitsIcESaIcEEbRKSbIT_T0_T1_ES8_
|
||||
fun:_ZSt6__findISt14_List_iteratorISsESsET_S2_S2_RKT0_St18input_iterator_tag
|
||||
fun:_ZSt4findISt14_List_iteratorISsESsET_S2_S2_RKT0_
|
||||
fun:_Z14TestLinkedListb
|
||||
fun:main
|
||||
}
|
||||
{
|
||||
<insert a suppression name here>
|
||||
Memcheck:Cond
|
||||
fun:_ZNKSs7compareERKSs
|
||||
fun:_ZStneIcSt11char_traitsIcESaIcEEbRKSbIT_T0_T1_ES8_
|
||||
fun:_Z14TestLinkedListb
|
||||
fun:main
|
||||
}
|
||||
{
|
||||
<insert a suppression name here>
|
||||
Memcheck:Cond
|
||||
fun:_ZNKSs7compareERKSs
|
||||
fun:_ZSteqIcSt11char_traitsIcESaIcEEbRKSbIT_T0_T1_ES8_
|
||||
}
|
||||
{
|
||||
<insert a suppression name here>
|
||||
Memcheck:Cond
|
||||
fun:strlen
|
||||
fun:_ZNSsC1EPKcRKSaIcE
|
||||
fun:_Z11generateKeyv
|
||||
fun:_Z7TestBSTb
|
||||
fun:main
|
||||
}
|
||||
{
|
||||
<insert a suppression name here>
|
||||
Memcheck:Cond
|
||||
fun:strlen
|
||||
fun:_ZNSsC1EPKcRKSaIcE
|
||||
fun:_Z11generateKeyv
|
||||
fun:_Z7TestBSTb
|
||||
fun:main
|
||||
}
|
||||
{
|
||||
<insert a suppression name here>
|
||||
Memcheck:Cond
|
||||
fun:strlen
|
||||
fun:_ZNSsC1EPKcRKSaIcE
|
||||
fun:_Z11generateKeyv
|
||||
fun:_Z7TestBSTb
|
||||
fun:main
|
||||
}
|
||||
{
|
||||
<insert a suppression name here>
|
||||
Memcheck:Cond
|
||||
fun:bcmp
|
||||
fun:_ZNSt11char_traitsIcE7compareEPKcS2_j
|
||||
fun:_ZSteqIcEN9__gnu_cxx11__enable_ifIXsrSt9__is_charIT_E7__valueEbE6__typeERKSbIS3_St11char_traitsIS3_ESaIS3_EESC_
|
||||
fun:_ZStneIcSt11char_traitsIcESaIcEEbRKSbIT_T0_T1_ES8_
|
||||
fun:_ZN3tut12_GLOBAL__N_113ensure_equalsISsSsEEvPKcRKT0_RKT_
|
||||
fun:_ZN7BSTTest7initBSTER3BST
|
||||
fun:_ZN3tut11test_objectI7BSTTestE4testILi2EEEvv
|
||||
fun:_ZN3tut10test_groupI7BSTTestLi50EE13run_test_seh_EMNS_11test_objectIS1_EEFvvERNS2_11safe_holderIS4_EERSs
|
||||
fun:_ZN3tut10test_groupI7BSTTestLi50EE9run_test_ERKSt17_Rb_tree_iteratorISt4pairIKiMNS_11test_objectIS1_EEFvvEEERNS2_11safe_holderIS7_EE
|
||||
fun:_ZN3tut10test_groupI7BSTTestLi50EE8run_nextEv
|
||||
fun:_ZNK3tut11test_runner23run_all_tests_in_group_ESt23_Rb_tree_const_iteratorISt4pairIKSsPNS_10group_baseEEE
|
||||
fun:_ZNK3tut11test_runner9run_testsEv
|
||||
}
|
||||
{
|
||||
<insert a suppression name here>
|
||||
Memcheck:Cond
|
||||
fun:bcmp
|
||||
fun:_ZNSt11char_traitsIcE7compareEPKcS2_j
|
||||
fun:_ZSteqIcEN9__gnu_cxx11__enable_ifIXsrSt9__is_charIT_E7__valueEbE6__typeERKSbIS3_St11char_traitsIS3_ESaIS3_EESC_
|
||||
fun:_ZNK10LinkedList4FindERKSsP6LLNode
|
||||
fun:_ZN3tut11test_objectI14LinkedListTestE4testILi8EEEvv
|
||||
fun:_ZN3tut10test_groupI14LinkedListTestLi50EE13run_test_seh_EMNS_11test_objectIS1_EEFvvERNS2_11safe_holderIS4_EERSs
|
||||
fun:_ZN3tut10test_groupI14LinkedListTestLi50EE9run_test_ERKSt17_Rb_tree_iteratorISt4pairIKiMNS_11test_objectIS1_EEFvvEEERNS2_11safe_holderIS7_EE
|
||||
fun:_ZN3tut10test_groupI14LinkedListTestLi50EE8run_nextEv
|
||||
fun:_ZNK3tut11test_runner23run_all_tests_in_group_ESt23_Rb_tree_const_iteratorISt4pairIKSsPNS_10group_baseEEE
|
||||
fun:_ZNK3tut11test_runner9run_testsEv
|
||||
fun:_Z3runRKSsi
|
||||
fun:main
|
||||
}
|
||||
{
|
||||
<insert a suppression name here>
|
||||
Memcheck:Cond
|
||||
fun:bcmp
|
||||
fun:_ZNSt11char_traitsIcE7compareEPKcS2_j
|
||||
fun:_ZSteqIcEN9__gnu_cxx11__enable_ifIXsrSt9__is_charIT_E7__valueEbE6__typeERKSbIS3_St11char_traitsIS3_ESaIS3_EESC_
|
||||
fun:_ZSt6__findISt14_List_iteratorISsESsET_S2_S2_RKT0_St18input_iterator_tag
|
||||
fun:_ZSt4findISt14_List_iteratorISsESsET_S2_S2_RKT0_
|
||||
fun:_ZN3tut11test_objectI14LinkedListTestE4testILi9EEEvv
|
||||
fun:_ZN3tut10test_groupI14LinkedListTestLi50EE13run_test_seh_EMNS_11test_objectIS1_EEFvvERNS2_11safe_holderIS4_EERSs
|
||||
fun:_ZN3tut10test_groupI14LinkedListTestLi50EE9run_test_ERKSt17_Rb_tree_iteratorISt4pairIKiMNS_11test_objectIS1_EEFvvEEERNS2_11safe_holderIS7_EE
|
||||
fun:_ZN3tut10test_groupI14LinkedListTestLi50EE8run_nextEv
|
||||
fun:_ZNK3tut11test_runner23run_all_tests_in_group_ESt23_Rb_tree_const_iteratorISt4pairIKSsPNS_10group_baseEEE
|
||||
fun:_ZNK3tut11test_runner9run_testsEv
|
||||
fun:_Z3runRKSsi
|
||||
}
|
||||
{
|
||||
<insert a suppression name here>
|
||||
Memcheck:Cond
|
||||
fun:bcmp
|
||||
fun:_ZNSt11char_traitsIcE7compareEPKcS2_j
|
||||
fun:_ZSteqIcEN9__gnu_cxx11__enable_ifIXsrSt9__is_charIT_E7__valueEbE6__typeERKSbIS3_St11char_traitsIS3_ESaIS3_EESC_
|
||||
fun:_ZN3tut11test_objectI14LinkedListTestE4testILi9EEEvv
|
||||
fun:_ZN3tut10test_groupI14LinkedListTestLi50EE13run_test_seh_EMNS_11test_objectIS1_EEFvvERNS2_11safe_holderIS4_EERSs
|
||||
fun:_ZN3tut10test_groupI14LinkedListTestLi50EE9run_test_ERKSt17_Rb_tree_iteratorISt4pairIKiMNS_11test_objectIS1_EEFvvEEERNS2_11safe_holderIS7_EE
|
||||
fun:_ZN3tut10test_groupI14LinkedListTestLi50EE8run_nextEv
|
||||
fun:_ZNK3tut11test_runner23run_all_tests_in_group_ESt23_Rb_tree_const_iteratorISt4pairIKSsPNS_10group_baseEEE
|
||||
fun:_ZNK3tut11test_runner9run_testsEv
|
||||
fun:_Z3runRKSsi
|
||||
fun:main
|
||||
}
|
|
@ -0,0 +1,368 @@
|
|||
#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
|
||||
}
|
|
@ -0,0 +1,407 @@
|
|||
#include <string>
|
||||
#include <iostream>
|
||||
#include <set>
|
||||
#include <list>
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
#include <time.h>
|
||||
|
||||
#include "tut/tut.hpp"
|
||||
#include "LinkedList.h"
|
||||
|
||||
#define NULL_NODE (static_cast<LLNode*>(NULL))
|
||||
|
||||
using namespace std;
|
||||
|
||||
bool gDoSmall = true;
|
||||
extern std::string gCurrentTest;
|
||||
|
||||
string generateKey();
|
||||
void CompareLists(const LinkedList & aList, list<string> & master);
|
||||
|
||||
struct LinkedListTest
|
||||
{
|
||||
public:
|
||||
LinkedListTest() : LLTestSize((gDoSmall) ? 2827 : 8239)
|
||||
{
|
||||
for(int i = 0; i < LLTestSize; ++i)
|
||||
{
|
||||
string key = generateKey();
|
||||
if(chosen.find(key) != chosen.end())
|
||||
{
|
||||
--i;
|
||||
}
|
||||
else
|
||||
{
|
||||
master.push_back(key);
|
||||
chosen.insert(key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void initList (LinkedList& aList)
|
||||
{
|
||||
list<string>::iterator iter;
|
||||
for(iter = master.begin(); iter != master.end(); ++iter)
|
||||
{
|
||||
LLNode* curNode = aList.Insert(*iter, NULL);
|
||||
tut::ensure ("Insert() - The returned node is NULL", curNode != NULL_NODE);
|
||||
tut::ensure_equals ("Insert() - The returned node had the wrong value", curNode->GetValue(), *iter);
|
||||
}
|
||||
}
|
||||
|
||||
void sortedInitList (LinkedList& aList)
|
||||
{
|
||||
aList.Clear();
|
||||
int count = 0;
|
||||
|
||||
list<string>::iterator iter;
|
||||
for(iter = master.begin(); iter != master.end(); ++iter)
|
||||
{
|
||||
LLNode* curNode = aList.GetLast();
|
||||
while(curNode != NULL && 0 < curNode->GetValue().compare(*iter))
|
||||
{
|
||||
curNode = curNode->GetPrevious();
|
||||
}
|
||||
aList.Insert(*iter, curNode);
|
||||
|
||||
tut::ensure_equals("Insert() - Size != number of elements inserted", aList.GetSize(), ++count);
|
||||
}
|
||||
}
|
||||
|
||||
string generateKey()
|
||||
{
|
||||
static const int kKeyLength = 9;
|
||||
char key[kKeyLength];
|
||||
for (int i = 0; i < kKeyLength; ++i)
|
||||
key[i] = '\0';
|
||||
|
||||
int digit = '9'-'0'+1;
|
||||
int upCase = 'Z'-'A'+digit+1;
|
||||
int top = 'z'-'a'+upCase+1;
|
||||
for(int i = 0; i < kKeyLength; ++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';
|
||||
}
|
||||
}
|
||||
string result(key);
|
||||
return result;
|
||||
}
|
||||
|
||||
const int LLTestSize;
|
||||
|
||||
set<string> chosen;
|
||||
list<string> master;
|
||||
};
|
||||
|
||||
void CompareLists(const LinkedList & aList, list<string> & master){
|
||||
const LLNode * curNode = aList.GetFirst();
|
||||
|
||||
list<string>::iterator iter;
|
||||
for(iter = master.begin(); iter != master.end() && curNode != NULL; iter++, curNode = curNode->GetNext())
|
||||
{
|
||||
tut::ensure_equals("GetValue() - The values are not the order which they should be", curNode->GetValue(), *iter);
|
||||
}
|
||||
|
||||
tut::ensure_equals("GetNext() - The list is longer than it should be", curNode, NULL_NODE);
|
||||
tut::ensure("GetNext() - The list is shorter than it should be", iter == master.end());
|
||||
}
|
||||
|
||||
namespace tut
|
||||
{
|
||||
namespace
|
||||
{
|
||||
typedef tut::test_group<LinkedListTest> tGroup;
|
||||
typedef tGroup::object tObject;
|
||||
tGroup group("LinkedList");
|
||||
}
|
||||
|
||||
template<>
|
||||
template<>
|
||||
void tObject::test<1> ()
|
||||
{
|
||||
set_test_name ("Default Constructor");
|
||||
gCurrentTest = get_test_name();
|
||||
|
||||
LinkedList aList;
|
||||
tut::ensure_equals("Default Constructor - List size != 0", aList.GetSize(), 0);
|
||||
tut::ensure_equals("Default Constructor - first != NULL", aList.GetFirst(), NULL_NODE);
|
||||
tut::ensure_equals("Default Constructor - last != NULL", aList.GetLast(), NULL_NODE);
|
||||
}
|
||||
|
||||
template<>
|
||||
template<>
|
||||
void tObject::test<2> ()
|
||||
{
|
||||
set_test_name ("Clear");
|
||||
gCurrentTest = get_test_name();
|
||||
|
||||
LinkedList aList;
|
||||
aList.Clear();
|
||||
|
||||
aList.Insert("To Remove", NULL);
|
||||
aList.Clear();
|
||||
|
||||
tut::ensure_equals("Clear() - size != 0", aList.GetSize(), 0);
|
||||
tut::ensure_equals("Clear() - first != NULL", aList.GetFirst(), NULL_NODE);
|
||||
tut::ensure_equals("Clear() - last != NULL", aList.GetLast(), NULL_NODE);
|
||||
}
|
||||
|
||||
template<>
|
||||
template<>
|
||||
void tObject::test<3> ()
|
||||
{
|
||||
set_test_name ("Basic Insert Tests");
|
||||
gCurrentTest = get_test_name();
|
||||
|
||||
LinkedList aList;
|
||||
initList(aList);
|
||||
master.reverse();
|
||||
|
||||
tut::ensure_equals("Insert() - List size != number of strings inserted", aList.GetSize(), static_cast<int>(master.size()));
|
||||
|
||||
tut::ensure("GetLast() - List was empty", aList.GetLast() != NULL);
|
||||
tut::ensure_equals("GetLast() - Returned the wrong value", aList.GetLast()->GetValue(), master.back());
|
||||
tut::ensure_equals("GetLast() - The returned node had a next", aList.GetLast()->GetNext(), NULL_NODE);
|
||||
|
||||
tut::ensure("GetFirst() - List was empty", aList.GetFirst() != NULL);
|
||||
tut::ensure_equals("GetFirst() - Returned the wrong value", aList.GetFirst()->GetValue(), master.front());
|
||||
tut::ensure_equals("GetFirst() - The returned node had a next", aList.GetFirst()->GetPrevious(), NULL_NODE);
|
||||
}
|
||||
|
||||
template<>
|
||||
template<>
|
||||
void tObject::test<4> ()
|
||||
{
|
||||
set_test_name ("Insert");
|
||||
gCurrentTest = get_test_name();
|
||||
|
||||
master.reverse();
|
||||
|
||||
LinkedList aList;
|
||||
aList.Clear();
|
||||
|
||||
int count = 0;
|
||||
list<string>::iterator iter;
|
||||
for(iter = master.begin(); iter != master.end(); iter++)
|
||||
{
|
||||
LLNode* curNode = aList.GetLast();
|
||||
while(curNode != NULL && curNode->GetValue().compare(*iter) > 0)
|
||||
{
|
||||
curNode = curNode->GetPrevious();
|
||||
}
|
||||
aList.Insert(*iter, curNode);
|
||||
|
||||
ensure_equals("Size != number of elements inserted", aList.GetSize(), ++count);
|
||||
}
|
||||
|
||||
sortedInitList(aList);
|
||||
list<string> sorted(master.begin(), master.end());
|
||||
sorted.sort();
|
||||
|
||||
tut::ensure_equals("Insert() - Size != Number of strings inserted", aList.GetSize(), static_cast<int>(sorted.size()));
|
||||
|
||||
CompareLists(aList, sorted);
|
||||
}
|
||||
|
||||
template<>
|
||||
template<>
|
||||
void tObject::test<5> ()
|
||||
{
|
||||
set_test_name ("Copy Constructor");
|
||||
gCurrentTest = get_test_name();
|
||||
|
||||
LinkedList aList;
|
||||
LinkedList emptyCopy(aList);
|
||||
|
||||
initList(aList);
|
||||
master.reverse();
|
||||
sortedInitList(aList);
|
||||
|
||||
list<string> sorted(master.begin(), master.end());
|
||||
sorted.sort();
|
||||
|
||||
LinkedList fullCopyList(aList);
|
||||
|
||||
tut::ensure_equals("Copy Constructor - Size != size of original list", aList.GetSize(), fullCopyList.GetSize());
|
||||
|
||||
aList.Clear();
|
||||
CompareLists(fullCopyList, sorted);
|
||||
}
|
||||
|
||||
template<>
|
||||
template<>
|
||||
void tObject::test<6> ()
|
||||
{
|
||||
set_test_name ("Assignment Operator");
|
||||
gCurrentTest = get_test_name();
|
||||
|
||||
LinkedList aList;
|
||||
|
||||
//Assign an empty to an empty
|
||||
LinkedList emptyList;
|
||||
emptyList = aList;
|
||||
|
||||
//Return type check
|
||||
tut::ensure ("Assignment Operator: Testing return value", &emptyList == &(emptyList = aList));
|
||||
|
||||
//Assign full to an empty
|
||||
initList(aList);
|
||||
master.reverse();
|
||||
sortedInitList(aList);
|
||||
|
||||
list<string> sorted(master.begin(), master.end());
|
||||
sorted.sort();
|
||||
|
||||
LinkedList fullList;
|
||||
fullList = aList;
|
||||
tut::ensure_equals("Assignment Operator - Size != size of original list when going from empty to full", fullList.GetSize(), aList.GetSize());
|
||||
|
||||
aList.Clear();
|
||||
CompareLists(fullList, sorted);
|
||||
|
||||
//Self assignment
|
||||
fullList = fullList;
|
||||
tut::ensure_equals("Assignment Operator - Size != size of original list on self assignment", fullList.GetSize(), sorted.size());
|
||||
CompareLists(fullList, sorted);
|
||||
|
||||
//Assign full to empty
|
||||
LinkedList& nowEmpty = fullList;
|
||||
nowEmpty = aList;
|
||||
tut::ensure_equals("Assignment Operator - Size != size of original list when going from full to empty", nowEmpty.GetSize(), aList.GetSize());
|
||||
}
|
||||
|
||||
template<>
|
||||
template<>
|
||||
void tObject::test<7> ()
|
||||
{
|
||||
set_test_name ("IsEmpty");
|
||||
gCurrentTest = get_test_name();
|
||||
|
||||
LinkedList aList;
|
||||
initList(aList);
|
||||
master.reverse();
|
||||
sortedInitList(aList);
|
||||
|
||||
list<string> sorted(master.begin(), master.end());
|
||||
sorted.sort();
|
||||
|
||||
LinkedList cList;
|
||||
cList = aList;
|
||||
|
||||
tut::ensure_equals("Assignment Operator - Size != size of original list", cList.GetSize(), aList.GetSize());
|
||||
|
||||
aList.Clear();
|
||||
|
||||
CompareLists(cList, sorted);
|
||||
|
||||
tut::ensure_not("IsEmpty() - returned true when list was not empty", cList.IsEmpty());
|
||||
tut::ensure("IsEmpty() - returned false when list was empty", aList.IsEmpty());
|
||||
}
|
||||
|
||||
template<>
|
||||
template<>
|
||||
void tObject::test<8> ()
|
||||
{
|
||||
set_test_name ("Find");
|
||||
gCurrentTest = get_test_name();
|
||||
|
||||
LinkedList aList;
|
||||
initList(aList);
|
||||
master.reverse();
|
||||
|
||||
list<string> sorted(master.begin(), master.end());
|
||||
sorted.sort();
|
||||
|
||||
list<string>::iterator iter;
|
||||
for(iter = master.begin(); iter != master.end(); iter++){
|
||||
LLNode* curNode = aList.Find(*iter, NULL);
|
||||
|
||||
tut::ensure("Find() - Find returned NULL when it shouldn't have", curNode != NULL);
|
||||
tut::ensure_equals("Find() - Find returned the wrong value", curNode->GetValue(), *iter);
|
||||
}//end for iter
|
||||
|
||||
LLNode* curNode = NULL;
|
||||
curNode = aList.Find(master.back(), aList.GetLast());
|
||||
|
||||
tut::ensure_equals("Find() - Find is starting its search on the node given, not the node after the one given", curNode, NULL_NODE);
|
||||
|
||||
curNode = aList.GetFirst();
|
||||
int attempt = -1;
|
||||
while(curNode != NULL){
|
||||
tut::ensure_equals("Find() - Find is returning a value when it should be returning NULL", aList.Find(curNode->GetValue(), curNode), NULL_NODE);
|
||||
curNode = curNode->GetNext();
|
||||
tut::ensure("GetNext() - Infinite loop hit", attempt++ <= LLTestSize);
|
||||
}
|
||||
|
||||
iter = master.begin();
|
||||
iter++;
|
||||
curNode = aList.Find(*iter, NULL);
|
||||
tut::ensure("Find() - Returned NULL when it should not have", curNode != NULL);
|
||||
curNode = aList.Find(master.front(), curNode);
|
||||
tut::ensure_equals("Find() - Did not return NULL when the item was in the list, but before the search point", curNode, NULL_NODE);
|
||||
|
||||
string key = generateKey();
|
||||
while(chosen.find(key) != chosen.end()){
|
||||
key = generateKey();
|
||||
}
|
||||
curNode = aList.Find(key, NULL);
|
||||
tut::ensure_equals("Find() - Find is returning a value when the value is not in the list", curNode, NULL_NODE);
|
||||
}
|
||||
|
||||
template<>
|
||||
template<>
|
||||
void tObject::test<9> ()
|
||||
{
|
||||
set_test_name ("Remove");
|
||||
gCurrentTest = get_test_name();
|
||||
|
||||
LinkedList aList;
|
||||
initList(aList);
|
||||
|
||||
master.reverse();
|
||||
list<string> sorted(master.begin(), master.end());
|
||||
sorted.sort();
|
||||
|
||||
for(int i = 0; i < LLTestSize/2; i++)
|
||||
{
|
||||
ensure_not("Internal Error", master.empty());
|
||||
master.pop_back();
|
||||
aList.Remove(aList.GetLast());
|
||||
ensure_equals("GetSize() Did not return the correct size after a remove", aList.GetSize(), static_cast<int>(master.size()));
|
||||
}
|
||||
|
||||
for(set<string>::iterator setIter = chosen.begin(); setIter != chosen.end(); ++setIter)
|
||||
{
|
||||
LLNode* curNode = aList.Find(*setIter, NULL);
|
||||
list<string>::iterator iter = find(master.begin(), master.end(), *setIter);
|
||||
ensure("Find() - Returned a value which was removed", iter != master.end() || curNode == NULL);
|
||||
ensure("Find() - Returned NULL when the value was in the list", iter == master.end() || curNode != NULL);
|
||||
ensure("Find() - Find returned the wrong value", curNode == NULL || curNode->GetValue() == *setIter);
|
||||
}
|
||||
|
||||
master.sort();
|
||||
list<string>::iterator iter;
|
||||
for(iter = master.begin(); iter != master.end(); ++iter)
|
||||
{
|
||||
aList.Remove(aList.Find(*iter,0));
|
||||
}
|
||||
|
||||
ensure_equals("Remove() - List did not return a size of 0 when the list was empty", aList.GetSize(), 0);
|
||||
ensure("Remove() - List should be empty", aList.IsEmpty());
|
||||
ensure_equals("Remove() - List should have no first node", aList.GetFirst(), NULL_NODE);
|
||||
ensure_equals("Remove() - List should have no last node", aList.GetLast(), NULL_NODE);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,111 @@
|
|||
#include <csignal>
|
||||
#include <boost/program_options.hpp>
|
||||
#include <boost/cstdlib.hpp>
|
||||
#include "tut/tut.hpp"
|
||||
#include "tut/tut_reporter.hpp"
|
||||
|
||||
///@file
|
||||
///All tests are auto-included through linking thanks to the TUT Unit Test frame-work
|
||||
///@see tut
|
||||
|
||||
namespace tut
|
||||
{
|
||||
test_runner_singleton gRunner;
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
const std::string gTestGroupDefault = "all";
|
||||
const int gTestDefault = -1;
|
||||
}
|
||||
|
||||
std::string gCurrentTest = "";
|
||||
|
||||
|
||||
void segfault_handler(int num)
|
||||
{
|
||||
std::cout << "Died during the test \"" << gCurrentTest << "\"" << std::endl;
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
|
||||
namespace po = boost::program_options;
|
||||
|
||||
void print_tests ()
|
||||
{
|
||||
std::cout << "CS 240 Collections Pass Off" << std::endl;
|
||||
std::cout << std::endl << "Tests: " << std::endl;
|
||||
|
||||
tut::groupnames names = tut::runner.get().list_groups();
|
||||
tut::groupnames::iterator nameItr = names.begin();
|
||||
for (; nameItr != names.end(); ++nameItr)
|
||||
std::cout << "\t\"" << *nameItr << "\"" << std::endl;
|
||||
}
|
||||
|
||||
bool run (const std::string &testGroup, int test)
|
||||
{
|
||||
std::cout << "CS 240 Collections Pass Off" << std::endl;
|
||||
tut::reporter reportPresenter;
|
||||
tut::runner.get().set_callback(&reportPresenter);
|
||||
|
||||
if (testGroup == gTestGroupDefault)
|
||||
tut::runner.get().run_tests ();
|
||||
else if (test == gTestDefault)
|
||||
tut::runner.get().run_tests (testGroup);
|
||||
else
|
||||
tut::runner.get().run_test (testGroup, test);
|
||||
|
||||
std::cout << std::endl << "Finished" << std::endl;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
bool success = true;
|
||||
|
||||
try
|
||||
{
|
||||
std::string testGroup;
|
||||
int test;
|
||||
|
||||
po::options_description optionList ("Allowed options");
|
||||
optionList.add_options()
|
||||
("test,t", po::value<std::string>(&testGroup)->default_value(gTestGroupDefault), "Selects which test group to run")
|
||||
("number,n", po::value<int>(&test)->default_value(gTestDefault), "Select a test within a group")
|
||||
("list-tests,l", "List available tests")
|
||||
("disable-seg,d", "Disable the seg-fault handler to make debugging easier")
|
||||
("help,h", "Prints this message")
|
||||
;
|
||||
|
||||
po::positional_options_description positionalOptions;
|
||||
positionalOptions.add("test", -1);
|
||||
|
||||
po::variables_map parsedOptions;
|
||||
po::store (po::command_line_parser (argc, argv).options(optionList).positional(positionalOptions).run(), parsedOptions);
|
||||
po::notify (parsedOptions);
|
||||
|
||||
if (parsedOptions.count("disable-seg") == 0)
|
||||
std::signal(SIGSEGV, segfault_handler);
|
||||
|
||||
if (0 < parsedOptions.count("help"))
|
||||
{
|
||||
std::cout << "CS 240 Collections Pass Off" << std::endl;
|
||||
std::cout << optionList << std::endl;
|
||||
}
|
||||
else if (0 < parsedOptions.count("list-tests"))
|
||||
print_tests();
|
||||
else
|
||||
success = run(testGroup, test);
|
||||
|
||||
}
|
||||
catch (std::exception &e)
|
||||
{
|
||||
std::cerr << e.what() << std::endl;
|
||||
std::cerr << "Abborting" << std::endl;
|
||||
success = false;;
|
||||
}
|
||||
|
||||
return success? boost::exit_success : boost::exit_failure;
|
||||
}
|
|
@ -0,0 +1,509 @@
|
|||
Documentation TUT How-To minimum steps to make TUT work for you
|
||||
|
||||
What is TUT
|
||||
|
||||
TUT is a pure C++ unit test framework. Its name - TUT - stands for
|
||||
Template Unit Tests.
|
||||
|
||||
Features
|
||||
|
||||
TUT provides all features required for unit testing:
|
||||
|
||||
* Similar tests can be grouped together into test groups. Each
|
||||
test group has its unique name and is located in a separate
|
||||
compilation unit. One group can contain almost unlimited number
|
||||
of tests (actually, the limit is the compiler template
|
||||
recursion depth).
|
||||
* User can run all the tests (regression), or just some selected
|
||||
groups or even some tests in these groups.
|
||||
* TUT provides special template functions to check the condition
|
||||
validity at run-time and to force test failure if required.
|
||||
Since C++ doesn't provide a facility for obtaining stack trace
|
||||
of the throwed exception and TUT avoids macros, those functions
|
||||
accept string marker to allow users easely determine the source
|
||||
of exception.
|
||||
* TUT contains callback that can be implemented by the calling code
|
||||
to integrate with an IDE, for example. Callbacks tell listener
|
||||
when a new test run started, when test runner switches to the
|
||||
next tests group, when a test was completed (and what result it
|
||||
has), and when test run was finished. The callbacks allow users
|
||||
to produce their own visualization format for test process and results.
|
||||
* Being a template library, it doesn't need compilation; just
|
||||
include the <tut.h> header into the test modules.
|
||||
|
||||
TUT tests organization
|
||||
|
||||
Test application
|
||||
|
||||
C++ produces executable code, so tests have to be compiled into a single
|
||||
binary called test application. The application can be built in automated
|
||||
mode to perform nightly tests. They also can be built manually when a
|
||||
developer hunts for bugs.
|
||||
|
||||
The test application contains tests, organized into test groups.
|
||||
|
||||
Test groups
|
||||
|
||||
The functionality of a tested application can be divided into a few separate
|
||||
function blocks (e.g. User Rights, Export, Processing, ...). It is natural
|
||||
to group together tests for each block. TUT invokes this test group. Each
|
||||
test group has a unique human-readable name and normally is located in a
|
||||
separate file.
|
||||
|
||||
Tests
|
||||
|
||||
Each single test usually checks only one specific element of functionality.
|
||||
For example, for a container a test could check whether size() call
|
||||
returns zero after the successful call to the clear() method.
|
||||
|
||||
Writing simple test
|
||||
|
||||
Preamble
|
||||
|
||||
You are going to create a new class for your application. You decided to
|
||||
write tests for the class to be sure it works while you are developing or,
|
||||
possibly, enhancing it. Let's consider your class is shared pointer:
|
||||
std::auto_ptr-alike type that shares the same object among instances.
|
||||
|
||||
Prior to test writing, you should decide what to test. Maximalist's
|
||||
approach requires to write so many tests that altering any single
|
||||
line of your production code will break at least one of them.
|
||||
Minimalist's approach allows one to write tests only for the most
|
||||
general or the most complex use cases. The truth lies somewhere in
|
||||
between, but only you, developer, know where. You should prepare
|
||||
common successful and unsuccessful scenarios, and the scenarios for
|
||||
testing any other functionality you believe might be broken in some way.
|
||||
|
||||
For our shared_ptr we obviosly should test constructors, assignment operators, referencing and passing ownership.
|
||||
|
||||
Skeleton
|
||||
|
||||
If you don't have any implemented class to test yet, it would be good to
|
||||
implement it as a set of stubs for a first time. Thus you'll get an
|
||||
interface, and be able to write your tests. Yes, that's correct: you
|
||||
should write your tests before writing code! First of all, writing tests
|
||||
often helps to understand oddities in the current interface, and fix it.
|
||||
Secondly, with the stubs all your tests will fail, so you'll be sure
|
||||
they do their job.
|
||||
|
||||
Creating Test Group
|
||||
|
||||
Since we're writing unit tests, it would be a good idea to group the
|
||||
tests for our class in one place to be able to run them separately.
|
||||
It's also natural in C++ to place all the grouped tests into one
|
||||
compilation unit (i.e. source file). So, to begin, we should create
|
||||
a new file. Let's call it test_shared_ptr.cpp. (Final variant of the
|
||||
test group can be found in examples/shared_ptr subdirectory of the
|
||||
distribution package)
|
||||
|
||||
// test_shared_ptr.cpp
|
||||
#include <tut.h>
|
||||
|
||||
namespace tut
|
||||
{
|
||||
};
|
||||
|
||||
|
||||
As you see, you need to include TUT header file (as expected) and
|
||||
use namespace tut for tests. You may also use anonymous namespace if
|
||||
your compiler allows it (you will need to instantiate methods from
|
||||
tut namespace and some compilers refuse to place such instantiations
|
||||
into the anonymous namespace).
|
||||
|
||||
A test group in TUT framework is described by the special template
|
||||
test_group<T>. The template parameter T is a type that will hold all
|
||||
test-specific data during the test execution. Actually, the data
|
||||
stored in T are member data of the test. Test object is inherited
|
||||
from T, so any test can refer to the data in T as its member data.
|
||||
|
||||
For simple test groups (where all data are stored in test local
|
||||
variables) type T is an empty struct.
|
||||
|
||||
#include <tut.h>
|
||||
|
||||
namespace tut
|
||||
{
|
||||
struct shared_ptr_data
|
||||
{
|
||||
};
|
||||
}
|
||||
|
||||
But when tests have complex or repeating creation phase, you may put
|
||||
data members into the T and provide constructor (and, if required,
|
||||
destructor) for it. For each test, a new instance of T will be
|
||||
created. To prepare your test for execution TUT will use default
|
||||
constructor. Similarly, after the test has been finished, TUT
|
||||
calls the destructor to clean up T. I.e.:
|
||||
|
||||
#include <tut.h>
|
||||
|
||||
namespace tut
|
||||
{
|
||||
struct complex_data
|
||||
{
|
||||
connection* con;
|
||||
complex_data(){ con = db_pool.get_connection(); }
|
||||
~complex_data(){ db_pool.release_connection(con); }
|
||||
};
|
||||
|
||||
// each test from now will have con data member initialized
|
||||
// by constructor:
|
||||
...
|
||||
con->commit();
|
||||
...
|
||||
|
||||
|
||||
What will happen if the constructor throws an exception? TUT will treat
|
||||
it as if test itself failed with exception, so this test will
|
||||
not be executed. You'll see an exception mark near the test, and
|
||||
if the constructor throwed something printable, a certain message will appear.
|
||||
|
||||
Exception in destructor is threated a bit different. Reaching destruction
|
||||
phase means that the test is passed, so TUT marks test with warning
|
||||
status meaning that test itself was OK, but something bad has happend
|
||||
after the test.
|
||||
|
||||
Well, all we have written so far is just a type declaration. To work
|
||||
with a group we have to have an object, so we must create the test group
|
||||
object. Since we need only one test group object for each unit, we can
|
||||
(and should, actually) make this object static. To prevent name clash with
|
||||
other test group objects in the namespace tut, we should provide a
|
||||
descriptive name, or, alternatively, we may put it into the anonymous
|
||||
namespace. The former is more correct, but a descriptive name usually works
|
||||
well too, unless you're too terse in giving names to objects.
|
||||
|
||||
#include <tut.h>
|
||||
|
||||
namespace tut
|
||||
{
|
||||
struct shared_ptr_data
|
||||
{
|
||||
|
||||
};
|
||||
|
||||
typedef test_group<shared_ptr_data> tg;
|
||||
tg shared_ptr_group("shared_ptr");
|
||||
};
|
||||
|
||||
As you see, any test group accepts a single parameter - its human-readable
|
||||
name. This name is used to identify the group when a programmer wants to
|
||||
execute all tests or a single test within the group. So this name shall
|
||||
also be descriptive enough to avoid clashes. Since we're writing tests
|
||||
for a specific unit, it's enough to name it after the unit name.
|
||||
|
||||
Test group constructor will be called at unspecified moment at the test
|
||||
application startup. The constructor performs self-registration; it calls
|
||||
tut::runner and asks it to store the test group object name and location.
|
||||
Any other test group in the system undergoes the same processing, i.e.
|
||||
each test group object registers itself. Thus, test runner can iterate
|
||||
all test groups or execute any test group by its name.
|
||||
|
||||
Newly created group has no tests associated with it. To be more precise,
|
||||
it has predefined set of dummy tests. By default, there are 50 tests in a
|
||||
group, including dummy ones. To create a test group with higher volume
|
||||
(e.g. when tests are generated by a script and their number is higher)
|
||||
we must provide a higher border of test group size when it is instantiated:
|
||||
|
||||
#include <tut.h>
|
||||
|
||||
namespace tut
|
||||
{
|
||||
struct huge_test_data
|
||||
{
|
||||
};
|
||||
|
||||
// test group with maximum 500 tests
|
||||
typedef test_group<huge_test_data,500> testgroup;
|
||||
testgroup huge_test_testgroup("huge group");
|
||||
};
|
||||
|
||||
|
||||
Note also, that your compiler will possibly need a command-line switch
|
||||
or pragma to enlarge recursive instantiation depth. For g++, for
|
||||
example, you should specify at least --ftemplate-depth-501 to increase
|
||||
the depth. For more information see your compiler documentation.
|
||||
|
||||
Creating Tests
|
||||
|
||||
Now it's time to fill our test group with content.
|
||||
|
||||
In TUT, all tests have unique numbers inside the test group. Some
|
||||
people believe that textual names better describe failed tests in
|
||||
reports. I agree; but in reality C++ templates work good with numbers
|
||||
because they are compile-time constants and refuse to do the same
|
||||
with strings, since strings are in fact addresses of character
|
||||
buffers, i.e. run-time data.
|
||||
|
||||
As I mentioned above, our test group already has a few dummy tests;
|
||||
and we can replace any of them with something real just by writing
|
||||
our own version:
|
||||
|
||||
#include <tut.h>
|
||||
|
||||
namespace tut
|
||||
{
|
||||
struct shared_ptr_data{};
|
||||
|
||||
typedef test_group<shared_ptr_data> testgroup;
|
||||
typedef testgroup::object testobject;
|
||||
testgroup shared_ptr_testgroup("shared_ptr");
|
||||
|
||||
template<>
|
||||
template<>
|
||||
void testobject::test<1>()
|
||||
{
|
||||
// do nothing test
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
So far this test does nothing, but it's enough to illustrate the concept.
|
||||
|
||||
All tests in the group belong to the type test_group<T>::object. This
|
||||
class is directly inherited from our test data structure. In our case, it is
|
||||
|
||||
class object : public shared_ptr_data { ... }
|
||||
|
||||
This allows to access members of the data structure directly, since at
|
||||
the same time they are members of the object type. We also typedef the
|
||||
type with testobject for brevity.
|
||||
|
||||
We mark our test with number 1. Previously, test group had a dummy test
|
||||
with the same number, but now, since we've defined our own version, it
|
||||
replaces the dummy test as more specialized one. It's how C++ template
|
||||
ordering works.
|
||||
|
||||
The test we've written always succeeds. Successful test returns with no
|
||||
exceptions. Unsuccessful one either throws an exception, or fails at
|
||||
fail() or ensure() methods (which anyway just throw the exception when failed).
|
||||
|
||||
First real test
|
||||
|
||||
Well, now we know enough to write the first real working test. This test
|
||||
will create shared_ptr instances and check their state. We will define a
|
||||
small structure (keepee) to use it as shared_ptr stored object type.
|
||||
|
||||
#include <tut.h>
|
||||
#include <shared_ptr.h>
|
||||
|
||||
namespace tut
|
||||
{
|
||||
struct shared_ptr_data
|
||||
{
|
||||
struct keepee{ int data; };
|
||||
};
|
||||
|
||||
typedef test_group<shared_ptr_data> testgroup;
|
||||
typedef testgroup::object testobject;
|
||||
testgroup shared_ptr_testgroup("shared_ptr");
|
||||
|
||||
/**
|
||||
* Checks default constructor.
|
||||
*/
|
||||
template<>
|
||||
template<>
|
||||
void testobject::test<1>()
|
||||
{
|
||||
shared_ptr<keepee> def;
|
||||
ensure("null",def.get() == 0);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
That's all! The first line creates shared_ptr. If constructor throws
|
||||
an exception, test will fail (exceptions, including '...', are catched
|
||||
by the TUT framework). If the first line succeeds, we must check
|
||||
whether the kept object is null one. To do this, we use test object
|
||||
member function ensure(), which throws std::logic_error with a given
|
||||
message if its second argument is not true. Finally, if destructor of
|
||||
shared_ptr fails with exception, TUT also will report this test as failed.
|
||||
|
||||
It's equally easy to write a test for the scenario where we expect to get
|
||||
an exception: let's consider our class should throw an exception if it
|
||||
has no stored object, and the operator -> is called.
|
||||
|
||||
/**
|
||||
* Checks operator -> throws instead of returning null.
|
||||
*/
|
||||
template<>
|
||||
template<>
|
||||
void testobject::test<2>()
|
||||
{
|
||||
try
|
||||
{
|
||||
shared_ptr<keepee> sp;
|
||||
sp->data = 0;
|
||||
fail("exception expected");
|
||||
}
|
||||
catch( const std::runtime_error& ex )
|
||||
{
|
||||
// ok
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Here we expect the std::runtime_error. If operator doesn't throw it,
|
||||
we'll force the test to fail using another member function: fail(). It
|
||||
just throws std::logic_error with a given message. If operator throws
|
||||
anything else, our test will fail too, since we intercept only
|
||||
std::runtime_error, and any other exception means the test has failed.
|
||||
|
||||
NB: our second test has number 2 in its name; it can, actually, be any
|
||||
in range 1..Max; the only requirement is not to write tests with the
|
||||
same numbers. If you did, compiler will force you to fix them anyway.
|
||||
|
||||
And finally, one more test to demonstrate how to use the
|
||||
ensure_equals template member function:
|
||||
|
||||
/**
|
||||
* Checks keepee counting.
|
||||
*/
|
||||
template<>
|
||||
template<>
|
||||
void testobject::test<3>()
|
||||
{
|
||||
shared_ptr<keepee> sp1(new keepee());
|
||||
shared_ptr<keepee> sp2(sp1);
|
||||
ensure_equals("second copy at sp1",sp1.count(),2);
|
||||
ensure_equals("second copy at sp2",sp2.count(),2);
|
||||
}
|
||||
|
||||
|
||||
The test checks if the shared_ptr correctly counts references during
|
||||
copy construction. What's interesting here is the template member
|
||||
ensure_equals. It has an additional functionality comparing with similar
|
||||
call ensure("second_copy",sp1.count()==2); it uses operator == to check
|
||||
the equality of the two passed parameters and, what's more important, it
|
||||
uses std::stream to format the passed parameters into a human-readable
|
||||
message (smth like: "second copy: expected 2, got 1"). It means that
|
||||
ensure_equals cannot be used with the types that don't have operator <<;
|
||||
but for those having the operator it provides much more informational message.
|
||||
|
||||
In contrast to JUnit assertEquals, where the expected value goes before
|
||||
the actual one, ensure_equals() accepts the expected after the actual
|
||||
value. I believe it's more natural to read ensure_equals("msg", count, 5)
|
||||
as "ensure that count equals to 5" rather than JUnit's
|
||||
"assert that 5 is the value of the count".
|
||||
|
||||
Running tests
|
||||
|
||||
Tests are already written, but an attempt to run them will be unsuccessful.
|
||||
We need a few other bits to complete the test application.
|
||||
|
||||
First of all, we need a main() method, simply because it must be in all
|
||||
applications. Secondly, we need a test runner singleton. Remember I said
|
||||
each test group should register itself in singleton? So, we need that
|
||||
singleton. And, finally, we need a kind of a callback handler to visualize
|
||||
our test results.
|
||||
|
||||
The design of TUT doesn't strictly set a way the tests are visualized;
|
||||
instead, it provides an opportunity to get the test results by means of
|
||||
callbacks. Moreover it allows user to output the results in any format he
|
||||
prefers. Of course, there is a "reference implementation" in the
|
||||
example/subdirectory of the project.
|
||||
|
||||
Test runner singleton is defined in tut.h, so all we need to activate it
|
||||
is to declare an object of the type tut::test_runner_singleton in the main
|
||||
module with a special name tut::runner.
|
||||
|
||||
Now, with the test_runner we can run tests. Singleton has method get()
|
||||
returning a reference to an instance of the test_runner class, which in
|
||||
turn has methods run_tests() to run all tests in all groups,
|
||||
run_tests(const std::string& groupname) to run all tests in a given group
|
||||
and run_test(const std::string& grp,int n) to run one test in the specified group.
|
||||
|
||||
// main.cpp
|
||||
#include <tut.h>
|
||||
|
||||
namespace tut
|
||||
{
|
||||
test_runner_singleton runner;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
// run all tests in all groups
|
||||
runner.get().run_tests();
|
||||
|
||||
// run all tests in group "shared_ptr"
|
||||
runner.get().run_tests("shared_ptr");
|
||||
|
||||
// run test number 5 in group "shared_ptr"
|
||||
runner.get().run_test("shared_ptr",5);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
It's up to user to handle command-line arguments or GUI messages and map those
|
||||
arguments/messages to actual calls to test runner. Again, as you see, TUT
|
||||
doesn't restrict user here.
|
||||
|
||||
But, the last question is still unanswered: how do we get our test results?
|
||||
The answer lies inside tut::callback interface. User shall create its subclass,
|
||||
and write up to three simple methods. He also can omit any method since they
|
||||
have default no-op implementation. Each corresponding method is called in the
|
||||
following cases:
|
||||
|
||||
* a new test run started;
|
||||
* test finished;
|
||||
* test run finished.
|
||||
|
||||
Here is a minimal implementation:
|
||||
|
||||
class visualizator : public tut::callback
|
||||
{
|
||||
public:
|
||||
void run_started(){ }
|
||||
|
||||
void test_completed(const tut::test_result& tr)
|
||||
{
|
||||
// ... show test result here ...
|
||||
}
|
||||
|
||||
void run_completed(){ }
|
||||
};
|
||||
|
||||
The most important is the test_completed() method; its parameter has type
|
||||
test_result, and contains everything about the finished test, from its group
|
||||
name and number to the exception message, if any. Member result is an enum
|
||||
that contains status of the test: ok, fail or ex. Take a look at the
|
||||
examples/basic/main.cpp for more complete visualizator.
|
||||
|
||||
Visualizator should be passed to the test_runner before run. Knowing that,
|
||||
we are ready to write the final version of our main module:
|
||||
|
||||
// main.cpp
|
||||
#include <tut.h>
|
||||
|
||||
namespace tut
|
||||
{
|
||||
test_runner_singleton runner;
|
||||
}
|
||||
|
||||
class callback : public tut::callback
|
||||
{
|
||||
public:
|
||||
void run_started(){ std::cout << "\nbegin"; }
|
||||
|
||||
void test_completed(const tut::test_result& tr)
|
||||
{
|
||||
std::cout << tr.test_pos << "=" << tr.result << std::flush;
|
||||
}
|
||||
|
||||
void run_completed(){ std::cout << "\nend"; }
|
||||
};
|
||||
|
||||
int main()
|
||||
{
|
||||
callback clbk;
|
||||
runner.get().set_callback(&clbk);
|
||||
|
||||
// run all tests in all groups
|
||||
runner.get().run_tests();
|
||||
return 0;
|
||||
}
|
||||
|
||||
That's it. You are now ready to link and run our test application. Do it as often as possible;
|
||||
once a day is a definite must. I hope, TUT will help you to make your application more
|
||||
robust and relieve your testing pain. Feel free to send your questions, suggestions and
|
||||
critical opinions to me; I'll do my best to address them asap.
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,226 @@
|
|||
#ifndef TUT_REPORTER
|
||||
#define TUT_REPORTER
|
||||
|
||||
#include "tut.hpp"
|
||||
|
||||
/**
|
||||
* Template Unit Tests Framework for C++.
|
||||
* http://tut.dozen.ru
|
||||
*
|
||||
* @author Vladimir Dyuzhev, Vladimir.Dyuzhev@gmail.com
|
||||
*/
|
||||
namespace
|
||||
{
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, const tut::test_result& tr)
|
||||
{
|
||||
switch(tr.result)
|
||||
{
|
||||
case tut::test_result::ok:
|
||||
os << "\t" << tr.test << " " << tr.name << "...ok" << std::endl;
|
||||
break;
|
||||
case tut::test_result::fail:
|
||||
os << "\t" << tr.test << " " << tr.name<< "...failed" << std::endl;
|
||||
break;
|
||||
case tut::test_result::ex_ctor:
|
||||
os << "\t" << tr.test << " " << tr.name<< "...exception in setup" << std::endl;
|
||||
break;
|
||||
case tut::test_result::ex:
|
||||
os << "\t" << tr.test << " " << tr.name<< "...exception" << std::endl;
|
||||
break;
|
||||
case tut::test_result::warn:
|
||||
os << "\t" << tr.test << " " << tr.name<< "...warning" << std::endl;
|
||||
break;
|
||||
case tut::test_result::term:
|
||||
os << "\t" << tr.test << " " << tr.name<< "...terminated" << std::endl;
|
||||
break;
|
||||
}
|
||||
|
||||
return os;
|
||||
}
|
||||
|
||||
} // end of namespace
|
||||
|
||||
namespace tut
|
||||
{
|
||||
|
||||
/**
|
||||
* Default TUT callback handler.
|
||||
*/
|
||||
class reporter : public tut::callback
|
||||
{
|
||||
std::string current_group;
|
||||
typedef std::vector<tut::test_result> not_passed_list;
|
||||
not_passed_list not_passed;
|
||||
std::ostream& os;
|
||||
|
||||
public:
|
||||
|
||||
int ok_count;
|
||||
int exceptions_count;
|
||||
int failures_count;
|
||||
int terminations_count;
|
||||
int warnings_count;
|
||||
|
||||
reporter()
|
||||
: os(std::cout)
|
||||
{
|
||||
init();
|
||||
}
|
||||
|
||||
reporter(std::ostream& out)
|
||||
: os(out)
|
||||
{
|
||||
init();
|
||||
}
|
||||
|
||||
void run_started()
|
||||
{
|
||||
init();
|
||||
}
|
||||
|
||||
void test_completed(const tut::test_result& tr)
|
||||
{
|
||||
if (tr.group != current_group)
|
||||
{
|
||||
os << std::endl << tr.group << ": " << std::endl;
|
||||
current_group = tr.group;
|
||||
}
|
||||
|
||||
os << tr << std::flush;
|
||||
if (tr.result == tut::test_result::ok)
|
||||
{
|
||||
ok_count++;
|
||||
}
|
||||
else if (tr.result == tut::test_result::ex)
|
||||
{
|
||||
exceptions_count++;
|
||||
}
|
||||
else if (tr.result == tut::test_result::ex_ctor)
|
||||
{
|
||||
exceptions_count++;
|
||||
}
|
||||
else if (tr.result == tut::test_result::fail)
|
||||
{
|
||||
failures_count++;
|
||||
}
|
||||
else if (tr.result == tut::test_result::warn)
|
||||
{
|
||||
warnings_count++;
|
||||
}
|
||||
else
|
||||
{
|
||||
terminations_count++;
|
||||
}
|
||||
|
||||
if (tr.result != tut::test_result::ok)
|
||||
{
|
||||
not_passed.push_back(tr);
|
||||
}
|
||||
}
|
||||
|
||||
void run_completed()
|
||||
{
|
||||
os << std::endl;
|
||||
|
||||
if (not_passed.size() > 0)
|
||||
{
|
||||
not_passed_list::const_iterator i = not_passed.begin();
|
||||
while (i != not_passed.end())
|
||||
{
|
||||
tut::test_result tr = *i;
|
||||
|
||||
os << std::endl;
|
||||
|
||||
os << "---> " << "group: " << tr.group
|
||||
<< ", test: test<" << tr.test << ">"
|
||||
<< (!tr.name.empty() ? (std::string(" : ") + tr.name) : std::string())
|
||||
<< std::endl;
|
||||
|
||||
os << " problem: ";
|
||||
switch(tr.result)
|
||||
{
|
||||
case test_result::fail:
|
||||
os << "assertion failed" << std::endl;
|
||||
break;
|
||||
case test_result::ex:
|
||||
case test_result::ex_ctor:
|
||||
os << "unexpected exception" << std::endl;
|
||||
if( tr.exception_typeid != "" )
|
||||
{
|
||||
os << " exception typeid: "
|
||||
<< tr.exception_typeid << std::endl;
|
||||
}
|
||||
break;
|
||||
case test_result::term:
|
||||
os << "would be terminated" << std::endl;
|
||||
break;
|
||||
case test_result::warn:
|
||||
os << "test passed, but cleanup code (destructor) raised"
|
||||
" an exception" << std::endl;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (!tr.message.empty())
|
||||
{
|
||||
if (tr.result == test_result::fail)
|
||||
{
|
||||
os << " failed assertion: \"" << tr.message << "\""
|
||||
<< std::endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
os << " message: \"" << tr.message << "\""
|
||||
<< std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
++i;
|
||||
}
|
||||
}
|
||||
|
||||
os << std::endl;
|
||||
|
||||
os << "tests summary:" << std::endl;
|
||||
if (terminations_count > 0)
|
||||
{
|
||||
os << " terminations:" << terminations_count << std::endl;
|
||||
}
|
||||
if (exceptions_count > 0)
|
||||
{
|
||||
os << " exceptions:" << exceptions_count << std::endl;
|
||||
}
|
||||
if (failures_count > 0)
|
||||
{
|
||||
os << " failures:" << failures_count << std::endl;
|
||||
}
|
||||
if (warnings_count > 0)
|
||||
{
|
||||
os << " warnings:" << warnings_count << std::endl;
|
||||
}
|
||||
os << " ok:" << ok_count << std::endl;
|
||||
}
|
||||
|
||||
bool all_ok() const
|
||||
{
|
||||
return not_passed.empty();
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
void init()
|
||||
{
|
||||
ok_count = 0;
|
||||
exceptions_count = 0;
|
||||
failures_count = 0;
|
||||
terminations_count = 0;
|
||||
warnings_count = 0;
|
||||
not_passed.clear();
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,394 @@
|
|||
#ifndef TUT_RESTARTABLE_H_GUARD
|
||||
#define TUT_RESTARTABLE_H_GUARD
|
||||
|
||||
#include "tut.hpp"
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <stdexcept>
|
||||
|
||||
/**
|
||||
* Template Unit Tests Framework for C++.
|
||||
* http://tut.dozen.ru
|
||||
*
|
||||
* Optional restartable wrapper for test_runner. Allows to restart test runs
|
||||
* finished due to abnormal test application termination (such as segmentation
|
||||
* fault or math error).
|
||||
*
|
||||
* @author Vladimir Dyuzhev, Vladimir.Dyuzhev@gmail.com
|
||||
*/
|
||||
|
||||
namespace tut
|
||||
{
|
||||
|
||||
namespace util
|
||||
{
|
||||
|
||||
/**
|
||||
* Escapes non-alphabetical characters in string.
|
||||
*/
|
||||
std::string escape(const std::string& orig)
|
||||
{
|
||||
std::string rc;
|
||||
std::string::const_iterator i,e;
|
||||
i = orig.begin();
|
||||
e = orig.end();
|
||||
|
||||
while (i != e)
|
||||
{
|
||||
if ((*i >= 'a' && *i <= 'z') ||
|
||||
(*i >= 'A' && *i <= 'Z') ||
|
||||
(*i >= '0' && *i <= '9') )
|
||||
{
|
||||
rc += *i;
|
||||
}
|
||||
else
|
||||
{
|
||||
rc += '\\';
|
||||
rc += ('a'+(((unsigned int)*i) >> 4));
|
||||
rc += ('a'+(((unsigned int)*i) & 0xF));
|
||||
}
|
||||
|
||||
++i;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Un-escapes string.
|
||||
*/
|
||||
std::string unescape(const std::string& orig)
|
||||
{
|
||||
std::string rc;
|
||||
std::string::const_iterator i,e;
|
||||
i = orig.begin();
|
||||
e = orig.end();
|
||||
|
||||
while (i != e)
|
||||
{
|
||||
if (*i != '\\')
|
||||
{
|
||||
rc += *i;
|
||||
}
|
||||
else
|
||||
{
|
||||
++i;
|
||||
if (i == e)
|
||||
{
|
||||
throw std::invalid_argument("unexpected end of string");
|
||||
}
|
||||
unsigned int c1 = *i;
|
||||
++i;
|
||||
if (i == e)
|
||||
{
|
||||
throw std::invalid_argument("unexpected end of string");
|
||||
}
|
||||
unsigned int c2 = *i;
|
||||
rc += (((c1 - 'a') << 4) + (c2 - 'a'));
|
||||
}
|
||||
|
||||
++i;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Serialize test_result avoiding interfering with operator <<.
|
||||
*/
|
||||
void serialize(std::ostream& os, const tut::test_result& tr)
|
||||
{
|
||||
os << escape(tr.group) << std::endl;
|
||||
os << tr.test << ' ';
|
||||
switch(tr.result)
|
||||
{
|
||||
case test_result::ok:
|
||||
os << 0;
|
||||
break;
|
||||
case test_result::fail:
|
||||
os << 1;
|
||||
break;
|
||||
case test_result::ex:
|
||||
os << 2;
|
||||
break;
|
||||
case test_result::warn:
|
||||
os << 3;
|
||||
break;
|
||||
case test_result::term:
|
||||
os << 4;
|
||||
break;
|
||||
default:
|
||||
throw std::logic_error("operator << : bad result_type");
|
||||
}
|
||||
os << ' ' << escape(tr.message) << std::endl;
|
||||
}
|
||||
|
||||
/**
|
||||
* deserialization for test_result
|
||||
*/
|
||||
void deserialize(std::istream& is, tut::test_result& tr)
|
||||
{
|
||||
std::getline(is,tr.group);
|
||||
if (is.eof())
|
||||
{
|
||||
throw tut::no_more_tests();
|
||||
}
|
||||
tr.group = unescape(tr.group);
|
||||
|
||||
tr.test = -1;
|
||||
is >> tr.test;
|
||||
if (tr.test < 0)
|
||||
{
|
||||
throw std::logic_error("operator >> : bad test number");
|
||||
}
|
||||
|
||||
int n = -1;
|
||||
is >> n;
|
||||
switch(n)
|
||||
{
|
||||
case 0:
|
||||
tr.result = test_result::ok;
|
||||
break;
|
||||
case 1:
|
||||
tr.result = test_result::fail;
|
||||
break;
|
||||
case 2:
|
||||
tr.result = test_result::ex;
|
||||
break;
|
||||
case 3:
|
||||
tr.result = test_result::warn;
|
||||
break;
|
||||
case 4:
|
||||
tr.result = test_result::term;
|
||||
break;
|
||||
default:
|
||||
throw std::logic_error("operator >> : bad result_type");
|
||||
}
|
||||
|
||||
is.ignore(1); // space
|
||||
std::getline(is,tr.message);
|
||||
tr.message = unescape(tr.message);
|
||||
if (!is.good())
|
||||
{
|
||||
throw std::logic_error("malformed test result");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Restartable test runner wrapper.
|
||||
*/
|
||||
class restartable_wrapper
|
||||
{
|
||||
test_runner& runner_;
|
||||
callback* callback_;
|
||||
|
||||
std::string dir_;
|
||||
std::string log_; // log file: last test being executed
|
||||
std::string jrn_; // journal file: results of all executed tests
|
||||
|
||||
public:
|
||||
/**
|
||||
* Default constructor.
|
||||
* @param dir Directory where to search/put log and journal files
|
||||
*/
|
||||
restartable_wrapper(const std::string& dir = ".")
|
||||
: runner_(runner.get()),
|
||||
callback_(0),
|
||||
dir_(dir)
|
||||
{
|
||||
// dozen: it works, but it would be better to use system path separator
|
||||
jrn_ = dir_ + '/' + "journal.tut";
|
||||
log_ = dir_ + '/' + "log.tut";
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores another group for getting by name.
|
||||
*/
|
||||
void register_group(const std::string& name, group_base* gr)
|
||||
{
|
||||
runner_.register_group(name,gr);
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores callback object.
|
||||
*/
|
||||
void set_callback(callback* cb)
|
||||
{
|
||||
callback_ = cb;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns callback object.
|
||||
*/
|
||||
callback& get_callback() const
|
||||
{
|
||||
return runner_.get_callback();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns list of known test groups.
|
||||
*/
|
||||
groupnames list_groups() const
|
||||
{
|
||||
return runner_.list_groups();
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs all tests in all groups.
|
||||
*/
|
||||
void run_tests() const
|
||||
{
|
||||
// where last run was failed
|
||||
std::string fail_group;
|
||||
int fail_test;
|
||||
read_log_(fail_group,fail_test);
|
||||
bool fail_group_reached = (fail_group == "");
|
||||
|
||||
// iterate over groups
|
||||
tut::groupnames gn = list_groups();
|
||||
tut::groupnames::const_iterator gni,gne;
|
||||
gni = gn.begin();
|
||||
gne = gn.end();
|
||||
while (gni != gne)
|
||||
{
|
||||
// skip all groups before one that failed
|
||||
if (!fail_group_reached)
|
||||
{
|
||||
if (*gni != fail_group)
|
||||
{
|
||||
++gni;
|
||||
continue;
|
||||
}
|
||||
fail_group_reached = true;
|
||||
}
|
||||
|
||||
// first or restarted run
|
||||
int test = (*gni == fail_group && fail_test >= 0) ? fail_test + 1 : 1;
|
||||
while(true)
|
||||
{
|
||||
// last executed test pos
|
||||
register_execution_(*gni,test);
|
||||
|
||||
try
|
||||
{
|
||||
tut::test_result tr = runner_.run_test(*gni,test);
|
||||
register_test_(tr);
|
||||
}
|
||||
catch (const tut::beyond_last_test&)
|
||||
{
|
||||
break;
|
||||
}
|
||||
catch(const tut::no_such_test&)
|
||||
{
|
||||
// it's ok
|
||||
}
|
||||
|
||||
++test;
|
||||
}
|
||||
|
||||
++gni;
|
||||
}
|
||||
|
||||
// show final results to user
|
||||
invoke_callback_();
|
||||
|
||||
// truncate files as mark of successful finish
|
||||
truncate_();
|
||||
}
|
||||
|
||||
private:
|
||||
/**
|
||||
* Shows results from journal file.
|
||||
*/
|
||||
void invoke_callback_() const
|
||||
{
|
||||
runner_.set_callback(callback_);
|
||||
runner_.get_callback().run_started();
|
||||
|
||||
std::string current_group;
|
||||
std::ifstream ijournal(jrn_.c_str());
|
||||
while (ijournal.good())
|
||||
{
|
||||
// read next test result
|
||||
try
|
||||
{
|
||||
tut::test_result tr;
|
||||
util::deserialize(ijournal,tr);
|
||||
runner_.get_callback().test_completed(tr);
|
||||
}
|
||||
catch (const no_more_tests&)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
runner_.get_callback().run_completed();
|
||||
}
|
||||
|
||||
/**
|
||||
* Register test into journal.
|
||||
*/
|
||||
void register_test_(const test_result& tr) const
|
||||
{
|
||||
std::ofstream ojournal(jrn_.c_str(), std::ios::app);
|
||||
util::serialize(ojournal, tr);
|
||||
ojournal << std::flush;
|
||||
if (!ojournal.good())
|
||||
{
|
||||
throw std::runtime_error("unable to register test result in file "
|
||||
+ jrn_);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark the fact test going to be executed
|
||||
*/
|
||||
void register_execution_(const std::string& grp, int test) const
|
||||
{
|
||||
// last executed test pos
|
||||
std::ofstream olog(log_.c_str());
|
||||
olog << util::escape(grp) << std::endl << test << std::endl << std::flush;
|
||||
if (!olog.good())
|
||||
{
|
||||
throw std::runtime_error("unable to register execution in file "
|
||||
+ log_);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Truncate tests.
|
||||
*/
|
||||
void truncate_() const
|
||||
{
|
||||
std::ofstream olog(log_.c_str());
|
||||
std::ofstream ojournal(jrn_.c_str());
|
||||
}
|
||||
|
||||
/**
|
||||
* Read log file
|
||||
*/
|
||||
void read_log_(std::string& fail_group, int& fail_test) const
|
||||
{
|
||||
// read failure point, if any
|
||||
std::ifstream ilog(log_.c_str());
|
||||
std::getline(ilog,fail_group);
|
||||
fail_group = util::unescape(fail_group);
|
||||
ilog >> fail_test;
|
||||
if (!ilog.good())
|
||||
{
|
||||
fail_group = "";
|
||||
fail_test = -1;
|
||||
truncate_();
|
||||
}
|
||||
else
|
||||
{
|
||||
// test was terminated...
|
||||
tut::test_result tr(fail_group, fail_test, "", tut::test_result::term);
|
||||
register_test_(tr);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
Binary file not shown.
Loading…
Reference in New Issue