/*****************************************************************************
 * $LastChangedDate: 2011-04-23 21:07:07 -0400 (Sat, 23 Apr 2011) $
 * @file
 * @author  Jim E. Brooks  http://www.palomino3d.org
 * @brief   Test of Stack template class.
 *//*
 * LEGAL:   COPYRIGHT (C) 2007 JIM E. BROOKS
 *          THIS SOURCE CODE IS RELEASED UNDER THE TERMS
 *          OF THE GNU GENERAL PUBLIC LICENSE VERSION 2 (GPL 2).
 *****************************************************************************/

#define TESTING 1
#include "test.hh"
#include "base/module.hh"
#include "base/stack.hh"
using namespace base;

/*****************************************************************************
 * Test.
 *****************************************************************************/
class Object : public Shared
{
public:
    Object( int n )
    {
        ++msInstances;
        mVal = n;
    }

    // Need copy ctor to count msInstances.
    Object( const Object& src )
    {
        ++msInstances;
        mVal = src.mVal;
    }

    ~Object()
    {
        --msInstances;
        if ( msInstances < 0 ) { Fail(); }
    }

public:
    int             mVal;
    CLASS_VAR int   msInstances;
};
int Object::msInstances;

bool
Test( void )
{
    // Along the way, test if shptr or Stack is causing leaks.

// -------------------------------------------
 {
    shptr<Object> o1 = new Object( 1 );
    shptr<Object> o2 = new Object( 2 );
    shptr<Object> o3 = new Object( 3 );

    Stack< shptr<Object> > stack;
    if ( not stack.IfEmpty() ) { Fail(); }

#if 0
    // Pop() cannot be called when stack is empty.
    // Stems from the limitation that shptr cannot be NULL
    // so Pop() will never return NULL;
  //if ( stack.Pop() != NULL ) { Fail(); }  // should return NULL when empty
#endif

    stack.Push( o1 ); if ( stack.GetCount() != 1 ) { Fail(); }
    if ( stack.Top()->mVal != 1 ) { Fail(); }

    stack.Push( o2 ); if ( stack.GetCount() != 2 ) { Fail(); }
    if ( stack.Top()->mVal != 2 ) { Fail(); }

    stack.Push( o3 ); if ( stack.GetCount() != 3 ) { Fail(); }
    if ( stack.Top()->mVal != 3 ) { Fail(); }

    if ( stack.IfEmpty() ) { Fail(); }
   {
    shptr<Object> p = stack.Pop(); if ( p->mVal != 3 ) { Fail(); }
   }
   {
    shptr<Object> p = stack.Pop(); if ( p->mVal != 2 ) { Fail(); }
   }
   {
    shptr<Object> p = stack.Pop(); if ( p->mVal != 1 ) { Fail(); }
   }

    if ( ! stack.IfEmpty() ) { Fail(); }
    if ( stack.GetCount() != 0 ) { Fail(); }
 }
// -------------------------------------------
    if ( Object::msInstances != 0 ) { Fail(); }
// -------------------------------------------
 {
    Object o1( 1 );
    Object o2( 2 );
    Object o3( 3 );
    Stack<Object> stack;

    stack.Push( o1 );
    stack.Push( o2 );
        stack.Pop();
    stack.Push( o3 );

    if ( stack.IfEmpty() ) { Fail(); }
   {
    Object o = stack.Pop(); if ( o.mVal != 3 ) { Fail(); }
   }
   {
    Object o = stack.Pop(); if ( o.mVal != 1 ) { Fail(); }
   }
    if ( ! stack.IfEmpty() ) { Fail(); }
 }
// -------------------------------------------
    if ( Object::msInstances != 0 ) { Fail(); }
// -------------------------------------------
 {
    Stack< shptr<Object> >* stack = new Stack< shptr<Object> >;
    const uint n = 4*MILLION;
    for ( uint i = 0; i < n; ++i )
    {
        stack->Push( new Object( i ) );
    }

    for ( int i = n-1; i >= 0; --i )
    {
        shptr<Object> o = stack->Pop();
        if ( o->mVal != int(i) ) { Fail(); }
    }
 }
// -------------------------------------------
    if ( Object::msInstances != 0 ) { Fail(); }
// -------------------------------------------

    return true;
}

/*****************************************************************************
 * main.
 *****************************************************************************/
int
main( int argc, char** argv )
{
    RUN_TEST( "stack", TEST_ERROR_MODE_ABORT,
             Test() )
}
