/**
 * @file TestNormal.cpp
 * @date Aug 9, 2008
 * @author Ronald Kluth
 *
 * @brief Tests for ODEMx class Normal
 */

#include "TestRandom.h"
#include "../TestBase/TestBase.h"

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

	/**
	 * @struct NormalFixture
	 * @brief Helper struct providing set-up/tear-down of Normal tests
	 *
	 * @copydetails EventFixture
	 */
	struct NormalFixture
	{
		SuiteBase::SimulationTest sim;
		TestLogConsumer::Ptr log;
		double mean;
		double deviation;
		int cells;
		Normal normal;
		statistics::Histogram histogram;
		data::TypeInfo type;

		NormalFixture()
		:	sim( "NormalTestSim" ),
			log( TestLogConsumer::create() ),
			mean( 10 ),
			deviation( 5 ),
			cells( (int)mean * 2 ),
			normal( sim, "NormalTest", mean, deviation ),
			histogram( sim, "NormalTestHistogram", 0, mean * 2, cells ),
			type( typeid(Normal) )
			{
				sim.addConsumer( log );
			}
	};

	/**
	 * @test odemx::Normal construction
	 *
	 * Expected function call effects:
	 * @li negative mean value produces a warning and inverts it
	 * @li label is set
	 * @li dist context (simulation) is set
	 * @li mean value is set
	 */
	TEST_FIXTURE( NormalFixture, ConstructionDestruction )
	{
		data::Label l = "NormalTestUserSimConstruction";
		{
			Normal normal2( sim, l, mean, -deviation );
			CHECK( log->getTraceRecord( "create", type ) );
			CHECK( log->getStatisticsRecord( "parameter", "seed", type ) );
			CHECK( log->getStatisticsRecord( "parameter", "mean", type ) );
			CHECK( log->getStatisticsRecord( "parameter", "deviation", type ) );
			CHECK( log->getWarningRecord( "Normal(): given deviation < 0; changed to -deviation", type ) );
			CHECK_EQUAL( l, normal2.getLabel() );
			CHECK_EQUAL( mean, normal2.getMean() );
			CHECK_EQUAL( deviation, normal2.getDeviation() );
		}
		CHECK( log->getTraceRecord( "destroy", type ) );
	}

	/**
	 * @test odemx::Normal::sample()
	 *
	 * Expected function call effects:
	 * @li samples are always greater or equal \c 0
	 * @li the given mean value is very close to the computed one
	 * @li the given mean value is very close to the variance
	 *
	 * @warning The computed mean value for this test differs from the given
	 * one by almost \c 0.5.
	 */
	TEST_FIXTURE( NormalFixture, Sample )
	{
		normal.sample();
		CHECK( log->getTraceRecord( "sample", type ) );
		CHECK( log->getStatisticsRecord( "count", "uses", type ) );

		for( int i = 0; i < 1000000; ++i )
		{
			double value = normal.sample();
			histogram.update( value );
		}

		CHECK_CLOSE( normal.getMean(), histogram.getMean(), 0.5  );
		CHECK_CLOSE( normal.getDeviation(), histogram.getStandardDeviation(), 0.05  );
	}

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