// 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: Handling timeouts on long acquisitions

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

#include <ctime>
#include <thread>

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

/// \brief Test THM1176 API: Handling timeouts on long acquisitions
class CTHM1176TimeoutHandlingTest : 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;
	}
	
	virtual void SetUp()
	{
		// Reset the instrument.
		ASSERT_NE(pTHM1176, nullptr);
		ASSERT_EQ(true, pTHM1176->Reset());
	}
};
THM1176_TEST_RESOURCE_MANAGER_CLASS * CTHM1176TimeoutHandlingTest::pResourceManager = nullptr;
CTHM1176Instrument<THM1176_TEST_INSTRUMENT_CLASS, THM1176_TEST_RESOURCE_MANAGER_CLASS> * CTHM1176TimeoutHandlingTest::pTHM1176 = nullptr;

/// \test Test Measure method after SetTimeout with a short timeout.
TEST_F(CTHM1176TimeoutHandlingTest, ReadWithTimeout)
{
	// Reset the instrument.
	ASSERT_EQ(true, pTHM1176->Reset());
	
	// Set up a timed trigger of 1 measurement / second.
	sInputTrigger<uParm> l_Trig;
	l_Trig.Source	= kInputTrigSrcTimer;
	l_Trig.Period_s	= 1.;
	l_Trig.Count	= 1;
	ASSERT_EQ(true, pTHM1176->ParmTriggerInputSet(l_Trig));
	
	// Set the timeout to 1 second.
	pTHM1176->SetTimeout(1000);
	
	// Measure multiple with with NoMeasurements = 3, DefaultParms=false.
	// This should complete successfully, working through the timeouts.
	CFluxList	l_Bx, l_By, l_Bz;
	ASSERT_EQ(true, pTHM1176->Measure(l_Bx, l_By, l_Bz, 3, false));
}

static void l_LaunchMeasurement(CTHM1176Instrument<THM1176_TEST_INSTRUMENT_CLASS, THM1176_TEST_RESOURCE_MANAGER_CLASS> * pTHM1176)
{
	// Measure multiple with with NoMeasurements = 4096, DefaultParms=false.
	CFluxList	l_Bx, l_By, l_Bz;
	pTHM1176->Measure(l_Bx, l_By, l_Bz, 4096, false);
}

/// \test Test AbortRead method.
TEST_F(CTHM1176TimeoutHandlingTest, DISABLED_AbortRead)
{
	// Reset the instrument.
	ASSERT_EQ(true, pTHM1176->Reset());
	
	// Set up a timed trigger of 1 measurement / second.
	sInputTrigger<uParm> l_Trig;
	l_Trig.Source	= kInputTrigSrcTimer;
	l_Trig.Period_s	= 1.;
	l_Trig.Count		= 1;
	ASSERT_EQ(true, pTHM1176->ParmTriggerInputSet(l_Trig));
	
	// Set the timeout to 1 second.
	pTHM1176->SetTimeout(1000);
	
	// An AbortRead without an ongoing Read should fail.
	ASSERT_EQ(false, pTHM1176->AbortRead());
	
	// Launch the measurement in another thread.
	std::thread l_MeasurementThread(l_LaunchMeasurement, pTHM1176);
	
	// Wait a second for the measurement to start.
	std::this_thread::sleep_for(std::chrono::seconds(1));
	
	// Try to abort the measurement.
	ASSERT_EQ(true, pTHM1176->AbortRead());
	
	// Wait for the measurement thread to finish execution.
	l_MeasurementThread.join();
	
	// Perform a plain-jane measurement to ensure the instrument is
	// left in a usable state.
	CFluxList	l_Bx, l_By, l_Bz;
	ASSERT_EQ(true, pTHM1176->Measure(l_Bx, l_By, l_Bz));
}
