diff --git a/linked-list-and-binary-search-tree-c++/BST.cpp b/linked-list-and-binary-search-tree-c++/BST.cpp new file mode 100755 index 0000000..111bb5c --- /dev/null +++ b/linked-list-and-binary-search-tree-c++/BST.cpp @@ -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); diff --git a/linked-list-and-binary-search-tree-c++/BST.h b/linked-list-and-binary-search-tree-c++/BST.h new file mode 100755 index 0000000..4bba7eb --- /dev/null +++ b/linked-list-and-binary-search-tree-c++/BST.h @@ -0,0 +1,122 @@ +#ifndef CS240_BST_H +#define CS240_BST_H + +#include + + +//! 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 diff --git a/linked-list-and-binary-search-tree-c++/LinkedList.cpp b/linked-list-and-binary-search-tree-c++/LinkedList.cpp new file mode 100755 index 0000000..1422314 --- /dev/null +++ b/linked-list-and-binary-search-tree-c++/LinkedList.cpp @@ -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; + } + diff --git a/linked-list-and-binary-search-tree-c++/LinkedList.h b/linked-list-and-binary-search-tree-c++/LinkedList.h new file mode 100755 index 0000000..0008ba2 --- /dev/null +++ b/linked-list-and-binary-search-tree-c++/LinkedList.h @@ -0,0 +1,118 @@ +#ifndef CS240_LINKED_LIST_H +#define CS240_LINKED_LIST_H + +#include + +//! 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 + diff --git a/linked-list-and-binary-search-tree-c++/Makefile b/linked-list-and-binary-search-tree-c++/Makefile new file mode 100644 index 0000000..c20d1a2 --- /dev/null +++ b/linked-list-and-binary-search-tree-c++/Makefile @@ -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 diff --git a/linked-list-and-binary-search-tree-c++/README.md b/linked-list-and-binary-search-tree-c++/README.md new file mode 100644 index 0000000..de59211 --- /dev/null +++ b/linked-list-and-binary-search-tree-c++/README.md @@ -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 diff --git a/linked-list-and-binary-search-tree-c++/colexp b/linked-list-and-binary-search-tree-c++/colexp new file mode 100755 index 0000000..13a4890 --- /dev/null +++ b/linked-list-and-binary-search-tree-c++/colexp @@ -0,0 +1,3 @@ +#!/usr/bin/env sh +echo "Running the Collections Test Passoff" +make -f ./passoff/Makefile $@ diff --git a/linked-list-and-binary-search-tree-c++/collections.html b/linked-list-and-binary-search-tree-c++/collections.html new file mode 100755 index 0000000..8e5c890 --- /dev/null +++ b/linked-list-and-binary-search-tree-c++/collections.html @@ -0,0 +1,153 @@ + + + + + + Collections Part I and II + + + + + +
+

Computer Science 240 :: Advanced Programming

+
+ +
+
+

Collections

+
+
+ +

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.

+ +

Overview

+ +

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 + LinkedList that implements a doubly-linked list and a + class named BST 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 LinkedList and BST + 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.

+ +

Project Files

+ +

Header files for the LinkedList and BST + classes are provided at the following links:

+ +

LinkedList.h

+ +

BST.h

+ +

Your task is to implement all of the methods on the + LinkedList and + BST classes + according to the comments in the header files. You should place + your LinkedList + and BST + implementations in files named LinkedList.cpp and + BST.cpp, + 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 .h files to add private + method and variable declarations, but your method bodies should + go in the .cpp + files.

+ +

The test program will assume that your files are named + LinkedList.h, + LinkedList.cpp, + BST.h, and + BST.cpp Since + Linux file names are case sensitive, capitalization does + matter.

+ +

Restrictions

+ +

For this project you are allowed to use the C++ + string class defined in the <string> header file + (in fact, you must use it to make your code work).

+ +

You are not 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:

+ +
    +
  • <algorithm>
  • + +
  • <deque>
  • + +
  • <list>
  • + +
  • <map>
  • + +
  • <queue>
  • + +
  • <set>
  • + +
  • <stack>
  • + +
  • <vector>
  • +
+ +

Part I

+ +

Implement all of the methods on the LinkedList and BST classes.

+ +

For Part I your code will not be tested for memory + management errors. That will come in Part II.

+ +

Part II

+ +

Ensure that your code does not contain any memory management + errors, as described in the Memory Management Errors + section of the Project I specification. The TAs will use + valgrind to + check your code for memory-related errors when you pass off. + You should run valgrind on your code and + fix any reported bugs before attempting to pass off.

+ +

Not all memory errors are your fault and there are cases of false positives. We offer a file to suppress these for you.

+
+ \ No newline at end of file diff --git a/linked-list-and-binary-search-tree-c++/collections_files/style.css b/linked-list-and-binary-search-tree-c++/collections_files/style.css new file mode 100755 index 0000000..8343b9d --- /dev/null +++ b/linked-list-and-binary-search-tree-c++/collections_files/style.css @@ -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; +} diff --git a/linked-list-and-binary-search-tree-c++/main.cpp b/linked-list-and-binary-search-tree-c++/main.cpp new file mode 100755 index 0000000..5158c8c --- /dev/null +++ b/linked-list-and-binary-search-tree-c++/main.cpp @@ -0,0 +1,17 @@ +#include "BST.h" +#include +#include +#include +#include +#include + +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; +} diff --git a/linked-list-and-binary-search-tree-c++/passoff/Makefile b/linked-list-and-binary-search-tree-c++/passoff/Makefile new file mode 100755 index 0000000..6096b36 --- /dev/null +++ b/linked-list-and-binary-search-tree-c++/passoff/Makefile @@ -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 -- diff --git a/linked-list-and-binary-search-tree-c++/passoff/coll.supp b/linked-list-and-binary-search-tree-c++/passoff/coll.supp new file mode 100755 index 0000000..c2e5972 --- /dev/null +++ b/linked-list-and-binary-search-tree-c++/passoff/coll.supp @@ -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 +} +{ + + Memcheck:Cond + fun:strlen + fun:_ZNSsC1EPKcRKSaIcE + fun:_Z11generateKeyv + fun:_Z14TestLinkedListb + fun:main +} +{ + + Memcheck:Cond + fun:_ZNKSs7compareERKSs + fun:_ZStneIcSt11char_traitsIcESaIcEEbRKSbIT_T0_T1_ES8_ + fun:_Z14TestLinkedListb + fun:main +} +{ + + Memcheck:Cond + fun:_ZNKSs7compareERKSs + fun:_ZStneIcSt11char_traitsIcESaIcEEbRKSbIT_T0_T1_ES8_ + fun:_Z14TestLinkedListb + fun:main +} +{ + + Memcheck:Cond + fun:_ZNKSs7compareERKSs + fun:_ZStneIcSt11char_traitsIcESaIcEEbRKSbIT_T0_T1_ES8_ + fun:_Z12CompareListsRK10LinkedListRSt4listISsSaISsEE + fun:_Z14TestLinkedListb + fun:main +} +{ + + Memcheck:Cond + fun:_ZNKSs7compareERKSs + fun:_ZStneIcSt11char_traitsIcESaIcEEbRKSbIT_T0_T1_ES8_ + fun:_Z12CompareListsRK10LinkedListRSt4listISsSaISsEE + fun:_Z14TestLinkedListb + fun:main +} +{ + + Memcheck:Cond + fun:_ZNKSs7compareERKSs + fun:_ZStneIcSt11char_traitsIcESaIcEEbRKSbIT_T0_T1_ES8_ + fun:_Z12CompareListsRK10LinkedListRSt4listISsSaISsEE + fun:_Z14TestLinkedListb + fun:main +} +{ + + Memcheck:Cond + fun:_ZNKSs7compareERKSs + fun:_ZStneIcSt11char_traitsIcESaIcEEbRKSbIT_T0_T1_ES8_ + fun:_Z12CompareListsRK10LinkedListRSt4listISsSaISsEE + fun:_Z14TestLinkedListb + fun:main +} +{ + + Memcheck:Cond + fun:_ZNKSs7compareERKSs + fun:_ZStneIcSt11char_traitsIcESaIcEEbRKSbIT_T0_T1_ES8_ + fun:_Z12CompareListsRK10LinkedListRSt4listISsSaISsEE + fun:_Z14TestLinkedListb + fun:main +} +{ + + Memcheck:Cond + fun:_ZNKSs7compareERKSs + fun:_ZSteqIcSt11char_traitsIcESaIcEEbRKSbIT_T0_T1_ES8_ + fun:_ZNK10LinkedList4FindERKSsP6LLNode + fun:_Z14TestLinkedListb + fun:main +} +{ + + Memcheck:Cond + fun:_ZNKSs7compareERKSs + fun:_ZStneIcSt11char_traitsIcESaIcEEbRKSbIT_T0_T1_ES8_ + fun:_Z14TestLinkedListb + fun:main +} +{ + + Memcheck:Cond + fun:_ZNKSs7compareERKSs + fun:_ZSteqIcSt11char_traitsIcESaIcEEbRKSbIT_T0_T1_ES8_ + fun:_ZNK10LinkedList4FindERKSsP6LLNode + fun:_Z14TestLinkedListb + fun:main +} +{ + + Memcheck:Cond + fun:strlen + fun:_ZNSsC1EPKcRKSaIcE + fun:_Z11generateKeyv + fun:_Z14TestLinkedListb + fun:main +} +{ + + Memcheck:Cond + fun:_ZNKSs7compareERKSs + fun:_ZSteqIcSt11char_traitsIcESaIcEEbRKSbIT_T0_T1_ES8_ + fun:_ZNK10LinkedList4FindERKSsP6LLNode + fun:_Z14TestLinkedListb + fun:main +} +{ + + 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 +} +{ + + Memcheck:Cond + fun:_ZNKSs7compareERKSs + fun:_ZStneIcSt11char_traitsIcESaIcEEbRKSbIT_T0_T1_ES8_ + fun:_Z14TestLinkedListb + fun:main +} +{ + + Memcheck:Cond + fun:_ZNKSs7compareERKSs + fun:_ZSteqIcSt11char_traitsIcESaIcEEbRKSbIT_T0_T1_ES8_ + fun:_ZNK10LinkedList4FindERKSsP6LLNode + fun:_Z14TestLinkedListb + fun:main +} +{ + + Memcheck:Cond + fun:strlen + fun:_ZNSsC1EPKcRKSaIcE + fun:_Z11generateKeyv + fun:_Z7TestBSTb + fun:main +} +{ + + Memcheck:Cond + fun:_ZNKSs7compareERKSs + fun:_ZStneIcSt11char_traitsIcESaIcEEbRKSbIT_T0_T1_ES8_ + fun:_Z7TestBSTb + fun:main +} +{ + + Memcheck:Cond + fun:_ZNKSs7compareERKSs + fun:_ZSteqIcSt11char_traitsIcESaIcEEbRKSbIT_T0_T1_ES8_ +} +{ + + Memcheck:Cond + fun:_ZNKSs7compareERKSs + fun:_ZSteqIcSt11char_traitsIcESaIcEEbRKSbIT_T0_T1_ES8_ +} +{ + + Memcheck:Cond + fun:_ZNKSs7compareERKSs + fun:_ZStneIcSt11char_traitsIcESaIcEEbRKSbIT_T0_T1_ES8_ + fun:_Z7TestBSTb + fun:main +} +{ + + Memcheck:Cond + fun:strlen + fun:_ZNSsC1EPKcRKSaIcE + fun:_Z11generateKeyv + fun:_Z7TestBSTb + fun:main +} +{ + + Memcheck:Cond + fun:_ZNKSs7compareERKSs + fun:_ZStneIcSt11char_traitsIcESaIcEEbRKSbIT_T0_T1_ES8_ +} +{ + + Memcheck:Cond + fun:strlen + fun:_ZNSsC1EPKcRKSaIcE +} +{ + + Memcheck:Cond + fun:_ZNKSs7compareERKSs + fun:_ZStltIcSt11char_traitsIcESaIcEEbRKSbIT_T0_T1_ES8_ +} +{ + + Memcheck:Cond + fun:_ZNKSs7compareERKSs + fun:_ZStltIcSt11char_traitsIcESaIcEEbRKSbIT_T0_T1_ES8_ +} +{ + + Memcheck:Cond + fun:_ZNKSs7compareERKSs +} +{ + + Memcheck:Cond + fun:strlen + fun:_ZNSsC1EPKcRKSaIcE + fun:_Z11generateKeyv + fun:_Z14TestLinkedListb + fun:main +} +{ + + Memcheck:Cond + fun:_ZNKSs7compareERKSs + fun:_ZStneIcSt11char_traitsIcESaIcEEbRKSbIT_T0_T1_ES8_ + fun:_Z14TestLinkedListb + fun:main +} +{ + + Memcheck:Cond + fun:_ZNKSs7compareERKSs + fun:_ZStneIcSt11char_traitsIcESaIcEEbRKSbIT_T0_T1_ES8_ + fun:_Z14TestLinkedListb + fun:main +} +{ + + Memcheck:Cond + fun:_ZNKSs7compareERKSs + fun:_ZStneIcSt11char_traitsIcESaIcEEbRKSbIT_T0_T1_ES8_ + fun:_Z12CompareListsRK10LinkedListRSt4listISsSaISsEE + fun:_Z14TestLinkedListb + fun:main +} +{ + + Memcheck:Cond + fun:_ZNKSs7compareERKSs + fun:_ZStneIcSt11char_traitsIcESaIcEEbRKSbIT_T0_T1_ES8_ + fun:_Z12CompareListsRK10LinkedListRSt4listISsSaISsEE + fun:_Z14TestLinkedListb + fun:main +} +{ + + Memcheck:Cond + fun:_ZNKSs7compareERKSs + fun:_ZStneIcSt11char_traitsIcESaIcEEbRKSbIT_T0_T1_ES8_ + fun:_Z12CompareListsRK10LinkedListRSt4listISsSaISsEE + fun:_Z14TestLinkedListb + fun:main +} +{ + + Memcheck:Cond + fun:_ZNKSs7compareERKSs + fun:_ZStneIcSt11char_traitsIcESaIcEEbRKSbIT_T0_T1_ES8_ + fun:_Z12CompareListsRK10LinkedListRSt4listISsSaISsEE + fun:_Z14TestLinkedListb + fun:main +} +{ + + Memcheck:Cond + fun:_ZNKSs7compareERKSs + fun:_ZStneIcSt11char_traitsIcESaIcEEbRKSbIT_T0_T1_ES8_ +} +{ + + Memcheck:Cond + fun:_ZNKSs7compareERKSs + fun:_ZNK10LinkedList4FindERKSsP6LLNode + fun:_Z14TestLinkedListb + fun:main +} +{ + + Memcheck:Cond + fun:_ZNKSs7compareERKSs + fun:_ZStneIcSt11char_traitsIcESaIcEEbRKSbIT_T0_T1_ES8_ + fun:_Z14TestLinkedListb + fun:main +} +{ + + Memcheck:Cond + fun:_ZNKSs7compareERKSs + fun:_ZNK10LinkedList4FindERKSsP6LLNode + fun:_Z14TestLinkedListb + fun:main +} +{ + + Memcheck:Cond + fun:strlen + fun:_ZNSsC1EPKcRKSaIcE + fun:_Z11generateKeyv + fun:_Z14TestLinkedListb + fun:main +} +{ + + Memcheck:Cond + fun:_ZNKSs7compareERKSs +} +{ + + Memcheck:Cond + fun:_ZNKSs7compareERKSs + fun:_ZSteqIcSt11char_traitsIcESaIcEEbRKSbIT_T0_T1_ES8_ +} +{ + + Memcheck:Cond + fun:_ZNKSs7compareERKSs + fun:_ZStneIcSt11char_traitsIcESaIcEEbRKSbIT_T0_T1_ES8_ + fun:_Z14TestLinkedListb + fun:main +} +{ + + Memcheck:Cond + fun:_ZNKSs7compareERKSs + fun:_ZNK10LinkedList4FindERKSsP6LLNode + fun:_Z14TestLinkedListb + fun:main +} +{ + + Memcheck:Cond + fun:strlen + fun:_ZNSsC1EPKcRKSaIcE + fun:_Z11generateKeyv + fun:_Z7TestBSTb + fun:main +} +{ + + Memcheck:Cond + fun:_ZNKSs7compareERKSs + fun:_ZStneIcSt11char_traitsIcESaIcEEbRKSbIT_T0_T1_ES8_ + fun:_Z7TestBSTb + fun:main +} +{ + + Memcheck:Cond + fun:_ZNKSs7compareERKSs +} +{ + + Memcheck:Cond + fun:_ZNKSs7compareERKSs +} +{ + + Memcheck:Cond + fun:_ZNKSs7compareERKSs +} +{ + + Memcheck:Cond + fun:_ZNKSs7compareERKSs +} +{ + + Memcheck:Cond + fun:_ZNKSs7compareERKSs + fun:_ZStneIcSt11char_traitsIcESaIcEEbRKSbIT_T0_T1_ES8_ + fun:_Z7TestBSTb + fun:main +} +{ + + Memcheck:Cond + fun:strlen + fun:_ZNSsC1EPKcRKSaIcE + fun:_Z11generateKeyv + fun:_Z7TestBSTb + fun:main +} +{ + + Memcheck:Cond + fun:_ZNKSs7compareERKSs + fun:_ZStneIcSt11char_traitsIcESaIcEEbRKSbIT_T0_T1_ES8_ +} +{ + + Memcheck:Cond + fun:strlen + fun:_ZNSsC1EPKcRKSaIcE + fun:_Z11generateKeyv + fun:_Z7TestBSTb + fun:main +} +{ + + Memcheck:Cond + fun:_ZNKSs7compareERKSs +} +{ + + Memcheck:Cond + fun:_ZNKSs7compareERKSs + fun:_ZStltIcSt11char_traitsIcESaIcEEbRKSbIT_T0_T1_ES8_ +} +{ + + Memcheck:Cond + fun:_ZNKSs7compareERKSs +} +{ + + Memcheck:Cond + fun:_ZNKSs7compareERKSs +} +{ + + Memcheck:Cond + fun:strlen + fun:_ZNSsC1EPKcRKSaIcE + fun:_Z11generateKeyv + fun:_Z14TestLinkedListb + fun:main +} +{ + + Memcheck:Cond + fun:_ZNKSs7compareERKSs + fun:_ZStneIcSt11char_traitsIcESaIcEEbRKSbIT_T0_T1_ES8_ + fun:_Z14TestLinkedListb + fun:main +} +{ + + Memcheck:Cond + fun:_ZNKSs7compareERKSs + fun:_ZStneIcSt11char_traitsIcESaIcEEbRKSbIT_T0_T1_ES8_ + fun:_Z14TestLinkedListb + fun:main +} +{ + + Memcheck:Cond + fun:_ZNKSs7compareERKSs + fun:_ZStneIcSt11char_traitsIcESaIcEEbRKSbIT_T0_T1_ES8_ + fun:_Z12CompareListsRK10LinkedListRSt4listISsSaISsEE + fun:_Z14TestLinkedListb + fun:main +} +{ + + Memcheck:Cond + fun:_ZNKSs7compareERKSs + fun:_ZStneIcSt11char_traitsIcESaIcEEbRKSbIT_T0_T1_ES8_ + fun:_Z12CompareListsRK10LinkedListRSt4listISsSaISsEE + fun:_Z14TestLinkedListb + fun:main +} +{ + + Memcheck:Cond + fun:_ZNKSs7compareERKSs + fun:_ZStneIcSt11char_traitsIcESaIcEEbRKSbIT_T0_T1_ES8_ + fun:_Z12CompareListsRK10LinkedListRSt4listISsSaISsEE + fun:_Z14TestLinkedListb + fun:main +} +{ + + Memcheck:Cond + fun:_ZNKSs7compareERKSs + fun:_ZStneIcSt11char_traitsIcESaIcEEbRKSbIT_T0_T1_ES8_ + fun:_Z12CompareListsRK10LinkedListRSt4listISsSaISsEE + fun:_Z14TestLinkedListb + fun:main +} +{ + + Memcheck:Cond + fun:_ZNKSs7compareERKSs + fun:_ZStneIcSt11char_traitsIcESaIcEEbRKSbIT_T0_T1_ES8_ + fun:_Z12CompareListsRK10LinkedListRSt4listISsSaISsEE + fun:_Z14TestLinkedListb + fun:main +} +{ + + Memcheck:Cond + fun:_ZNKSs7compareERKSs + fun:_ZSteqIcSt11char_traitsIcESaIcEEbRKSbIT_T0_T1_ES8_ +} +{ + + Memcheck:Cond + fun:_ZNKSs7compareERKSs + fun:_ZStneIcSt11char_traitsIcESaIcEEbRKSbIT_T0_T1_ES8_ + fun:_Z14TestLinkedListb + fun:main +} +{ + + Memcheck:Cond + fun:_ZNKSs7compareERKSs + fun:_ZSteqIcSt11char_traitsIcESaIcEEbRKSbIT_T0_T1_ES8_ +} +{ + + Memcheck:Cond + fun:strlen + fun:_ZNSsC1EPKcRKSaIcE + fun:_Z11generateKeyv + fun:_Z14TestLinkedListb + fun:main +} +{ + + Memcheck:Cond + fun:_ZNKSs7compareERKSs + fun:_ZSteqIcSt11char_traitsIcESaIcEEbRKSbIT_T0_T1_ES8_ +} +{ + + 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 +} +{ + + Memcheck:Cond + fun:_ZNKSs7compareERKSs + fun:_ZStneIcSt11char_traitsIcESaIcEEbRKSbIT_T0_T1_ES8_ + fun:_Z14TestLinkedListb + fun:main +} +{ + + Memcheck:Cond + fun:_ZNKSs7compareERKSs + fun:_ZSteqIcSt11char_traitsIcESaIcEEbRKSbIT_T0_T1_ES8_ +} +{ + + Memcheck:Cond + fun:strlen + fun:_ZNSsC1EPKcRKSaIcE + fun:_Z11generateKeyv + fun:_Z7TestBSTb + fun:main +} +{ + + Memcheck:Cond + fun:strlen + fun:_ZNSsC1EPKcRKSaIcE + fun:_Z11generateKeyv + fun:_Z7TestBSTb + fun:main +} +{ + + Memcheck:Cond + fun:strlen + fun:_ZNSsC1EPKcRKSaIcE + fun:_Z11generateKeyv + fun:_Z7TestBSTb + fun:main +} +{ + + 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 +} +{ + + 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 +} +{ + + 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 +} +{ + + 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 +} diff --git a/linked-list-and-binary-search-tree-c++/passoff/test_bst.cpp b/linked-list-and-binary-search-tree-c++/passoff/test_bst.cpp new file mode 100755 index 0000000..4a2024b --- /dev/null +++ b/linked-list-and-binary-search-tree-c++/passoff/test_bst.cpp @@ -0,0 +1,368 @@ +#include +#include +#include +#include +#include +#include +#include + +#include "tut/tut.hpp" +#include "BST.h" + +#define NULL_NODE (static_cast(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 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 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(chosen.size())); + } + + template<> + template<> + void tObject::test<4> () + { + set_test_name("Find"); + gCurrentTest = get_test_name(); + BST bst; + initBST(bst); + + set::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::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 randomv(chosen.begin(), chosen.end()); + random_shuffle(randomv.begin(), randomv.end()); + + for(vector::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 +} diff --git a/linked-list-and-binary-search-tree-c++/passoff/test_ll.cpp b/linked-list-and-binary-search-tree-c++/passoff/test_ll.cpp new file mode 100755 index 0000000..2d21c90 --- /dev/null +++ b/linked-list-and-binary-search-tree-c++/passoff/test_ll.cpp @@ -0,0 +1,407 @@ +#include +#include +#include +#include +#include +#include +#include + +#include "tut/tut.hpp" +#include "LinkedList.h" + +#define NULL_NODE (static_cast(NULL)) + +using namespace std; + +bool gDoSmall = true; +extern std::string gCurrentTest; + +string generateKey(); +void CompareLists(const LinkedList & aList, list & 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::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::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 chosen; + list master; +}; + +void CompareLists(const LinkedList & aList, list & master){ + const LLNode * curNode = aList.GetFirst(); + + list::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 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(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::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 sorted(master.begin(), master.end()); + sorted.sort(); + + tut::ensure_equals("Insert() - Size != Number of strings inserted", aList.GetSize(), static_cast(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 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 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 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 sorted(master.begin(), master.end()); + sorted.sort(); + + list::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 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(master.size())); + } + + for(set::iterator setIter = chosen.begin(); setIter != chosen.end(); ++setIter) + { + LLNode* curNode = aList.Find(*setIter, NULL); + list::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::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); + } +} + diff --git a/linked-list-and-binary-search-tree-c++/passoff/test_runner.cpp b/linked-list-and-binary-search-tree-c++/passoff/test_runner.cpp new file mode 100755 index 0000000..8f3ebe4 --- /dev/null +++ b/linked-list-and-binary-search-tree-c++/passoff/test_runner.cpp @@ -0,0 +1,111 @@ +#include +#include +#include +#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(&testGroup)->default_value(gTestGroupDefault), "Selects which test group to run") + ("number,n", po::value(&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; +} diff --git a/linked-list-and-binary-search-tree-c++/passoff/tut/readme b/linked-list-and-binary-search-tree-c++/passoff/tut/readme new file mode 100755 index 0000000..2d28735 --- /dev/null +++ b/linked-list-and-binary-search-tree-c++/passoff/tut/readme @@ -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 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 + +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. 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 + +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 + +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 + +namespace tut +{ + struct shared_ptr_data + { + + }; + + typedef test_group 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 + +namespace tut +{ + struct huge_test_data + { + }; + + // test group with maximum 500 tests + typedef test_group 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 + +namespace tut +{ + struct shared_ptr_data{}; + + typedef test_group 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::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 +#include + +namespace tut +{ + struct shared_ptr_data + { + struct keepee{ int data; }; + }; + + typedef test_group testgroup; + typedef testgroup::object testobject; + testgroup shared_ptr_testgroup("shared_ptr"); + + /** + * Checks default constructor. + */ + template<> + template<> + void testobject::test<1>() + { + shared_ptr 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 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 sp1(new keepee()); + shared_ptr 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 + +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 + +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. diff --git a/linked-list-and-binary-search-tree-c++/passoff/tut/tut.hpp b/linked-list-and-binary-search-tree-c++/passoff/tut/tut.hpp new file mode 100755 index 0000000..cb0a06a --- /dev/null +++ b/linked-list-and-binary-search-tree-c++/passoff/tut/tut.hpp @@ -0,0 +1,1180 @@ +#ifndef TUT_H_GUARD +#define TUT_H_GUARD + +#include +#include +#include +#include +#include +#include + +#if defined(TUT_USE_SEH) +#include +#include +#endif + +/** + * Template Unit Tests Framework for C++. + * http://tut.dozen.ru + * + * @author Vladimir Dyuzhev, Vladimir.Dyuzhev@gmail.com + */ +namespace tut +{ + +/** + * The base for all TUT exceptions. + */ +struct tut_error : public std::exception +{ + tut_error(const std::string& msg) + : err_msg(msg) + { + } + + ~tut_error() throw() + { + } + + const char* what() const throw() + { + return err_msg.c_str(); + } + +private: + + std::string err_msg; +}; + +/** + * Exception to be throwed when attempted to execute + * missed test by number. + */ +struct no_such_test : public tut_error +{ + no_such_test() + : tut_error("no such test") + { + } + + ~no_such_test() throw() + { + } +}; + +/** + * No such test and passed test number is higher than + * any test number in current group. Used in one-by-one + * test running when upper bound is not known. + */ +struct beyond_last_test : public no_such_test +{ + beyond_last_test() + { + } + + ~beyond_last_test() throw() + { + } +}; + +/** + * Group not found exception. + */ +struct no_such_group : public tut_error +{ + no_such_group(const std::string& grp) + : tut_error(grp) + { + } + + ~no_such_group() throw() + { + } +}; + +/** + * Internal exception to be throwed when + * no more tests left in group or journal. + */ +struct no_more_tests +{ + no_more_tests() + { + } + + ~no_more_tests() throw() + { + } +}; + +/** + * Internal exception to be throwed when + * test constructor has failed. + */ +struct bad_ctor : public tut_error +{ + bad_ctor(const std::string& msg) + : tut_error(msg) + { + } + + ~bad_ctor() throw() + { + } +}; + +/** + * Exception to be throwed when ensure() fails or fail() called. + */ +struct failure : public tut_error +{ + failure(const std::string& msg) + : tut_error(msg) + { + } + + ~failure() throw() + { + } +}; + +/** + * Exception to be throwed when test desctructor throwed an exception. + */ +struct warning : public tut_error +{ + warning(const std::string& msg) + : tut_error(msg) + { + } + + ~warning() throw() + { + } +}; + +/** + * Exception to be throwed when test issued SEH (Win32) + */ +struct seh : public tut_error +{ + seh(const std::string& msg) + : tut_error(msg) + { + } + + ~seh() throw() + { + } +}; + +/** + * Return type of runned test/test group. + * + * For test: contains result of test and, possible, message + * for failure or exception. + */ +struct test_result +{ + /** + * Test group name. + */ + std::string group; + + /** + * Test number in group. + */ + int test; + + /** + * Test name (optional) + */ + std::string name; + + /** + * ok - test finished successfully + * fail - test failed with ensure() or fail() methods + * ex - test throwed an exceptions + * warn - test finished successfully, but test destructor throwed + * term - test forced test application to terminate abnormally + */ + enum result_type + { + ok, + fail, + ex, + warn, + term, + ex_ctor + }; + + result_type result; + + /** + * Exception message for failed test. + */ + std::string message; + std::string exception_typeid; + + /** + * Default constructor. + */ + test_result() + : test(0), + result(ok) + { + } + + /** + * Constructor. + */ + test_result(const std::string& grp, int pos, + const std::string& test_name, result_type res) + : group(grp), + test(pos), + name(test_name), + result(res) + { + } + + /** + * Constructor with exception. + */ + test_result(const std::string& grp,int pos, + const std::string& test_name, result_type res, + const std::exception& ex) + : group(grp), + test(pos), + name(test_name), + result(res), + message(ex.what()), + exception_typeid(typeid(ex).name()) + { + } +}; + +/** + * Interface. + * Test group operations. + */ +struct group_base +{ + virtual ~group_base() + { + } + + // execute tests iteratively + virtual void rewind() = 0; + virtual test_result run_next() = 0; + + // execute one test + virtual test_result run_test(int n) = 0; +}; + +/** + * Test runner callback interface. + * Can be implemented by caller to update + * tests results in real-time. User can implement + * any of callback methods, and leave unused + * in default implementation. + */ +struct callback +{ + /** + * Virtual destructor is a must for subclassed types. + */ + virtual ~callback() + { + } + + /** + * Called when new test run started. + */ + virtual void run_started() + { + } + + /** + * Called when a group started + * @param name Name of the group + */ + virtual void group_started(const std::string& /*name*/) + { + } + + /** + * Called when a test finished. + * @param tr Test results. + */ + virtual void test_completed(const test_result& /*tr*/) + { + } + + /** + * Called when a group is completed + * @param name Name of the group + */ + virtual void group_completed(const std::string& /*name*/) + { + } + + /** + * Called when all tests in run completed. + */ + virtual void run_completed() + { + } +}; + +/** + * Typedef for runner::list_groups() + */ +typedef std::vector groupnames; + +/** + * Test runner. + */ +class test_runner +{ + +public: + + /** + * Constructor + */ + test_runner() + : callback_(&default_callback_) + { + } + + /** + * Stores another group for getting by name. + */ + void register_group(const std::string& name, group_base* gr) + { + if (gr == 0) + { + throw tut_error("group shall be non-null"); + } + + // TODO: inline variable + groups::iterator found = groups_.find(name); + if (found != groups_.end()) + { + std::string msg("attempt to add already existent group " + name); + // this exception terminates application so we use cerr also + // TODO: should this message appear in stream? + std::cerr << msg << std::endl; + throw tut_error(msg); + } + + groups_[name] = gr; + } + + /** + * Stores callback object. + */ + void set_callback(callback* cb) + { + callback_ = cb == 0 ? &default_callback_ : cb; + } + + /** + * Returns callback object. + */ + callback& get_callback() const + { + return *callback_; + } + + /** + * Returns list of known test groups. + */ + const groupnames list_groups() const + { + groupnames ret; + const_iterator i = groups_.begin(); + const_iterator e = groups_.end(); + while (i != e) + { + ret.push_back(i->first); + ++i; + } + return ret; + } + + /** + * Runs all tests in all groups. + * @param callback Callback object if exists; null otherwise + */ + void run_tests() const + { + callback_->run_started(); + + const_iterator i = groups_.begin(); + const_iterator e = groups_.end(); + while (i != e) + { + callback_->group_started(i->first); + try + { + run_all_tests_in_group_(i); + } + catch (const no_more_tests&) + { + callback_->group_completed(i->first); + } + + ++i; + } + + callback_->run_completed(); + } + + /** + * Runs all tests in specified group. + */ + void run_tests(const std::string& group_name) const + { + callback_->run_started(); + + const_iterator i = groups_.find(group_name); + if (i == groups_.end()) + { + callback_->run_completed(); + throw no_such_group(group_name); + } + + callback_->group_started(group_name); + try + { + run_all_tests_in_group_(i); + } + catch (const no_more_tests&) + { + // ok + } + + callback_->group_completed(group_name); + callback_->run_completed(); + } + + /** + * Runs one test in specified group. + */ + test_result run_test(const std::string& group_name, int n) const + { + callback_->run_started(); + + const_iterator i = groups_.find(group_name); + if (i == groups_.end()) + { + callback_->run_completed(); + throw no_such_group(group_name); + } + + callback_->group_started(group_name); + try + { + test_result tr = i->second->run_test(n); + callback_->test_completed(tr); + callback_->group_completed(group_name); + callback_->run_completed(); + return tr; + } + catch (const beyond_last_test&) + { + callback_->group_completed(group_name); + callback_->run_completed(); + throw; + } + catch (const no_such_test&) + { + callback_->group_completed(group_name); + callback_->run_completed(); + throw; + } + } + +protected: + + typedef std::map groups; + typedef groups::iterator iterator; + typedef groups::const_iterator const_iterator; + groups groups_; + + callback default_callback_; + callback* callback_; + + +private: + + void run_all_tests_in_group_(const_iterator i) const + { + i->second->rewind(); + for ( ;; ) + { + test_result tr = i->second->run_next(); + callback_->test_completed(tr); + + if (tr.result == test_result::ex_ctor) + { + throw no_more_tests(); + } + } + } +}; + +/** + * Singleton for test_runner implementation. + * Instance with name runner_singleton shall be implemented + * by user. + */ +class test_runner_singleton +{ +public: + + static test_runner& get() + { + static test_runner tr; + return tr; + } +}; + +extern test_runner_singleton runner; + +/** + * Test object. Contains data test run upon and default test method + * implementation. Inherited from Data to allow tests to + * access test data as members. + */ +template +class test_object : public Data +{ +public: + + /** + * Default constructor + */ + test_object() + { + } + + void set_test_name(const std::string& current_test_name) + { + current_test_name_ = current_test_name; + } + + const std::string& get_test_name() const + { + return current_test_name_; + } + + /** + * Default do-nothing test. + */ + template + void test() + { + called_method_was_a_dummy_test_ = true; + } + + /** + * The flag is set to true by default (dummy) test. + * Used to detect usused test numbers and avoid unnecessary + * test object creation which may be time-consuming depending + * on operations described in Data::Data() and Data::~Data(). + * TODO: replace with throwing special exception from default test. + */ + bool called_method_was_a_dummy_test_; + +private: + + std::string current_test_name_; +}; + +namespace +{ + +/** + * Tests provided condition. + * Throws if false. + */ +void ensure(bool cond) +{ + if (!cond) + { + // TODO: default ctor? + throw failure(""); + } +} + +/** + * Tests provided condition. + * Throws if true. + */ +void ensure_not(bool cond) +{ + ensure(!cond); +} + +/** + * Tests provided condition. + * Throws if false. + */ +template +void ensure(const T msg, bool cond) +{ + if (!cond) + { + throw failure(msg); + } +} + +/** + * Tests provided condition. + * Throws if true. + */ +template +void ensure_not(const T msg, bool cond) +{ + ensure(msg, !cond); +} + +/** + * Tests two objects for being equal. + * Throws if false. + * + * NB: both T and Q must have operator << defined somewhere, or + * client code will not compile at all! + */ +template +void ensure_equals(const char* msg, const Q& actual, const T& expected) +{ + if (expected != actual) + { + std::stringstream ss; + ss << (msg ? msg : "") + << (msg ? ":" : "") + << " expected '" + << expected + << "' actual '" + << actual + << '\''; + throw failure(ss.str().c_str()); + } +} + +template +void ensure_equals(const Q& actual, const T& expected) +{ + ensure_equals<>(0, actual, expected); +} + +/** + * Tests two objects for being at most in given distance one from another. + * Borders are excluded. + * Throws if false. + * + * NB: T must have operator << defined somewhere, or + * client code will not compile at all! Also, T shall have + * operators + and -, and be comparable. + */ +template +void ensure_distance(const char* msg, const T& actual, const T& expected, + const T& distance) +{ + if (expected-distance >= actual || expected+distance <= actual) + { + std::stringstream ss; + ss << (msg ? msg : "") + << (msg? ":" : "") + << " expected (" + << expected-distance + << " - " + << expected+distance + << ") actual '" + << actual + << '\''; + throw failure(ss.str().c_str()); + } +} + +template +void ensure_distance(const T& actual, const T& expected, const T& distance) +{ + ensure_distance<>(0, actual, expected, distance); +} + +/** + * Unconditionally fails with message. + */ +void fail(const char* msg = "") +{ + throw failure(msg); +} + +} // end of namespace + +/** + * Walks through test tree and stores address of each + * test method in group. Instantiation stops at 0. + */ +template +struct tests_registerer +{ + static void reg(Group& group) + { + group.reg(n, &Test::template test); + tests_registerer::reg(group); + } +}; + +template +struct tests_registerer +{ + static void reg(Group&) + { + } +}; + +/** + * Test group; used to recreate test object instance for + * each new test since we have to have reinitialized + * Data base class. + */ +template +class test_group : public group_base +{ + const char* name_; + + typedef void (test_object::*testmethod)(); + typedef std::map tests; + typedef typename tests::iterator tests_iterator; + typedef typename tests::const_iterator tests_const_iterator; + typedef typename tests::const_reverse_iterator + tests_const_reverse_iterator; + typedef typename tests::size_type size_type; + + tests tests_; + tests_iterator current_test_; + + /** + * Exception-in-destructor-safe smart-pointer class. + */ + template + class safe_holder + { + T* p_; + bool permit_throw_in_dtor; + + safe_holder(const safe_holder&); + safe_holder& operator=(const safe_holder&); + + public: + safe_holder() + : p_(0), + permit_throw_in_dtor(false) + { + } + + ~safe_holder() + { + release(); + } + + T* operator->() const + { + return p_; + } + + T* get() const + { + return p_; + } + + /** + * Tell ptr it can throw from destructor. Right way is to + * use std::uncaught_exception(), but some compilers lack + * correct implementation of the function. + */ + void permit_throw() + { + permit_throw_in_dtor = true; + } + + /** + * Specially treats exceptions in test object destructor; + * if test itself failed, exceptions in destructor + * are ignored; if test was successful and destructor failed, + * warning exception throwed. + */ + void release() + { + try + { + if (delete_obj() == false) + { + throw warning("destructor of test object raised" + " an SEH exception"); + } + } + catch (const std::exception& ex) + { + if (permit_throw_in_dtor) + { + std::string msg = "destructor of test object raised" + " exception: "; + msg += ex.what(); + throw warning(msg); + } + } + catch( ... ) + { + if (permit_throw_in_dtor) + { + throw warning("destructor of test object raised an" + " exception"); + } + } + } + + /** + * Re-init holder to get brand new object. + */ + void reset() + { + release(); + permit_throw_in_dtor = false; + p_ = new T(); + } + + bool delete_obj() + { +#if defined(TUT_USE_SEH) + __try + { +#endif + T* p = p_; + p_ = 0; + delete p; +#if defined(TUT_USE_SEH) + } + __except(handle_seh_(::GetExceptionCode())) + { + if (permit_throw_in_dtor) + { + return false; + } + } +#endif + return true; + } + }; + +public: + + typedef test_object object; + + /** + * Creates and registers test group with specified name. + */ + test_group(const char* name) + : name_(name) + { + // register itself + runner.get().register_group(name_,this); + + // register all tests + tests_registerer::reg(*this); + } + + /** + * This constructor is used in self-test run only. + */ + test_group(const char* name, test_runner& another_runner) + : name_(name) + { + // register itself + another_runner.register_group(name_, this); + + // register all tests + tests_registerer, test_group, + MaxTestsInGroup>::reg(*this); + }; + + /** + * Registers test method under given number. + */ + void reg(int n, testmethod tm) + { + tests_[n] = tm; + } + + /** + * Reset test position before first test. + */ + void rewind() + { + current_test_ = tests_.begin(); + } + + /** + * Runs next test. + */ + test_result run_next() + { + if (current_test_ == tests_.end()) + { + throw no_more_tests(); + } + + // find next user-specialized test + safe_holder obj; + while (current_test_ != tests_.end()) + { + try + { + return run_test_(current_test_++, obj); + } + catch (const no_such_test&) + { + continue; + } + } + + throw no_more_tests(); + } + + /** + * Runs one test by position. + */ + test_result run_test(int n) + { + // beyond tests is special case to discover upper limit + if (tests_.rbegin() == tests_.rend()) + { + throw beyond_last_test(); + } + + if (tests_.rbegin()->first < n) + { + throw beyond_last_test(); + } + + // withing scope; check if given test exists + tests_iterator ti = tests_.find(n); + if (ti == tests_.end()) + { + throw no_such_test(); + } + + safe_holder obj; + return run_test_(ti, obj); + } + +private: + + /** + * VC allows only one exception handling type per function, + * so I have to split the method. + * + * TODO: refactoring needed! + */ + test_result run_test_(const tests_iterator& ti, safe_holder& obj) + { + std::string current_test_name; + try + { + if (run_test_seh_(ti->second,obj, current_test_name) == false) + { + throw seh("seh"); + } + } + catch (const no_such_test&) + { + throw; + } + catch (const warning& ex) + { + // test ok, but destructor failed + if (obj.get()) + { + current_test_name = obj->get_test_name(); + } + test_result tr(name_,ti->first, current_test_name, + test_result::warn, ex); + return tr; + } + catch (const failure& ex) + { + // test failed because of ensure() or similar method + if (obj.get()) + { + current_test_name = obj->get_test_name(); + } + test_result tr(name_,ti->first, current_test_name, + test_result::fail, ex); + return tr; + } + catch (const seh& ex) + { + // test failed with sigsegv, divide by zero, etc + if (obj.get()) + { + current_test_name = obj->get_test_name(); + } + test_result tr(name_, ti->first, current_test_name, + test_result::term, ex); + return tr; + } + catch (const bad_ctor& ex) + { + // test failed because test ctor failed; stop the whole group + if (obj.get()) + { + current_test_name = obj->get_test_name(); + } + test_result tr(name_, ti->first, current_test_name, + test_result::ex_ctor, ex); + return tr; + } + catch (const std::exception& ex) + { + // test failed with std::exception + if (obj.get()) + { + current_test_name = obj->get_test_name(); + } + test_result tr(name_, ti->first, current_test_name, + test_result::ex, ex); + return tr; + } + catch (...) + { + // test failed with unknown exception + if (obj.get()) + { + current_test_name = obj->get_test_name(); + } + test_result tr(name_, ti->first, current_test_name, + test_result::ex); + return tr; + } + + // test passed + test_result tr(name_,ti->first, current_test_name, test_result::ok); + return tr; + } + + /** + * Runs one under SEH if platform supports it. + */ + bool run_test_seh_(testmethod tm, safe_holder& obj, + std::string& current_test_name) + { +#if defined(TUT_USE_SEH) + __try + { +#endif + if (obj.get() == 0) + { + reset_holder_(obj); + } + + obj->called_method_was_a_dummy_test_ = false; + +#if defined(TUT_USE_SEH) + + __try + { +#endif + (obj.get()->*tm)(); +#if defined(TUT_USE_SEH) + } + __except(handle_seh_(::GetExceptionCode())) + { + // throw seh("SEH"); + current_test_name = obj->get_test_name(); + return false; + } +#endif + + if (obj->called_method_was_a_dummy_test_) + { + // do not call obj.release(); reuse object + throw no_such_test(); + } + + current_test_name = obj->get_test_name(); + obj.permit_throw(); + obj.release(); +#if defined(TUT_USE_SEH) + } + __except(handle_seh_(::GetExceptionCode())) + { + return false; + } +#endif + return true; + } + + void reset_holder_(safe_holder& obj) + { + try + { + obj.reset(); + } + catch (const std::exception& ex) + { + throw bad_ctor(ex.what()); + } + catch (...) + { + throw bad_ctor("test constructor has generated an exception;" + " group execution is terminated"); + } + } +}; + +#if defined(TUT_USE_SEH) +/** + * Decides should we execute handler or ignore SE. + */ +inline int handle_seh_(DWORD excode) +{ + switch(excode) + { + case EXCEPTION_ACCESS_VIOLATION: + case EXCEPTION_DATATYPE_MISALIGNMENT: + case EXCEPTION_BREAKPOINT: + case EXCEPTION_SINGLE_STEP: + case EXCEPTION_ARRAY_BOUNDS_EXCEEDED: + case EXCEPTION_FLT_DENORMAL_OPERAND: + case EXCEPTION_FLT_DIVIDE_BY_ZERO: + case EXCEPTION_FLT_INEXACT_RESULT: + case EXCEPTION_FLT_INVALID_OPERATION: + case EXCEPTION_FLT_OVERFLOW: + case EXCEPTION_FLT_STACK_CHECK: + case EXCEPTION_FLT_UNDERFLOW: + case EXCEPTION_INT_DIVIDE_BY_ZERO: + case EXCEPTION_INT_OVERFLOW: + case EXCEPTION_PRIV_INSTRUCTION: + case EXCEPTION_IN_PAGE_ERROR: + case EXCEPTION_ILLEGAL_INSTRUCTION: + case EXCEPTION_NONCONTINUABLE_EXCEPTION: + case EXCEPTION_STACK_OVERFLOW: + case EXCEPTION_INVALID_DISPOSITION: + case EXCEPTION_GUARD_PAGE: + case EXCEPTION_INVALID_HANDLE: + return EXCEPTION_EXECUTE_HANDLER; + }; + + return EXCEPTION_CONTINUE_SEARCH; +} +#endif +} + +#endif + diff --git a/linked-list-and-binary-search-tree-c++/passoff/tut/tut_reporter.hpp b/linked-list-and-binary-search-tree-c++/passoff/tut/tut_reporter.hpp new file mode 100755 index 0000000..9c7f5d5 --- /dev/null +++ b/linked-list-and-binary-search-tree-c++/passoff/tut/tut_reporter.hpp @@ -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 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 diff --git a/linked-list-and-binary-search-tree-c++/passoff/tut/tut_restartable.hpp b/linked-list-and-binary-search-tree-c++/passoff/tut/tut_restartable.hpp new file mode 100755 index 0000000..b30bb1e --- /dev/null +++ b/linked-list-and-binary-search-tree-c++/passoff/tut/tut_restartable.hpp @@ -0,0 +1,394 @@ +#ifndef TUT_RESTARTABLE_H_GUARD +#define TUT_RESTARTABLE_H_GUARD + +#include "tut.hpp" +#include +#include +#include + +/** + * 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 + diff --git a/linked-list-and-binary-search-tree-c++/test_runner b/linked-list-and-binary-search-tree-c++/test_runner new file mode 100755 index 0000000..1e15487 Binary files /dev/null and b/linked-list-and-binary-search-tree-c++/test_runner differ