//////////////////////////////////////////////////////////////////////////////
//            CTA++, C++ Test Aider/Visual Studio Integration v2.0          //
//                                                                          //
//                     GENERATED TEST SCRIPT FILE                           //
//                                                                          //
//            Copyright (c) [generated parts] 2003-2004 Testwell Oy         //
//////////////////////////////////////////////////////////////////////////////
//
// CTA/VSI: File created: Jan 22 2004 11:09:47
// CTA/VSI: Last CTA/VSI update: Jan 23 2004 11:31:16
// Last user update: <date> (when edit, you may wish to maintain this)
//
// Here you may wish to insert version control hooks, like
// $RCSfile$, $Revision$, $Date$, $Author$ and $Log$
//
// Note 1. Lines starting with '// CTA/VSI:' are auxiliary lines to
// CTA++/Visual Studio Integration. DO NOT EDIT THESE LINES!
// Note 2. Lines starting with '// TODO:' advises where especially you
// can and sometimes must insert test code. You can edit these freely.
//////////////////////////////////////////////////////////////////////////////
//
// TODO: Uncomment the following  definition, if old streams...
// #define CTA_OLDSTREAM

// Enable the CTA++ macro language and class interface
#include <cta.h>

// TODO: Include code under test headers as required by C++ rules.
// Remember extern "C" {...} wrapping if testing plain C code.

// ----------------------------------------------------------------------
// The class under test, 'List'. Also auxiliary classes
// 'List_element', 'List_iterator' and 'List_reverse_iterator'.
// ----------------------------------------------------------------------

#include "list.h"

// Get CTA_ prefixless aliases for the test macros defined in 'cta.h'
// If name conflicts, see CTA++ User's Guide for resolving.
#include <ctanames.h>

// Images //
// TODO: Add image macros IMAGE... ENDIMAGE and IMAGE_CAST
// to display objects of user's type

// ----------------------------------------------------------------------
// Image-function to display objects of user's type
// 'ExceptionIteratorOutOfBounds'
// ----------------------------------------------------------------------

IMAGE(ExceptionIteratorOutOfBounds e)
    CTA_img.noAggregate(); // CTA_img is an "implicit" parameter to IMAGE
    CTA_img << e.getMsg();
ENDIMAGE

// Exception handlers //
// TODO: User's exceptions to be caught by name by the test driver
// (this means: when the user's code escapes with one of the exceptions
// below, CTA++ is able to report the type of the exception)
// ----------------------------------------------------------------------

HANDLER
  CATCH(ExceptionEmptyList)
  CATCH(ExceptionIteratorOutOfBounds)
  CATCH(ExceptionOutOfMemory)
ENDHANDLER

// Stubs //
// TODO: Add stub functions (if introduced them manually)
// Remember extern "C" {...} wrapping, if stubbing plain C code.

// ----------------------------------------------------------------------
// Stubs needed by class 'List'.
// ----------------------------------------------------------------------
#include "CTA_memory.h_stb.inc"
// CTA/VSI: Include stub function files above

// Test case functions //
// TODO: Define test case functions

// Below are the test-case functions used in testing the class 'List'

// ----------------------------------------------------------------------
// Test-case function testing an empty 'List'
// ----------------------------------------------------------------------
void CTA_test_case_1(void) {
	// TODO: Add test macros here
    HARD_MSG("This test case tests the functionality of 'List' methods "
             "when called on an empty 'List' object."); NL;

    MSG("Create a List");
    DECL(List l);

    NL; MSG("The List should be initially empty.");
    ASSERT(l.empty());

    NL; MSG("It means that item count should be 0");
    ASSERT_EQ(l.itemCount(), 0);

    NL; MSG("An attempt to extract something from an empty list should "
        "cause an exception to be thrown.");
    DECL(int i);
    ASSERT_EXCEPTION(i = l.extract(), ExceptionEmptyList);

    NL; MSG("Taking an iterator to the begin and end of the list should yield "
        "iterators with the status 'end'");
    ASSERT(l.begin().end());
    ASSERT(l.last().end());
    ASSERT(l.rbegin().rend());

    NL; MSG("Trying to access with '*' an item in empty list should "
            "cause exception");
    ASSERT_EXCEPTION(*l.begin(), ExceptionIteratorOutOfBounds);

    NL; MSG("Trying to update an empty iterator with '++' should "
            "cause exception");
    ASSERT_EXCEPTION(++(l.begin()), ExceptionIteratorOutOfBounds);

    NL; MSG("Inserting an item (7) into the list.");
    DO(l.insert(7));

    MSG("The list should no longer be empty.");
    ASSERT(!l.empty());

    MSG("The item count should be 1");
    ASSERT_EQ(l.itemCount(), 1);

    MSG("Extracting the item...");
    ASSERT_EQ(l.extract(), 7);

    MSG("Now the list should be empty again.");
    ASSERT(l.empty());
    ASSERT_EQ(l.itemCount(), 0);

    MSG("Now the stub 'List_free' should be invoked because 'l' "
        "goes out of scope and its destructor calls 'List_free'."); 
    NL;	
}

// ----------------------------------------------------------------------
// Test-case function that inserts and extracts integers into and
// out of a 'List', asserting that correct items were extracted.
// ----------------------------------------------------------------------
void CTA_test_case_2(CTA_TestData& td) {
	// TODO: Add test macros here
    HARD_MSG("This test case inserts integers into a 'List', and "
             "then extracts them, asserting that correct items get "
             "extracted."); NL;

    MSG("At this point we set the verbosity of the stubs to BRIEF."); NL;

    DO(List_malloc_stub.beBrief());
    DO(List_realloc_stub.beBrief());
    DO(List_free_stub.beBrief());

    NL; MSG("Create some variables."); NL;

    DECL(List l);
    DECL(int i);
    DECL(int n = 0);

    NL; MSG("Insert integers read from a data file into List 'l'");

    while (!td.end()) {
        DO(td >> i);
        PUT(i);
        DO(l.insert(i); n++);
    }

    NL; MSG("Assert that item count equals the number of items inserted "
            "into the List");
    ASSERT_EQ(l.itemCount(), n);

    NL; MSG("Assert that the List contains correct items, i.e. those that "
            "were just inserted there; a List_iterator is created "
            "for scanning through the List");

    DO(td.rewind());
    DECL(List_iterator iter = l.begin());

    while (!td.end()) {
        DO(td >> i);
        PUT(i);
        ASSERT_EQ(*iter, i);
        DO(++iter);
        NL;
    }

    NL; MSG("Assert that there are no more items to be iterated in the List");
    ASSERT(iter.end());

    NL; MSG("And the List 'l' goes out of scope...");	
}

// ----------------------------------------------------------------------
// Test-case function testing the List method 'remove'
// ----------------------------------------------------------------------
void CTA_test_case_3(void) {
	// TODO: Add test macros here
    HARD_MSG("Test the List method 'remove'"); NL;

    DECL(List l);

    NL; MSG("Insert some int's into the List l"); NL;

    DO(l.insert(3));
    DO(l.insert(1));
    DO(l.insert(2));
    DO(l.insert(0));
    DO(l.insert(123));

    NL; MSG("Remove the int's from the list one by one; assert that "
            "item count has decreased accordingly"); NL;

    ASSERT_EQ(l.itemCount(), 5);
    DO(l.remove(2));
    ASSERT_EQ(l.itemCount(), 4);
    DO(l.remove(3));
    ASSERT_EQ(l.itemCount(), 3);
    DO(l.remove(123));
    ASSERT_EQ(l.itemCount(), 2);
    DO(l.remove(0));
    ASSERT_EQ(l.itemCount(), 1);
    DO(l.remove(1));
    ASSERT_EQ(l.itemCount(), 0);
    ASSERT(l.empty());
    ASSERT_EXCEPTION(l.extract(), ExceptionEmptyList);	
}

// ----------------------------------------------------------------------
// Test-case function doing a stress test on 'List'; insert a lot of
// items into the list and extract them; assert that correct items
// get extracted
// ----------------------------------------------------------------------
void CTA_test_case_4(int stress) {
	// TODO: Add test macros here
	HARD_MSG("Do a little stress test. "
            "Insert a lot of integers!"); NL;

    PUT(stress);
 
    DECL(List l2);

    for (int j = 0; j < stress; ++j) {
        l2.insert(j);
    }

    ASSERT_EQ(l2.itemCount(), stress);

    NL; MSG("Now doing so many assertions that BRIEF mode is entered "
        "for the time of the assertions in order to avoid unreasonably "
        "long trace...");

    DO(CTA_TestDriver::whichDriver()->beBrief());

    for (int jj = stress - 1; jj >= 0; --jj) {
        ASSERT_EQ(l2.extract(), jj);
    }

    DO(CTA_TestDriver::whichDriver()->beVerbose());

    MSG("Assertions done");
}

// ----------------------------------------------------------------------
// Test-case function testing 'List' in out of memory conditions.
// ----------------------------------------------------------------------
void CTA_test_case_5(void) {
	// TODO: Add test macros here
    HARD_MSG("This test case tests the class 'List' in out-of-memory "
             "condition. The condition is achieved by setting the stubs "
             "List_malloc and List_realloc to return 0 when called. "
             "This is done via the corresponding stub objects "
             "List_malloc_stub and List_realloc_stub."); NL;


    MSG("Set the stub List_realloc to return 0 when called "
        "to simulate the out of memory condition");
    DO(List_realloc_stub << (void*)0);

    DECL(List l);

    NL; MSG("The statement block below should throw exception at the point "
            "where 'insert' finally calls 'List_realloc'!");

    ASSERT_TRY
        for (int i = 0; i < 20; ++i) {
            DO(l.insert(i*i));
        }
    ASSERT_CATCH(ExceptionOutOfMemory);

    NL; MSG("Set the stub List_malloc to return 0 when called "
            "to simulate the out of memory condition");
    DO(List_malloc_stub << (void*)0);

    MSG("Try to create a 'List', should throw exception!");
    ASSERT_EXCEPTION(DECL(List l2), ExceptionOutOfMemory);	
}

// ----------------------------------------------------------------------
// Test-case function testing 'List_reverse_iterator'
// ----------------------------------------------------------------------
void CTA_test_case_6(void) {
	// TODO: Add test macros here
    HARD_MSG("This test case tests the List_reverse_iterator");

    List_malloc_stub.beSilent();
    List_realloc_stub.beSilent();
    List_free_stub.beSilent();

    List_malloc_stub << CTA_Stub::body(1);
    List_realloc_stub << CTA_Stub::body(1);
    List_free_stub << CTA_Stub::body(1);

    DECL(List l);
    for (int i = -5; i <= 5; ++i) {
        DO(l.insert(i));
    }
    DECL(List_reverse_iterator riter = l.rbegin());
    DECL(List l2);
    while (!riter.rend()) {
        DO(l2.insert(*riter));
        DO(--riter);
    }

    DECL(List_iterator iter = l2.begin());
    DO(riter = l.rbegin());
    while (!iter.end()) {
        ASSERT_EQ(*riter, *iter);
        DO(--riter; ++iter);
    }

    List_malloc_stub.beBrief();
    List_realloc_stub.beBrief();
    List_free_stub.beBrief();	
}

// CTA/VSI: Define test case functions above

// The main test script function //
int main(int argc, char* argv[])
{
	// Create a test driver object 'd'
	DRIVER(d);

	// TODO: Add object definitions needed in test case function registrations

	d.add(CTA_TestCase<void>(CTA_test_case_1, 
		"1", "test empty list"));
	d.add(CTA_TestCase<void>(CTA_test_case_2, "2@CTA_vsList_drv.dat", 
		"2", "test list"));
	d.add(CTA_TestCase<void>(CTA_test_case_3, 
		"3", "test 'List::remove'"));
	d.add(CTA_TestCase<int>(CTA_test_case_4, 132, 
		"4", "stress test"));
	d.add(CTA_TestCase<void>(CTA_test_case_5, 
		"5", "out of memory-test"));
	d.add(CTA_TestCase<void>(CTA_test_case_6, 
		"6", "test List_reverse_iterator"));
// CTA/VSI: Register test cases in 'd' above

	// Run the test cases and return status code to the shell level
	return d.run(argc, argv);
}
// EOF