#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