/**
 * @file TestReport.cpp
 * @date Jul 12, 2008
 * @author Ronald Kluth
 *
 * @brief Tests for ODEMx classes Report, ReportProducer
 */

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

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

	using namespace SuiteBase;

	/**
	 * @struct ReportFixture
	 * @brief Helper struct providing set-up/tear-down of Report tests
	 *
	 * @copydetails EventFixture
	 */
	struct ReportFixture
	{
		SimulationTest sim;
		ReportProducerTest producer1;
		ReportProducerTest producer2;
		ReportTest reporter;

		ReportFixture()
		:	sim( "ReportTestSim" )
		,	producer1( sim, "ReportTestProducer1" )
		,	producer2( sim, "ReportTestProducer2" )
		,	reporter()
		{}
	};

	/**
	 * @test odemx::Report::addProducer(ReportProducer*)
	 *
	 * Expected function call effects:
	 * @li the producers are added to the internal list
	 */
	TEST_FIXTURE( ReportFixture, AddProducer )
	{
		const std::set< ReportProducer* >& producers = reporter.getReportProducers();
		CHECK( producers.empty() );

		reporter.addReportProducer( producer1 );
		reporter.addReportProducer( producer2 );

		CHECK_EQUAL( (std::size_t) 2, producers.size() );
		CHECK( std::find( producers.begin(), producers.end(), &producer1 ) != producers.end() );
		CHECK( std::find( producers.begin(), producers.end(), &producer2 ) != producers.end() );
	}

	/**
	 * @test odemx::Report::removeProducer(ReportProducer*)
	 *
	 * Expected function call effects:
	 * @li the producers are removed from the internal list
	 */
	TEST_FIXTURE( ReportFixture, RemoveProducer )
	{
		std::set< ReportProducer* >& producers = reporter.getReportProducers();
		CHECK( producers.empty() );

		reporter.addReportProducer( producer1 );
		reporter.addReportProducer( producer2 );
		reporter.removeReportProducer( producer1 );

		CHECK_EQUAL( (std::size_t) 1, producers.size() );
		CHECK( std::find( producers.begin(), producers.end(), &producer1 ) == producers.end() );
		CHECK( std::find( producers.begin(), producers.end(), &producer2 ) != producers.end() );
	}

	/**
	 * @test odemx::Report::createTable(const string&,TableDefinition*)
	 *
	 * Expected function call effects:
	 * @li with the first call, a new Table is created
	 * @li the table is added to the internal table vector
	 * @li with the same call, the previously created table is returned
	 */
	TEST_FIXTURE( ReportFixture, CreateTable )
	{
		std::vector< ReportTable* >& tables = reporter.getReportTables();
		CHECK( tables.empty() );

		ReportTable::Definition tableDef;

		ReportTable& table = reporter.getTable( "Test Table", tableDef );

		CHECK_EQUAL( std::size_t(1), tables.size() );
		CHECK( std::find( tables.begin(), tables.end(), &table ) != tables.end() );

		ReportTable& table2 = reporter.getTable( "Test Table", tableDef );
		CHECK_EQUAL( &table, &table2 );
	}

	/**
	 * @test odemx::Report::findTable(const string&,TableDefinition*)
	 *
	 * Expected function call effects:
	 * @li returns 0 if table name is empty or table definition is 0
	 * @li tables with different definitions but the same labels are found
	 * @li tables with different labels but the same definitions are found
	 */
	TEST_FIXTURE( ReportFixture, FindTable )
	{
		std::vector< ReportTable* >& tables = reporter.getReportTables();
		CHECK( tables.empty() );

		ReportTable::Definition tableDef;
		ReportTable::Definition tableDef2;
		tableDef2.addColumn( "int", ReportTable::Column::INTEGER );

		ReportTable& table1 = reporter.getTable( "Test Table", tableDef );
		ReportTable& table2 = reporter.getTable( "Test Table 2", tableDef );
		ReportTable& table3 = reporter.getTable( "Test Table", tableDef2 );

		CHECK( 0 == reporter.findTable( "Not There", tableDef ) );

		ReportTable* found = 0;
		found = reporter.findTable( "Test Table", tableDef );
		CHECK_EQUAL( &table1, found );

		found = reporter.findTable( "Test Table 2", tableDef );
		CHECK_EQUAL( &table2, found );

		found = reporter.findTable( "Test Table", tableDef2 );
		CHECK_EQUAL( &table3, found );
	}

	/**
	 * @test odemx::Report::generateReport()
	 *
	 * Expected function call effects:
	 * @li all registered producers called \c report()
	 * @li the Report object called \c processTables()
	 */
	TEST_FIXTURE( ReportFixture, GenerateReport )
	{
		std::set< ReportProducer* >& producers = reporter.getReportProducers();
		CHECK( producers.empty() );

		reporter.addReportProducer( producer1 );
		reporter.addReportProducer( producer2 );
		CHECK( ! producer1.sentReport );
		CHECK( ! producer2.sentReport );

		reporter.generateReport();

		CHECK( producer1.sentReport );
		CHECK( producer2.sentReport );
		CHECK( reporter.calledStartProcessing );
		CHECK( reporter.processedTables );
		CHECK( reporter.calledEndProcessing );
	}

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