Listing 5: Test harness for Stack.h
#include "Counter.h" #include "TestClass.h" #if defined( STACK_REED ) #include "Stack_Reed.h" #elif defined( STACK_REED_FIXED ) #include "Stack_Reed_Fixed.h" #elif defined( STACK_SUTTER_1 ) #include "Stack_Sutter_1.h" #elif defined( STACK_SUTTER_3 ) #include "Stack_Sutter_3.h" #else #error "Don't know which stack to include." // #include "Stack_Reed.h" #endif typedef TestClass element_type; typedef Stack<element_type> TestType; class TestConstructDestruct { public: static void DoTest() { TestType a; Counter::Test( 0 == a.Size(), "Default constructor" ); Counter::Test( a.Consistent(), "a internal state" ); } }; class TestCopyConstruct1 { public: static void DoTest() { TestType a; { TestType b( a ); Counter::Test( 0 == b.Size(), "Copy empty" ); Counter::Test( b.Consistent(), "b internal state" ); } Counter::Test( a.Consistent(), "a internal state" ); } }; class TestCopyConstruct2 { public: static void DoTest() { TestType a; a.Push( element_type() ); a.Push( element_type() ); { TestType b( a ); Counter::Test( 2 == b.Size(), "copy with 2 elements" ); Counter::Test( b.Consistent(), "b internal state" ); } Counter::Test( a.Consistent(), "a internal state" ); } }; class TestAssign1 { public: static void DoTest() { TestType a; TestType b; b = a; Counter::Test( 0 == b.Size(), "Assign empty" ); Counter::Test( a.Consistent(), "a internal state" ); Counter::Test( b.Consistent(), "b internal state" ); } }; class TestAssign2 { public: static void DoTest() { TestType a; TestType b; a.Push( element_type() ); a.Push( element_type() ); b.Push( element_type() ); b = a; Counter::Test( 2 == b.Size(), "Assign 2 elements" ); Counter::Test( a.Consistent(), "a internal state" ); Counter::Test( b.Consistent(), "b internal state" ); a = a; Counter::Test( 2 == a.Size(), "Assign a to self" ); Counter::Test( a.Consistent(), "a internal state" ); } }; class TestPush { public: static void DoTest() { // This tests that the class obeys commit or rollback // semantics. TestType a; for( int i = 0; i < 12; ++i ) { try { a.Push( element_type() ); Counter::Test( i+1 == a.Size(), "push 1 element" ); } catch( ... ) { Counter::Test( i == a.Size(), "push 1 element recover from exception" ); Counter::Test( a.Consistent(), "a internal state after exception" ); throw; } } Counter::Test( a.Consistent(), "a internal state" ); } }; #ifdef STACK_HAS_TOP class TestTop { public: static void DoTest() { TestType a; try { element_type b = a.Top(); // Should throw. Counter::Fail( "Top of empty" ); } catch( const char* ) { Counter::Pass( "Top of empty" ); } a.Push( element_type() ); try { element_type b = a.Top(); // Should not throw. Counter::Pass( "Top of non-empty" ); } catch( const char* ) { Counter::Fail( "Top of non-empty" ); } Counter::Test( a.Consistent(), "a internal state" ); } }; class TestPop { public: static void DoTest() { TestType a; a.Push( element_type(1) ); a.Push( element_type(2) ); a.Pop(); Counter::Test( 1 == a.Size(), "Pop reduces size" ); Counter::Test( element_type(1) == a.Top(), "Correct top element" ); a.Pop(); Counter::Test( 0 == a.Size(), "Pop reduces size" ); try { a.Pop(); Counter::Fail( "Pop empty" ); } catch( const char* ) { Counter::Pass( "Pop empty" ); } Counter::Test( a.Consistent(), "a internal state" ); Counter::Test( 0 == a.Size(), "a correct size" ); } }; #else // STACK_HAS_TOP // Test old style pop which returns the popped element. // Note that it's impossible to pass these tests, which is why // the newer version changes the pop method to return nothing. class TestPop { public: static void DoTest() { TestType a; element_type b(0); a.Push( element_type(1) ); a.Push( element_type(2) ); try { b = a.Pop(); Counter::Test( 1 == a.Size(), "Pop reduces count" ); Counter::Test( element_type(2) == b, "Correct pop value" ); } catch(...) { // This test will get confused with the // assignment failing. Counter::Test( 2 == a.Size(), "Pop rollback on exception 1" ); // Can't test value of stack top. throw; } try { a.Pop(); Counter::Test( 0 == a.Size(), "Pop reduces count" ); } catch( ... ) { Counter::Test( 1 == a.Size(), "Pop rollback on exception 2" ); throw; } try { a.Pop(); Counter::Fail( "Pop empty throws exception" ); } catch( const char* ) { Counter::Pass( "Pop empty throws exception" ); Counter::Test( 0 == a.Size(), "Pop empty stays empty" ); } Counter::Test( a.Consistent(), "a internal state" ); } }; #endif // STACK_HAS_TOP int main( int argc, char* argv[] ) { TestDriver<TestConstructDestruct>(); TestDriver<TestCopyConstruct1>(); TestDriver<TestPush>(); TestDriver<TestCopyConstruct2>(); TestDriver<TestAssign1>(); TestDriver<TestAssign2>(); #ifdef STACK_HAS_TOP TestDriver<TestTop>(); #endif TestDriver<TestPop>(); TestDriver<TestAssign2>(); Counter::PrintTestSummary(); return 0; } End of Listing