// 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 IEEE488 Instrument: Read and Write methods.

#pragma once

#include <gtest/gtest.h>

#include "IEEE488InstrumentTest.h"

using namespace testing;

class IEEE488InstrumentReadWriteTest : public ::testing::Test
{
protected:
    static IEEE4888_TEST_RESOURCE_MANAGER_CLASS *	pResourceManager;
    static IEEE4888_TEST_INSTRUMENT_CLASS *         pInstrument;

    static void SetUpTestCase()
    {
        ASSERT_EQ(true, ConnectToIEEE488Instrument(pResourceManager, pInstrument));
        ASSERT_NE(nullptr, pResourceManager);
        ASSERT_NE(nullptr, pInstrument);
        ASSERT_EQ(true, pInstrument->IsOpen());
        ASSERT_EQ(true, pInstrument->Clear());
    }

    static void TearDownTestCase()
    {
        delete pInstrument;
        pInstrument = nullptr;
        delete pResourceManager;
        pResourceManager = nullptr;
    }
};

IEEE4888_TEST_RESOURCE_MANAGER_CLASS *  IEEE488InstrumentReadWriteTest::pResourceManager    = nullptr;
IEEE4888_TEST_INSTRUMENT_CLASS *        IEEE488InstrumentReadWriteTest::pInstrument         = nullptr;

/// \brief Test *IDN? query with C string variant of Write.
TEST_F(IEEE488InstrumentReadWriteTest, IDN_Query_WriteCString)
{
    ASSERT_EQ(true, pInstrument->Write ("*IDN?"));
    CSCPIBuffer l_Buffer;
    ASSERT_EQ(true, pInstrument->Read (l_Buffer));
    EXPECT_EQ(true, CheckIDNResponse (l_Buffer));

}

/// \brief Test *IDN? query with C++ string variant of Write.
TEST_F(IEEE488InstrumentReadWriteTest, IDN_Query_WriteCPPString)
{
    ASSERT_EQ(true, pInstrument->Write (std::string("*IDN?")));
    CSCPIBuffer l_Buffer;
    ASSERT_EQ(true, pInstrument->Read (l_Buffer));
    EXPECT_EQ(true, CheckIDNResponse (l_Buffer));

}

/// \brief Test *IDN? query with SCPI Buffer variant of Write.
TEST_F(IEEE488InstrumentReadWriteTest, IDN_Query_WriteSCPIBuffer)
{
    const char * l_Command = "*IDN?";
    CSCPIBuffer l_Buffer(l_Command, std::strlen(l_Command));
    ASSERT_EQ(true, pInstrument->Write (l_Buffer));
    ASSERT_EQ(true, pInstrument->Read (l_Buffer));
    EXPECT_EQ(true, CheckIDNResponse (l_Buffer));

}

/// \brief Test *IDN? query response split into multiple buffers.
TEST_F(IEEE488InstrumentReadWriteTest, IDN_Query_MultipleBuffers)
{
    CSCPIBuffer l_Buffer(16);
    ASSERT_EQ(true, pInstrument->Write ("*IDN?"));

    ASSERT_EQ(true, pInstrument->Read (l_Buffer, false));
    for (;;)
    {
        U16 l_Status;
        ASSERT_EQ(true, pInstrument->ReadSTB (l_Status));
        if ((l_Status & 0x0010) == 0) break;
        ASSERT_EQ(true, pInstrument->Read (l_Buffer, true));
    }

    EXPECT_EQ(true, CheckIDNResponse(l_Buffer));

}

/// \brief Test *IDN? query after spurious read (tests Clear BulkIn).
TEST_F(IEEE488InstrumentReadWriteTest, IDN_Query_AfterSpuriousRead)
{
    // Perform a spurious read.
    CSCPIBuffer l_Buffer;
    ASSERT_EQ(false, pInstrument->Read (l_Buffer));

    // Perform the *IDN? query.
    ASSERT_EQ(true, pInstrument->Write ("*IDN?"));
    ASSERT_EQ(true, pInstrument->Read (l_Buffer));
    EXPECT_EQ(true, CheckIDNResponse (l_Buffer));

}

/// \brief Test *IDN? query after failed write (tests Clear BulkOut).
TEST_F(IEEE488InstrumentReadWriteTest, IDN_Query_AfterFailedWrite)
{
    // Write a long command with a very short timeout.
    std::string l_LongCommand;
    for (int i = 0; i < 100; i++)
        l_LongCommand += "*RST;";
    U32 l_Timeout = pInstrument->GetTimeout();
    pInstrument->SetTimeout(1ul);
    ASSERT_EQ(false, pInstrument->Write (l_LongCommand));

    // Restore the default timeout and perform the *IDN? query.
    pInstrument->SetTimeout(l_Timeout);
    ASSERT_EQ(true, pInstrument->Write ("*IDN?"));
    CSCPIBuffer l_Buffer;
    ASSERT_EQ(true, pInstrument->Read (l_Buffer));
    EXPECT_EQ(true, CheckIDNResponse (l_Buffer));

}

