#ifndef COUNTER_H
#define COUNTER_H
#include <exception>
#include <iostream>
#include <typeinfo>
#include <strstream>
class TestException : public std::exception
{
virtual const char* what() const throw() {
return "TestException";
}
};
class Counter {
private:
// This variable indicates the number of the exception point
// that we are up to executing in the code.
static int sExceptionPointCount;
// The number of the exception point which should throw.
static int sThrowCount;
static bool sDontThrow;
// This counts the number of times new has successfully returned
// a non-null result, minus the number of times a non-null ptr
// has been passed to delete.
static int sNewCount;
static int sPassCount;
static int sFailCount;
static std::ostream* mOs;
public:
// This function should be called wherever an
// exception could be generated in the real code.
static void CouldThrow() throw ( TestException );
// Functions for the test harness to use.
static void SetThrowCount( int inCount ) throw();
// Prevents throwing until next call to SetThrowCount()
static void DontThrow() throw();
static bool HasThrown() throw();
// Return the number of currently allocated blocks.
static int GetAllocationCount() throw();
// Managing tests.
static void Pass( const char* testName ) throw();
static void Fail( const char* testName ) throw();
static void Test( bool result, const char* testName ) throw();
static void PrintTestSummary();
// Managing where the output is sent. The default is cout.
static void SetOutputStream( std::ostream* os );
static std::ostream& GetOut(){ return *mOs; }
// For use by our definitions of new and delete.
static void* MemAllocated( void* rawMem );
static void DoDeallocate( void* userMem );
};
/************************************************
TestDriver
This method does the test. It will cause all
exception paths to be executed.
For example usage, see below.
*************************************************/
template<class TestFunction>
void TestDriver()
{
int i = 0;
int start_count, leaks;
bool thrown;
Counter::GetOut() << "Doing test "
<< typeid( TestFunction ).name()
<< std::endl;
do {
start_count = Counter::GetAllocationCount();
Counter::SetThrowCount( ++i );
//Counter::GetOut() << std::endl
// << " Exception count: " << i << std::endl;
try {
TestFunction::DoTest();
}
catch( const TestException& e ) {
}
catch( const std::bad_alloc& e ) {
}
catch( ... ) {
}
thrown = Counter::HasThrown();
// Should set not to throw exceptions for the stuff below.
Counter::DontThrow();
// Check for resource leaks here.
// ...
} while( thrown );
// Loop terminates when we make it all the way
// through a test without triggering the exception counter.
Counter::GetOut() << " " << i
<< " execution paths were tested."
<< std::endl;
}
/*******************
To use this TestDriver function, supply a class like this:
class TestPath1
{
public:
static void DoTest() {
// Test some aspect of your class or function here,
// by calling it with known inputs and checking the results.
// For example:
// This tests the conversion constructor of a
// String class (assuming that operator== works OK).
String s1(""), s2("Hello");
Counter::Test( s1 == "", "Correct string value" );
Counter::Test( s2 == "Hello", "Correct string value" );
}
};
Then, supply a main like this
int main()
{
TestDriver<TestPath1>();
TestDriver<TestPath2>();
// and so on...
Counter::PrintTestSummary();
return 0;
}
********************/
#endif // COUNTER_H
End of Listing