/**
 * @file TestStack.cpp
 * @date May 4, 2010
 * @author ron
 *
 * @brief
 */

#include "TestProtocol.h"
#include "../TestBase/TestBase.h"

/// @cond DOXYGEN_SKIP
SUITE( Protocol )
{
/// @endcond

	/**
	 * @struct StackFixture
	 * @brief Helper struct providing set-up/tear-down of Stack tests
	 *
	 * @copydetails EventFixture
	 */
	struct StackFixture
	{
		SuiteBase::SimulationTest sim;
		TestLogConsumer::Ptr log;
		Stack stack;
		data::TypeInfo type;
		data::TypeInfo layerType;

		StackFixture()
		:	sim( "StackTestSim" )
		,	log( TestLogConsumer::create() )
		,	stack( sim, "StackTest" )
		,	type( typeid(Stack) )
		,	layerType( typeid(Layer) )
		{
			sim.addConsumer( log );
		}
	};

	TEST_FIXTURE( StackFixture, Construction )
	{
		data::Label label = "StackTestConstruction";
		{
			Stack stack( sim, label );

			CHECK( log->getTraceRecord( "create", type ) );
			// check creation and registration of internal top layer
			CHECK( log->getTraceRecord( "create", layerType ) );
			CHECK_EQUAL( (std::size_t) 1, stack.getLayers().size() );
		}
		CHECK( log->getTraceRecord( "destroy", type ) );
		CHECK( log->getTraceRecord( "destroy", layerType ) );
	}

	TEST_FIXTURE( StackFixture, AddLayer )
	{
		Layer* internal = stack.getLayers().front();
		Layer* layer = new Layer( sim, "StackTestAddLayerLayer" );
		stack.addLayer( layer );

		CHECK( log->getTraceRecord( "add layer", type ) );
		CHECK_EQUAL( (std::size_t) 2, stack.getLayers().size() );
		// check correct addition
		CHECK_EQUAL( internal, stack.getLayers().front() );
		CHECK_EQUAL( layer, stack.getLayers().back() );
		// check layer linking (top to bottom)
		CHECK_EQUAL( layer, internal->getLowerLayer() );
		CHECK_EQUAL( internal, layer->getUpperLayer() );
	}

	TEST_FIXTURE( StackFixture, AddReceiveSap )
	{
		Sap* sap = stack.addReceiveSap( "SAP" );
		CHECK( sap != 0 );

		Layer* internal = stack.getLayers().front();
		CHECK( internal->getSaps().find( "SAP" ) != internal->getSaps().end() );
		CHECK( log->getTraceRecord( "add receive SAP", type ) );

		Sap* found = stack.addReceiveSap( "SAP" );
		CHECK_EQUAL( sap, found );
		CHECK( log->getWarningRecord( "Stack::addReceiveSap(): SAP already exists", type ) );
	}

	TEST_FIXTURE( StackFixture, GetSap )
	{
		Layer* layer = new Layer( sim, "StackTestGetSapLayer" );
		ServiceProviderTest* sp = new ServiceProviderTest( sim, "StackTestGetSapSP" );
		Sap* sap = sp->addSap( "Exists" );
		layer->addServiceProvider( sp );
		stack.addLayer( layer );

		CHECK_EQUAL( sap, stack.getSap( "Exists" ) );
	}

	TEST_FIXTURE( StackFixture, GetSapErrors )
	{
		stack.getSap( "NoLayer" );
		CHECK( log->getErrorRecord( "Stack::getSap():"
				"no service providing layer, cannot access SAP", type ) );

		Layer* layer = new Layer( sim, "StackTestGetSapErrorsLayer" );
		layer->addServiceProvider( new ServiceProviderTest( sim, "StackTestGetSapErrorsSP" ) );
		stack.addLayer( layer );

		stack.getSap( "NotInLayer" );
		CHECK( log->getErrorRecord( "Stack::getSap(): SAP not found in top layer", type ) );
	}


/// @cond DOXYGEN_SKIP
}
/// @endcond
