If you call TRACE_OFF( ) at the beginning of the program, the output is as follows:
hello
Attempt to delete unknown pointer: 0x1
No user memory leaks!.
Much of the headache of software engineering can be avoided by being deliberate about what you’re doing. You’ve probably been using mental assertions as you’ve crafted your loops and functions anyway, even if you haven’t routinely used the assert( ) macro. If you’ll use assert( ), you’ll find logic errors sooner and end up with more readable code as well. Remember to only use assertions for invariants, though, and not for runtime error handling.
Nothing will give you more peace of mind than thoroughly tested code. If it’s been a hassle for you in the past, use an automated framework, such as the one we’ve presented here, to integrate routine testing into your daily work. You (and your users!) will be glad you did.
1. Write a test program using the TestSuite Framework for the standard vector class that thoroughly tests the following member functions with a vector of integers: push_back( ) (appends an element to the end of the vector), front( ) (returns the first element in the vector), back( ) (returns the last element in the vector), pop_back( ) (removes the last element without returning it), at( ) (returns the element in a specified index position), and size( ) (returns the number of elements). Be sure to verify that vector::at( ) throws a std::out_of_range exception if the supplied index is out of range.
14. Suppose you are asked to develop a class named Rational that supports rational numbers (fractions). The fraction in a Rational object should always be stored in lowest terms, and a denominator of zero is an error. Here is a sample interface for such a Rational class:
class Rational {
public:
Rational(int numerator = 0, int denominator = 1);
Rational operator-() const;
friend Rational operator+(const Rational&,
const Rational&);
friend Rational operator-(const Rational&,
const Rational&);
friend Rational operator*(const Rational&,
const Rational&);
friend Rational operator/(const Rational&,
const Rational&);
friend ostream& operator<<(ostream&,
const Rational&);
friend istream& operator>>(istream&, Rational&);
Rational& operator+=(const Rational&);
Rational& operator-=(const Rational&);
Rational& operator*=(const Rational&);
Rational& operator/=(const Rational&);
friend bool operator<(const Rational&,
const Rational&);
friend bool operator>(const Rational&,
const Rational&);
friend bool operator<=(const Rational&,
const Rational&);
friend bool operator>=(const Rational&,
const Rational&);
friend bool operator==(const Rational&,
const Rational&);
friend bool operator!=(const Rational&,
const Rational&);
};
Write a complete specification for this class, including pre-conditions, post-conditions, and exception specifications.
15. Write a test using the TestSuite framework that thoroughly tests all the specifications from the previous exercise, including testing exceptions.
16. Implement the Rational class so that all the tests from the previous exercise pass. Use assertions only for invariants.
17. The file BuggedSearch.cpp below contains a binary search function that searches the range [beg, end) for what. There are some bugs in the algorithm. Use the trace techniques from this chapter to debug the search function.
// BuggedSearch.cpp
#include "../TestSuite/Test.h"
#include
#include
#include
#include
using namespace std;
// This function is only one with bugs
int* binarySearch(int* beg, int* end, int what) {
while(end - beg != 1) {
if(*beg == what) return beg;
int mid = (end - beg) / 2;
if(what <= beg[mid]) end = beg + mid;
else beg = beg + mid;
}
return 0;
}
class BinarySearchTest : public TestSuite::Test {
enum { sz = 10 };
int* data;
int max; //Track largest number
int current; // Current non-contained number
// Used in notContained()
// Find the next number not contained in the array
int notContained() {
while(data[current] + 1 == data[current + 1])
current++;
if(current >= sz) return max + 1;
int retValue = data[current++] + 1;
return retValue;
}
void setData() {
data = new int[sz];
assert(!max);
// Input values with increments of one. Leave
// out some values on both odd and even indexes.
for(int i = 0; i < sz;
rand() % 2 == 0 ? max += 1 : max += 2)
data[i++] = max;
}
void testInBound() {
// Test locations both odd and even
// not contained and contained
for(int i = sz; --i >=0;)
test_(binarySearch(data, data + sz, data[i]));
for(int i = notContained(); i < max;
i = notContained())
test_(!binarySearch(data, data + sz, i));
}
void testOutBounds() {
// Test lower values
for(int i = data[0]; --i > data[0] - 100;)
test_(!binarySearch(data, data + sz, i));
// Test higher values
for(int i = data[sz - 1];
++i < data[sz -1] + 100;)
test_(!binarySearch(data, data + sz, i));
}
public:
BinarySearchTest() {