Listing 1: A class for counting tests passed, tests failed, number of exception points, and which exception point to fail on
#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