// Copyright (c) 2020 Metrolab Technology S.A., Geneva, Switzerland (www.metrolab.com)
// See the included file LICENSE.txt for the licensing conditions.

//////////////////////////////////////////////////////////////////////////
/// \file
/// \brief Test THM1176 API: Set/get parameters

#include "gtest/gtest.h"
#include "THM1176TestUtilities.h"

using namespace MTL::Instrument;
using namespace MTL::Instrument::THM1176Types;

/// \brief Test THM1176 API: Set/get parameters
class CTHM1176SetGetParametersTest : public ::testing::Test
{
protected:
	static THM1176_TEST_RESOURCE_MANAGER_CLASS * pResourceManager;
	static CTHM1176Instrument<THM1176_TEST_INSTRUMENT_CLASS, THM1176_TEST_RESOURCE_MANAGER_CLASS> * pTHM1176;

	static void SetUpTestCase()
	{
		ASSERT_EQ(true, ConnectToTHM1176(pResourceManager, pTHM1176));
		ASSERT_NE(nullptr, pResourceManager);
		ASSERT_NE(nullptr, pTHM1176);
		ASSERT_EQ(true, pTHM1176->IsOpen());
		ASSERT_EQ(true, pTHM1176->Reset());
	}
	
	static void TearDownTestCase()
	{
		delete pTHM1176;
		pTHM1176 = nullptr;
		delete pResourceManager;
		pResourceManager = nullptr;
	}
};
THM1176_TEST_RESOURCE_MANAGER_CLASS * CTHM1176SetGetParametersTest::pResourceManager = nullptr;
CTHM1176Instrument<THM1176_TEST_INSTRUMENT_CLASS, THM1176_TEST_RESOURCE_MANAGER_CLASS> * CTHM1176SetGetParametersTest::pTHM1176 = nullptr;

/// \test Test ParmAveragingGet and ParmAveragingSet methods.
TEST_F(CTHM1176SetGetParametersTest, ParmAveraging)
{
	sAveraging<uParm> l_Avg;
	sAveraging<sBoundedParm> l_AvgBounds;
	
	ASSERT_EQ(true, pTHM1176->ParmAveragingGet(l_AvgBounds));
	EXPECT_EQ(1, l_AvgBounds.NoPoints.Min);
	EXPECT_LE(l_AvgBounds.NoPoints.Min, l_AvgBounds.NoPoints.Val);
	EXPECT_LE(l_AvgBounds.NoPoints.Val, l_AvgBounds.NoPoints.Max);
	EXPECT_EQ(l_AvgBounds.NoPoints.Max, 0xffff);
	EXPECT_EQ(1, l_AvgBounds.NoPoints.Def);
	EXPECT_EQ(l_AvgBounds.NoPoints.Def, l_AvgBounds.NoPoints.Val);

	l_Avg.NoPoints = 100;
	ASSERT_EQ(true, pTHM1176->ParmAveragingSet(l_Avg));
	l_Avg.NoPoints = 0;
	ASSERT_EQ(true, pTHM1176->ParmAveragingGet(l_Avg));
	EXPECT_EQ(100, l_Avg.NoPoints);
	
	ASSERT_EQ(true, pTHM1176->ParmAveragingGet(l_AvgBounds));
	EXPECT_EQ(1, l_AvgBounds.NoPoints.Min);
	EXPECT_LE(l_AvgBounds.NoPoints.Min, l_AvgBounds.NoPoints.Val);
	EXPECT_LE(l_AvgBounds.NoPoints.Val, l_AvgBounds.NoPoints.Max);
	EXPECT_EQ(l_AvgBounds.NoPoints.Max, 0xffff);
	EXPECT_EQ(1, l_AvgBounds.NoPoints.Def);
	EXPECT_EQ(100, l_AvgBounds.NoPoints.Val);

	l_Avg.NoPoints = l_AvgBounds.NoPoints.Min;
	ASSERT_EQ(true, pTHM1176->ParmAveragingSet(l_Avg));
	l_Avg.NoPoints = l_AvgBounds.NoPoints.Max;
	ASSERT_EQ(true, pTHM1176->ParmAveragingSet(l_Avg));
	l_Avg.NoPoints = 0;
	ASSERT_EQ(false, pTHM1176->ParmAveragingSet(l_Avg));
	{
		std::vector<sError> l_ErrorList = pTHM1176->CurrentErrorList();
		ASSERT_EQ(1, l_ErrorList.size());
		EXPECT_EQ(-222, l_ErrorList[0].Code);
		EXPECT_EQ("Data out of range", l_ErrorList[0].Description);
		EXPECT_EQ(":AVER:COUN 0", l_ErrorList[0].Context);
	}
}

/// \test Test ParmSleepGet and ParmSleepSet methods.
TEST_F(CTHM1176SetGetParametersTest, ParmSleep)
{
	bool l_Sleep = false;
	
	ASSERT_EQ(true, pTHM1176->ParmSleepSet(true));
	ASSERT_EQ(true, pTHM1176->ParmSleepGet(l_Sleep));
	EXPECT_EQ(true, l_Sleep);
	
	ASSERT_EQ(true, pTHM1176->ParmSleepSet(false));
	ASSERT_EQ(true, pTHM1176->ParmSleepGet(l_Sleep));
	EXPECT_EQ(false, l_Sleep);
}

/// \test Test ParmTriggerInputGet and ParmTriggerInputSet methods.
TEST_F(CTHM1176SetGetParametersTest, ParmTriggerInput)
{
	sInputTrigger<uParm> l_Trig;
	sInputTrigger<sBoundedParm> l_TrigBounds;

	// Test Bounds
	ASSERT_EQ(true, pTHM1176->ParmTriggerInputGet(l_TrigBounds));
	
	EXPECT_EQ(kInputTrigSrcImmediate, l_TrigBounds.Source);
	
	EXPECT_DOUBLE_EQ(122e-6, l_TrigBounds.Period_s.Min);
	EXPECT_LE(l_TrigBounds.Period_s.Min, l_TrigBounds.Period_s.Val);
	EXPECT_LE(l_TrigBounds.Period_s.Val, l_TrigBounds.Period_s.Max);
	EXPECT_DOUBLE_EQ(l_TrigBounds.Period_s.Max, 2.79);
	EXPECT_DOUBLE_EQ(0.1, l_TrigBounds.Period_s.Def);
	EXPECT_DOUBLE_EQ(l_TrigBounds.Period_s.Val, l_TrigBounds.Period_s.Def);
	
	EXPECT_EQ(1, l_TrigBounds.Count.Min);
	EXPECT_LE(l_TrigBounds.Count.Min, l_TrigBounds.Count.Val);
	EXPECT_LE(l_TrigBounds.Count.Val, l_TrigBounds.Count.Max);
	EXPECT_EQ(l_TrigBounds.Count.Max, 4096);
	EXPECT_EQ(1, l_TrigBounds.Count.Def);
	EXPECT_EQ(l_TrigBounds.Count.Val, l_TrigBounds.Count.Def);
	
	// Test Source
	l_Trig.Period_s	= l_TrigBounds.Period_s.Def;
	l_Trig.Count		= l_TrigBounds.Count.Def;
	
	l_Trig.Source	= kInputTrigSrcImmediate;
	ASSERT_EQ(true, pTHM1176->ParmTriggerInputSet(l_Trig));
	l_Trig.Source	= kInputTrigSrcTimer;
	ASSERT_EQ(true, pTHM1176->ParmTriggerInputGet(l_Trig));
	EXPECT_EQ(kInputTrigSrcImmediate, l_Trig.Source);
	EXPECT_DOUBLE_EQ(l_TrigBounds.Period_s.Def, l_Trig.Period_s);
	EXPECT_EQ(l_TrigBounds.Count.Def, l_Trig.Count);
	
	l_Trig.Source	= kInputTrigSrcTimer;
	ASSERT_EQ(true, pTHM1176->ParmTriggerInputSet(l_Trig));
	l_Trig.Source	= kInputTrigSrcBus;
	ASSERT_EQ(true, pTHM1176->ParmTriggerInputGet(l_Trig));
	EXPECT_EQ(kInputTrigSrcTimer, l_Trig.Source);
	EXPECT_DOUBLE_EQ(l_TrigBounds.Period_s.Def, l_Trig.Period_s);
	EXPECT_EQ(l_TrigBounds.Count.Def, l_Trig.Count);
	
	l_Trig.Source	= kInputTrigSrcBus;
	ASSERT_EQ(true, pTHM1176->ParmTriggerInputSet(l_Trig));
	l_Trig.Source	= kInputTrigSrcImmediate;
	ASSERT_EQ(true, pTHM1176->ParmTriggerInputGet(l_Trig));
	EXPECT_EQ(kInputTrigSrcBus, l_Trig.Source);
	EXPECT_DOUBLE_EQ(l_TrigBounds.Period_s.Def, l_Trig.Period_s);
	EXPECT_EQ(l_TrigBounds.Count.Def, l_Trig.Count);
	
	// Test Period_s
	l_Trig.Source	= kInputTrigSrcTimer;
	l_Trig.Count		= l_TrigBounds.Count.Def;
	
	l_Trig.Period_s	= 1.;
	ASSERT_EQ(true, pTHM1176->ParmTriggerInputSet(l_Trig));
	l_Trig.Period_s = 0;
	ASSERT_EQ(true, pTHM1176->ParmTriggerInputGet(l_Trig));
	EXPECT_EQ(kInputTrigSrcTimer, l_Trig.Source);
	EXPECT_DOUBLE_EQ(1., l_Trig.Period_s);
	EXPECT_EQ(l_TrigBounds.Count.Def, l_Trig.Count);

	l_Trig.Period_s = l_TrigBounds.Period_s.Min;
	ASSERT_EQ(true, pTHM1176->ParmTriggerInputSet(l_Trig));
	l_Trig.Period_s = l_TrigBounds.Period_s.Max;
	ASSERT_EQ(true, pTHM1176->ParmTriggerInputSet(l_Trig));
	l_Trig.Period_s = 0;
	ASSERT_EQ(false, pTHM1176->ParmTriggerInputSet(l_Trig));
	{
		std::vector<sError> l_ErrorList = pTHM1176->CurrentErrorList();
		ASSERT_EQ(1, l_ErrorList.size());
		EXPECT_EQ(-222, l_ErrorList[0].Code);
		EXPECT_EQ("Data out of range", l_ErrorList[0].Description);
		EXPECT_EQ(":TRIG:SOUR TIM;COUN 1;TIM 0.000000000000000e+00", l_ErrorList[0].Context);
	}
	l_Trig.Period_s = 10.;
	ASSERT_EQ(false, pTHM1176->ParmTriggerInputSet(l_Trig));
	{
		std::vector<sError> l_ErrorList = pTHM1176->CurrentErrorList();
		ASSERT_EQ(1, l_ErrorList.size());
		EXPECT_EQ(-222, l_ErrorList[0].Code);
		EXPECT_EQ("Data out of range", l_ErrorList[0].Description);
		EXPECT_EQ(":TRIG:SOUR TIM;COUN 1;TIM 1.000000000000000e+01", l_ErrorList[0].Context);
	}

	// Test Count
	l_Trig.Source	= kInputTrigSrcImmediate;
	
	l_Trig.Count = 100;
	ASSERT_EQ(true, pTHM1176->ParmTriggerInputSet(l_Trig));
	l_Trig.Count = 0;
	ASSERT_EQ(true, pTHM1176->ParmTriggerInputGet(l_Trig));
	EXPECT_EQ(kInputTrigSrcImmediate, l_Trig.Source);
	EXPECT_EQ(100, l_Trig.Count);
	
	l_Trig.Count = l_TrigBounds.Count.Min;
	ASSERT_EQ(true, pTHM1176->ParmTriggerInputSet(l_Trig));
	l_Trig.Count = l_TrigBounds.Count.Max;
	ASSERT_EQ(true, pTHM1176->ParmTriggerInputSet(l_Trig));
	l_Trig.Count = 0;
	ASSERT_EQ(false, pTHM1176->ParmTriggerInputSet(l_Trig));
	{
		std::vector<sError> l_ErrorList = pTHM1176->CurrentErrorList();
		ASSERT_EQ(1, l_ErrorList.size());
		EXPECT_EQ(-222, l_ErrorList[0].Code);
		EXPECT_EQ("Data out of range", l_ErrorList[0].Description);
		EXPECT_EQ(":TRIG:SOUR IMM;COUN 0", l_ErrorList[0].Context);
	}
	l_Trig.Count = 4097;
	ASSERT_EQ(false, pTHM1176->ParmTriggerInputSet(l_Trig));
	{
		std::vector<sError> l_ErrorList = pTHM1176->CurrentErrorList();
		ASSERT_EQ(1, l_ErrorList.size());
		EXPECT_EQ(-222, l_ErrorList[0].Code);
		EXPECT_EQ("Data out of range", l_ErrorList[0].Description);
		EXPECT_EQ(":TRIG:SOUR IMM;COUN 4097", l_ErrorList[0].Context);
	}
}

/// \test Test ParmUnitsGet and ParmUnitsSet methods.
TEST_F(CTHM1176SetGetParametersTest, ParmUnits)
{
	CUnitsList l_Units;
	ASSERT_EQ(true, pTHM1176->GetAllUnits(l_Units));
	for (auto l_Unit : l_Units)
	{
		ASSERT_EQ(true, pTHM1176->ParmUnitsSet(l_Unit));
		eUnits l_UnitRead;
		ASSERT_EQ(true, pTHM1176->ParmUnitsGet(l_UnitRead));
		EXPECT_EQ(l_Unit, l_UnitRead);
	}
}

/// \test Test ParmUseCalibrationGet and ParmUseCalibrationSet methods.
TEST_F(CTHM1176SetGetParametersTest, ParmUseCalibration)
{
	bool l_UseCalibration = false;
	
	ASSERT_EQ(true, pTHM1176->ParmUseCalibrationSet(true));
	ASSERT_EQ(true, pTHM1176->ParmUseCalibrationGet(l_UseCalibration));
	EXPECT_EQ(true, l_UseCalibration);
	
	ASSERT_EQ(true, pTHM1176->ParmUseCalibrationSet(false));
	ASSERT_EQ(true, pTHM1176->ParmUseCalibrationGet(l_UseCalibration));
	EXPECT_EQ(false, l_UseCalibration);
}

/// \test Test ParmRangeGet and ParmRangeSet methods.
TEST_F(CTHM1176SetGetParametersTest, ParmRange)
{
	sRange<uParm> l_RangeStruct;
	sRange<sBoundedParm> l_RangeStructBounds;
	CFluxList l_Ranges;
	ASSERT_EQ(true, pTHM1176->GetAllRanges(l_Ranges));

	// Test Bounds.
	ASSERT_EQ(true, pTHM1176->ParmRangeGet(l_RangeStructBounds));
	EXPECT_EQ(true, l_RangeStructBounds.Auto);
	EXPECT_FLOAT_EQ(l_Ranges.front(), l_RangeStructBounds.Range.Min);
	EXPECT_LE(l_RangeStructBounds.Range.Min, l_RangeStructBounds.Range.Val);
	EXPECT_LE(l_RangeStructBounds.Range.Val, l_RangeStructBounds.Range.Max);
	EXPECT_FLOAT_EQ(l_RangeStructBounds.Range.Max, l_Ranges.back());
	EXPECT_FLOAT_EQ(l_Ranges.back(), l_RangeStructBounds.Range.Def);
	EXPECT_FLOAT_EQ(l_RangeStructBounds.Range.Def, l_RangeStructBounds.Range.Val);

	// Test Auto
	l_RangeStruct.Range = l_RangeStructBounds.Range.Def;
	
	l_RangeStruct.Auto = true;
	ASSERT_EQ(true, pTHM1176->ParmRangeSet(l_RangeStruct));
	l_RangeStruct.Auto = false;
	ASSERT_EQ(true, pTHM1176->ParmRangeGet(l_RangeStruct));
	EXPECT_EQ(true, l_RangeStruct.Auto);
	
	l_RangeStruct.Auto = false;
	ASSERT_EQ(true, pTHM1176->ParmRangeSet(l_RangeStruct));
	l_RangeStruct.Auto = true;
	ASSERT_EQ(true, pTHM1176->ParmRangeGet(l_RangeStruct));
	EXPECT_EQ(false, l_RangeStruct.Auto);
	
	// Test Range.
	l_RangeStruct.Auto = false;
	for (auto l_Range : l_Ranges)
	{
		l_RangeStruct.Range = l_Range;
		ASSERT_EQ(true, pTHM1176->ParmRangeSet(l_RangeStruct));
		l_RangeStruct.Auto = 0.;
		ASSERT_EQ(true, pTHM1176->ParmRangeGet(l_RangeStruct));
		EXPECT_EQ(false, l_RangeStruct.Auto);
		EXPECT_FLOAT_EQ(l_Range, l_RangeStruct.Range);
	}
}

