/**
 * @file TestLoggingManager.cpp
 * @date May 2, 2010
 * @author Ronald Kluth
 *
 * @brief Tests for ODEMx class LoggingManager
 */

#include "TestData.h"
#include "../TestBase/TestBase.h"

#ifdef _MSC_VER
#include <memory>
#else
#include <tr1/memory>
#endif

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

	/**
	 * @test odemx::data::LoggingManager construction
	 *
	 * Tests:
	 * @li default error logging
	 */
	TEST( LoggingManagerConstruction )
	{
		// check error logging
		LoggingManager man1;
		CHECK_EQUAL( (std::size_t) 1, man1.getChannel( channel_id::warning )->getConsumers().size() );
		CHECK_EQUAL( (std::size_t) 1, man1.getChannel( channel_id::error )->getConsumers().size() );
		CHECK_EQUAL( (std::size_t) 1, man1.getChannel( channel_id::fatal )->getConsumers().size() );
	}

	/// Helper function templatefor checking that a consumer is set
	template < typename ConsumerPtrT >
	bool findConsumer( base::Simulation& sim, Log::ChannelId id, ConsumerPtrT ptr )
	{
		return sim.getChannel( id )->getConsumers().find( ptr )
				!= sim.getChannel( id )->getConsumers().end();
	}

	/**
	 * @test odemx::data::LoggingManager default logging to console
	 *
	 * Tests:
	 * @li all channels have the same OStreamWriter consumer
	 */
	TEST( LoggingManagerDefaultLoggingConsole )
	{
		std::ostringstream coutStream;
		std::streambuf* coutBuf = std::cout.rdbuf( coutStream.rdbuf() );
		assert( coutBuf );

		SuiteBase::SimulationTest sim( "LoggingManagerTestSim" );
		sim.enableDefaultLogging( output::STDOUT );

		// get consumer
		const std::tr1::shared_ptr< Log::Consumer< SimRecord > > coutWriter =
				*sim.getChannel( channel_id::trace )->getConsumers().begin();

		CHECK( dynamic_cast< OStreamWriter* >( coutWriter.get() ) );
		// the writer must be registered on all channel
		CHECK( findConsumer( sim, channel_id::trace, coutWriter ) );
		CHECK( findConsumer( sim, channel_id::debug, coutWriter ) );
		CHECK( findConsumer( sim, channel_id::info, coutWriter ) );
		CHECK( findConsumer( sim, channel_id::warning, coutWriter ) );
		CHECK( findConsumer( sim, channel_id::error, coutWriter ) );
		CHECK( findConsumer( sim, channel_id::fatal, coutWriter ) );
		CHECK( findConsumer( sim, channel_id::statistics, coutWriter ) );

		// a second call does nothing and returns false
		CHECK( ! sim.enableDefaultLogging( output::STDOUT ) );
		CHECK( sim.disableDefaultLogging() );

		std::cout.rdbuf( coutBuf );
	}

	/**
	 * @test odemx::data::LoggingManager default logging to XML
	 *
	 * Tests:
	 * @li if XML filename is missing, throws an exception
	 * @li all channels have the same XmlWriter consumer
	 */
	TEST( LoggingManagerDefaultLoggingXml )
	{
		SuiteBase::SimulationTest sim( "LoggingManagerTestSim" );

		CHECK_THROW( sim.enableDefaultLogging( output::XML ), odemx::DataOutputException );
		sim.enableDefaultLogging( output::XML, "LoggingManagerTestDefaultLogging" );

		// get consumer
		const std::tr1::shared_ptr< Log::Consumer< SimRecord > > xmlWriter =
				*sim.getChannel( channel_id::trace )->getConsumers().begin();

		CHECK( dynamic_cast< XmlWriter* >( xmlWriter.get() ) );

		// the writer must be registered on all channel
		CHECK( findConsumer( sim, channel_id::trace, xmlWriter ) );
		CHECK( findConsumer( sim, channel_id::debug, xmlWriter ) );
		CHECK( findConsumer( sim, channel_id::info, xmlWriter ) );
		CHECK( findConsumer( sim, channel_id::warning, xmlWriter ) );
		CHECK( findConsumer( sim, channel_id::error, xmlWriter ) );
		CHECK( findConsumer( sim, channel_id::fatal, xmlWriter ) );
		CHECK( findConsumer( sim, channel_id::statistics, xmlWriter ) );

		// a second call does nothing and returns false
		CHECK( ! sim.enableDefaultLogging( output::XML ) );
		CHECK( sim.disableDefaultLogging() );
		CHECK( Poco::File( "LoggingManagerTestDefaultLogging_0.xml" ).exists() );
	}

	/**
	 * @test odemx::data::LoggingManager default logging to SQLite
	 *
	 * Tests:
	 * @li if DB filename is missing, throws an exception
	 * @li all channels have the same DatabaseWriter consumer
	 */
	TEST( LoggingManagerDefaultLoggingDatabase )
	{
		SuiteBase::SimulationTest sim( "LoggingManagerTestSim" );
		CHECK_THROW( sim.enableDefaultLogging( output::DATABASE ), odemx::DataOutputException );
		sim.enableDefaultLogging( output::DATABASE, "LoggingManagerTestDefaultLogging.db" );

		// get consumer
		const std::tr1::shared_ptr< DatabaseWriter > dbWriter =
				std::tr1::dynamic_pointer_cast< DatabaseWriter >( *sim.getChannel( channel_id::trace )->getConsumers().begin() );

		// the writer must be registered on all channel
		CHECK( findConsumer( sim, channel_id::trace, dbWriter ) );
		CHECK( findConsumer( sim, channel_id::debug, dbWriter ) );
		CHECK( findConsumer( sim, channel_id::info, dbWriter ) );
		CHECK( findConsumer( sim, channel_id::warning, dbWriter ) );
		CHECK( findConsumer( sim, channel_id::error, dbWriter ) );
		CHECK( findConsumer( sim, channel_id::fatal, dbWriter ) );
		CHECK( findConsumer( sim, channel_id::statistics, dbWriter ) );

		// a second call does nothing and returns false
		CHECK( ! sim.enableDefaultLogging( output::DATABASE ) );
		CHECK( sim.disableDefaultLogging() );
		CHECK( Poco::File( "LoggingManagerTestDefaultLogging.db" ).exists() );
	}

	/**
	 * @test odemx::data::LoggingManager default statistics
	 *
	 * Tests:
	 * @li without default logging, calls return false
	 * @li with default logging, a StatisticsBuffer consumer is set
	 * @li reporting with XML or DB option can throw
	 * @li XML report file exists afterwards
	 */
	TEST( LoggingManagerDefaultStatisticsConsole )
	{
		std::ostringstream coutStream;
		std::streambuf* coutBuf = std::cout.rdbuf( coutStream.rdbuf() );
		assert( coutBuf );

		SuiteBase::SimulationTest sim( "LoggingManagerTestSim" );

		// false when no default logging used
		CHECK( ! sim.resetDefaultStatistics( 99 ) );
		CHECK( ! sim.reportDefaultStatistics( output::STDOUT ) );

		sim.enableDefaultLogging( output::STDOUT );

		// get consumers
		Log::Channel< SimRecord >::ConsumerSet consumers =
				sim.getChannel( channel_id::statistics )->getConsumers();

		std::tr1::shared_ptr< StatisticsBuffer > statsBuf;

		for( Log::Channel< SimRecord >::ConsumerSet::const_iterator iter = consumers.begin();
			iter != consumers.end(); ++iter )
		{
			if( const std::tr1::shared_ptr< StatisticsBuffer > tmp =
				std::tr1::dynamic_pointer_cast< StatisticsBuffer >( *iter ) )
			{
				statsBuf = tmp;
			}
		}
		CHECK( statsBuf );

		CHECK( sim.resetDefaultStatistics( 42 ) );
		CHECK( sim.reportDefaultStatistics( output::STDOUT ) );
		// missing XML filename
		CHECK_THROW( sim.reportDefaultStatistics( output::XML ), odemx::DataOutputException );
		// DB not implemented
		CHECK_THROW( sim.reportDefaultStatistics( output::DATABASE ), odemx::DataOutputException );

		CHECK( sim.reportDefaultStatistics( output::XML,
				"LoggingManagerTestDefaultStatistics.xml" ) );
		CHECK( Poco::File( "LoggingManagerTestDefaultStatistics.xml" ).exists() );

		CHECK( sim.disableDefaultLogging() );

		std::cout.rdbuf( coutBuf );
	}

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