text: /*
   * LLCmdDispatcherImplTester.cpp
   *
   *  Created on: Mar 18, 2015
   *      Author: tcanham
   */
  
  #include <LLProc/LLCmdDispatcher/test/ut/Tester.hpp>
  #include <Fw/Com/ComBuffer.hpp>
  #include <Fw/Com/ComPacket.hpp>
  #include <Os/IntervalTimer.hpp>
  
  #include <cstdio>
  
  #include <gtest/gtest.h>
  #include <Fw/Test/UnitTest.hpp>
  
  
  namespace LLProc {
  
      void LLCmdDispatcherImplTester::init(NATIVE_INT_TYPE instance) {
          LLCmdDispatcherGTestBase::init();
      }
  
      LLCmdDispatcherImplTester::LLCmdDispatcherImplTester(LLProc::LLCmdDispatcherImpl& inst) :
          LLCmdDispatcherGTestBase("testerbase",100),
          m_impl(inst) {
      }
  
      LLCmdDispatcherImplTester::~LLCmdDispatcherImplTester() {
      }
  
      void LLCmdDispatcherImplTester::from_compCmdSend_handler(NATIVE_INT_TYPE portNum, FwOpcodeType opCode, U32 cmdSeq, Fw::CmdArgBuffer &args) {
          this->m_cmdSendOpCode = opCode;
          this->m_cmdSendCmdSeq = cmdSeq;
          this->m_cmdSendArgs = args;
          this->m_cmdSendRcvd = true;
      }
  
      void LLCmdDispatcherImplTester::from_seqCmdStatus_handler(NATIVE_INT_TYPE portNum, FwOpcodeType opCode, U32 cmdSeq, Fw::CommandResponse response) {
          this->m_seqStatusRcvd = true;
          this->m_seqStatusOpCode = opCode;
          this->m_seqStatusCmdSeq = cmdSeq;
          this->m_seqStatusCmdResponse = response;
      }
  
      void LLCmdDispatcherImplTester::runNominalDispatch(void) {
  
          // verify dispatch table is empty
          for (NATIVE_UINT_TYPE entry = 0; entry < FW_NUM_ARRAY_ELEMENTS(this->m_impl.m_entryTable); entry++) {
              ASSERT_TRUE(this->m_impl.m_entryTable[entry].used == false);
          }
  
          // verify sequence tracker table is empty
  
          for (NATIVE_UINT_TYPE entry = 0; entry < FW_NUM_ARRAY_ELEMENTS(this->m_impl.m_sequenceTracker); entry++) {
              ASSERT_TRUE(this->m_impl.m_sequenceTracker[entry].used == false);
          }
          // clear reg events
          this->clearEvents();
          // register built-in commands
          this->m_impl.regCommands();
          // verify registrations
          ASSERT_TRUE(this->m_impl.m_entryTable[0].used);
          ASSERT_EQ(this->m_impl.m_entryTable[0].opcode,LLCmdDispatcherImpl::OPCODE_CMD_NO_OP);
          ASSERT_EQ(this->m_impl.m_entryTable[0].port,1);
  
          ASSERT_TRUE(this->m_impl.m_entryTable[1].used);
          ASSERT_EQ(this->m_impl.m_entryTable[1].opcode,LLCmdDispatcherImpl::OPCODE_CMD_NO_OP_STRING);
          ASSERT_EQ(this->m_impl.m_entryTable[1].port,1);
  
          ASSERT_TRUE(this->m_impl.m_entryTable[2].used);
          ASSERT_EQ(this->m_impl.m_entryTable[2].opcode,LLCmdDispatcherImpl::OPCODE_CMD_TEST_CMD_1);
          ASSERT_EQ(this->m_impl.m_entryTable[2].port,1);
  
          ASSERT_TRUE(this->m_impl.m_entryTable[3].used);
          ASSERT_EQ(this->m_impl.m_entryTable[3].opcode,LLCmdDispatcherImpl::OPCODE_CMD_CLEAR_TRACKING);
          ASSERT_EQ(this->m_impl.m_entryTable[3].port,1);
  
          // verify event
          printTextLogHistory(stdout);
          ASSERT_EVENTS_SIZE(4);
          ASSERT_EVENTS_OpCodeRegistered_SIZE(4);
          ASSERT_EVENTS_OpCodeRegistered(0,LLCmdDispatcherImpl::OPCODE_CMD_NO_OP,1,0);
          ASSERT_EVENTS_OpCodeRegistered(1,LLCmdDispatcherImpl::OPCODE_CMD_NO_OP_STRING,1,1);
          ASSERT_EVENTS_OpCodeRegistered(2,LLCmdDispatcherImpl::OPCODE_CMD_TEST_CMD_1,1,2);
          ASSERT_EVENTS_OpCodeRegistered(3,LLCmdDispatcherImpl::OPCODE_CMD_CLEAR_TRACKING,1,3);
  
  
          REQUIREMENT("CD-003");
          // register our own command
          FwOpcodeType testOpCode = 0x50;
  
          this->clearEvents();
          this->invoke_to_compCmdReg(0,0x50);
          ASSERT_TRUE(this->m_impl.m_entryTable[4].used);
          ASSERT_EQ(this->m_impl.m_entryTable[4].opcode,testOpCode);
          ASSERT_EQ(this->m_impl.m_entryTable[4].port,0);
  
          // verify registration event
          ASSERT_EVENTS_SIZE(1);
          ASSERT_EVENTS_OpCodeRegistered_SIZE(1);
          ASSERT_EVENTS_OpCodeRegistered(0,testOpCode,0,4);
  
          // dispatch a test command
          REQUIREMENT("CD-001");
  
          U32 testCmdArg = 100;
          U32 testContext = 110;
          this->clearEvents();
          Fw::ComBuffer buff;
          ASSERT_EQ(buff.serialize(FwPacketDescriptorType(Fw::ComPacket::FW_PACKET_COMMAND)),Fw::FW_SERIALIZE_OK);
          ASSERT_EQ(buff.serialize(testOpCode),Fw::FW_SERIALIZE_OK);
          ASSERT_EQ(buff.serialize(testCmdArg),Fw::FW_SERIALIZE_OK);
  
          this->invoke_to_seqCmdBuff(0,buff,testContext);
  
          REQUIREMENT("CD-002");
  
          // verify dispatch event
          ASSERT_EVENTS_SIZE(1);
          ASSERT_EVENTS_OpCodeDispatched_SIZE(1);
          ASSERT_EVENTS_OpCodeDispatched(0,(U32)testOpCode,0);
  
          // verify sequence table entry
          ASSERT_TRUE(this->m_impl.m_sequenceTracker[0].used);
          ASSERT_EQ(this->m_impl.m_sequenceTracker[0].seq,(U32)0);
          ASSERT_EQ(this->m_impl.m_sequenceTracker[0].opCode,testOpCode);
          ASSERT_EQ(this->m_impl.m_sequenceTracker[0].callerPort,(NATIVE_INT_TYPE)0);
  
          // verify command received
          ASSERT_TRUE(this->m_cmdSendRcvd);
          ASSERT_EQ(this->m_cmdSendOpCode,testOpCode);
          ASSERT_EQ(this->m_cmdSendCmdSeq,(U32)0);
          // check argument
          U32 checkVal;
          ASSERT_EQ(this->m_cmdSendArgs.deserialize(checkVal),Fw::FW_SERIALIZE_OK);
          ASSERT_EQ(checkVal,testCmdArg);
  
          this->clearEvents();
          this->m_seqStatusRcvd = false;
          // perform command response
          this->invoke_to_compCmdStat(0,testOpCode,this->m_cmdSendCmdSeq,Fw::COMMAND_OK);
  
          // Check dispatch table
          ASSERT_FALSE(this->m_impl.m_sequenceTracker[0].used);
          ASSERT_EQ(this->m_impl.m_sequenceTracker[0].seq,(U32)0);
          ASSERT_EQ(this->m_impl.m_sequenceTracker[0].opCode,testOpCode);
          ASSERT_EQ(this->m_impl.m_sequenceTracker[0].context,testContext);
          ASSERT_EQ(this->m_impl.m_sequenceTracker[0].callerPort,(NATIVE_INT_TYPE)0);
  
          // Verify completed event
          ASSERT_EVENTS_SIZE(1);
          ASSERT_EVENTS_OpCodeCompleted_SIZE(1);
          ASSERT_EVENTS_OpCodeCompleted(0,(U32)testOpCode);
  
          REQUIREMENT("CD-004");
  
          // Verify status passed back to port
          ASSERT_TRUE(this->m_seqStatusRcvd);
          ASSERT_EQ(this->m_seqStatusOpCode,(U32)testOpCode);
          ASSERT_EQ(this->m_seqStatusCmdSeq,testContext);
          ASSERT_EQ(this->m_seqStatusCmdResponse,Fw::COMMAND_OK);
      }
  
      void LLCmdDispatcherImplTester::runNopCommands(void) {
  
          // verify dispatch table is empty
          for (NATIVE_UINT_TYPE entry = 0; entry < FW_NUM_ARRAY_ELEMENTS(this->m_impl.m_entryTable); entry++) {
              ASSERT_TRUE(this->m_impl.m_entryTable[entry].used == false);
          }
  
          // verify sequence tracker table is empty
  
          for (NATIVE_UINT_TYPE entry = 0; entry < FW_NUM_ARRAY_ELEMENTS(this->m_impl.m_sequenceTracker); entry++) {
              ASSERT_TRUE(this->m_impl.m_sequenceTracker[entry].used == false);
          }
  
          // clear reg events
          this->clearEvents();
          // register built-in commands
          this->m_impl.regCommands();
          // verify registrations
          ASSERT_TRUE(this->m_impl.m_entryTable[0].used);
          ASSERT_EQ(this->m_impl.m_entryTable[0].opcode,LLCmdDispatcherImpl::OPCODE_CMD_NO_OP);
          ASSERT_EQ(this->m_impl.m_entryTable[0].port,1);
  
          ASSERT_TRUE(this->m_impl.m_entryTable[1].used);
          ASSERT_EQ(this->m_impl.m_entryTable[1].opcode,LLCmdDispatcherImpl::OPCODE_CMD_NO_OP_STRING);
          ASSERT_EQ(this->m_impl.m_entryTable[1].port,1);
  
          ASSERT_TRUE(this->m_impl.m_entryTable[2].used);
          ASSERT_EQ(this->m_impl.m_entryTable[2].opcode,LLCmdDispatcherImpl::OPCODE_CMD_TEST_CMD_1);
          ASSERT_EQ(this->m_impl.m_entryTable[2].port,1);
  
          ASSERT_TRUE(this->m_impl.m_entryTable[3].used);
          ASSERT_EQ(this->m_impl.m_entryTable[3].opcode,LLCmdDispatcherImpl::OPCODE_CMD_CLEAR_TRACKING);
          ASSERT_EQ(this->m_impl.m_entryTable[3].port,1);
  
          // verify event
  
          ASSERT_EVENTS_SIZE(4);
          ASSERT_EVENTS_OpCodeRegistered_SIZE(4);
          ASSERT_EVENTS_OpCodeRegistered(0,LLCmdDispatcherImpl::OPCODE_CMD_NO_OP,1,0);
          ASSERT_EVENTS_OpCodeRegistered(1,LLCmdDispatcherImpl::OPCODE_CMD_NO_OP_STRING,1,1);
          ASSERT_EVENTS_OpCodeRegistered(2,LLCmdDispatcherImpl::OPCODE_CMD_TEST_CMD_1,1,2);
          ASSERT_EVENTS_OpCodeRegistered(3,LLCmdDispatcherImpl::OPCODE_CMD_CLEAR_TRACKING,1,3);
  
          // send NO_OP command
          this->m_seqStatusRcvd = false;
          Fw::ComBuffer buff;
          ASSERT_EQ(buff.serialize(FwPacketDescriptorType(Fw::ComPacket::FW_PACKET_COMMAND)),Fw::FW_SERIALIZE_OK);
          ASSERT_EQ(buff.serialize((FwOpcodeType)LLCmdDispatcherImpl::OPCODE_CMD_NO_OP),Fw::FW_SERIALIZE_OK);
  
          this->clearEvents();
          this->invoke_to_seqCmdBuff(0,buff,12);
  
          // verify dispatch event
          ASSERT_EVENTS_SIZE(1);
          ASSERT_EVENTS_OpCodeDispatched_SIZE(1);
          ASSERT_EVENTS_OpCodeDispatched(0,LLCmdDispatcherImpl::OPCODE_CMD_NO_OP,1);
  
          // Verify status passed back to port
          ASSERT_TRUE(this->m_seqStatusRcvd);
          ASSERT_EQ(LLCmdDispatcherImpl::OPCODE_CMD_NO_OP,this->m_seqStatusOpCode);
          // Verify correct context value is passed back.
          ASSERT_EQ((U32)12,this->m_seqStatusCmdSeq);
          ASSERT_EQ(this->m_seqStatusCmdResponse,Fw::COMMAND_OK);
  
          // send NO_OP_STRING command
          this->clearEvents();
          this->m_seqStatusRcvd = false;
          buff.resetSer();
          ASSERT_EQ(buff.serialize(FwPacketDescriptorType(Fw::ComPacket::FW_PACKET_COMMAND)),Fw::FW_SERIALIZE_OK);
          ASSERT_EQ(buff.serialize((FwOpcodeType)LLCmdDispatcherImpl::OPCODE_CMD_NO_OP_STRING),Fw::FW_SERIALIZE_OK);
          // serialize arg1
          Fw::CmdStringArg argString("BOO!");
          ASSERT_EQ(buff.serialize(argString),Fw::FW_SERIALIZE_OK);
  
          this->invoke_to_seqCmdBuff(0,buff,13);
  
          // verify dispatch event
          ASSERT_EVENTS_SIZE(1);
          ASSERT_EVENTS_OpCodeDispatched_SIZE(1);
          ASSERT_EVENTS_OpCodeDispatched(0,LLCmdDispatcherImpl::OPCODE_CMD_NO_OP_STRING,1);
  
          // Verify status passed back to port
          ASSERT_TRUE(this->m_seqStatusRcvd);
          ASSERT_EQ(LLCmdDispatcherImpl::OPCODE_CMD_NO_OP_STRING,this->m_seqStatusOpCode);
          ASSERT_EQ((U32)13,this->m_seqStatusCmdSeq);
          ASSERT_EQ(this->m_seqStatusCmdResponse,Fw::COMMAND_OK);
  
          // send TEST_CMD_1 command
          this->m_seqStatusRcvd = false;
          buff.resetSer();
          ASSERT_EQ(buff.serialize(FwPacketDescriptorType(Fw::ComPacket::FW_PACKET_COMMAND)),Fw::FW_SERIALIZE_OK);
          ASSERT_EQ(buff.serialize((FwOpcodeType)LLCmdDispatcherImpl::OPCODE_CMD_TEST_CMD_1),Fw::FW_SERIALIZE_OK);
          // serialize arg1
          ASSERT_EQ(buff.serialize((I32)1),Fw::FW_SERIALIZE_OK);
          // serialize arg2
          ASSERT_EQ(buff.serialize((F32)2.3),Fw::FW_SERIALIZE_OK);
          // serialize arg3
          ASSERT_EQ(buff.serialize((U8)4),Fw::FW_SERIALIZE_OK);
  
          this->clearEvents();
          this->invoke_to_seqCmdBuff(0,buff,14);
  
          // verify dispatch event
          ASSERT_EVENTS_SIZE(1);
          ASSERT_EVENTS_OpCodeDispatched_SIZE(1);
          ASSERT_EVENTS_OpCodeDispatched(0,LLCmdDispatcherImpl::OPCODE_CMD_TEST_CMD_1,1);
  
          // Verify status passed back to port
          ASSERT_TRUE(this->m_seqStatusRcvd);
          ASSERT_EQ(LLCmdDispatcherImpl::OPCODE_CMD_TEST_CMD_1,this->m_seqStatusOpCode);
          ASSERT_EQ((U32)14,this->m_seqStatusCmdSeq);
          ASSERT_EQ(this->m_seqStatusCmdResponse,Fw::COMMAND_OK);
      }
  
      void LLCmdDispatcherImplTester::runInvalidOpcodeDispatch(void) {
  
          // verify dispatch table is empty
          for (NATIVE_UINT_TYPE entry = 0; entry < FW_NUM_ARRAY_ELEMENTS(this->m_impl.m_entryTable); entry++) {
              ASSERT_TRUE(this->m_impl.m_entryTable[entry].used == false);
          }
  
          // verify sequence tracker table is empty
  
          for (NATIVE_UINT_TYPE entry = 0; entry < FW_NUM_ARRAY_ELEMENTS(this->m_impl.m_sequenceTracker); entry++) {
              ASSERT_TRUE(this->m_impl.m_sequenceTracker[entry].used == false);
          }
          // clear reg events
          this->clearEvents();
          // register built-in commands
          this->m_impl.regCommands();
          // verify registrations
          ASSERT_TRUE(this->m_impl.m_entryTable[0].used);
          ASSERT_EQ(this->m_impl.m_entryTable[0].opcode,LLCmdDispatcherImpl::OPCODE_CMD_NO_OP);
          ASSERT_EQ(this->m_impl.m_entryTable[0].port,1);
  
          ASSERT_TRUE(this->m_impl.m_entryTable[1].used);
          ASSERT_EQ(this->m_impl.m_entryTable[1].opcode,LLCmdDispatcherImpl::OPCODE_CMD_NO_OP_STRING);
          ASSERT_EQ(this->m_impl.m_entryTable[1].port,1);
  
          ASSERT_TRUE(this->m_impl.m_entryTable[2].used);
          ASSERT_EQ(this->m_impl.m_entryTable[2].opcode,LLCmdDispatcherImpl::OPCODE_CMD_TEST_CMD_1);
          ASSERT_EQ(this->m_impl.m_entryTable[2].port,1);
  
          ASSERT_TRUE(this->m_impl.m_entryTable[3].used);
          ASSERT_EQ(this->m_impl.m_entryTable[3].opcode,LLCmdDispatcherImpl::OPCODE_CMD_CLEAR_TRACKING);
          ASSERT_EQ(this->m_impl.m_entryTable[3].port,1);
  
          // verify event
          ASSERT_EVENTS_SIZE(4);
          ASSERT_EVENTS_OpCodeRegistered_SIZE(4);
          ASSERT_EVENTS_OpCodeRegistered(0,LLCmdDispatcherImpl::OPCODE_CMD_NO_OP,1,0);
          ASSERT_EVENTS_OpCodeRegistered(1,LLCmdDispatcherImpl::OPCODE_CMD_NO_OP_STRING,1,1);
          ASSERT_EVENTS_OpCodeRegistered(2,LLCmdDispatcherImpl::OPCODE_CMD_TEST_CMD_1,1,2);
          ASSERT_EVENTS_OpCodeRegistered(3,LLCmdDispatcherImpl::OPCODE_CMD_CLEAR_TRACKING,1,3);
  
          // register our own command
          FwOpcodeType testOpCode = 0x50;
  
          this->clearEvents();
          this->invoke_to_compCmdReg(0,0x50);
          ASSERT_TRUE(this->m_impl.m_entryTable[4].used);
          ASSERT_EQ(this->m_impl.m_entryTable[4].opcode,testOpCode);
          ASSERT_EQ(this->m_impl.m_entryTable[4].port,0);
  
          // verify registration event
          ASSERT_EVENTS_SIZE(1);
          ASSERT_EVENTS_OpCodeRegistered_SIZE(1);
          ASSERT_EVENTS_OpCodeRegistered(0,(U32)testOpCode,0,4);
  
          // dispatch a test command with a bad opcode
          U32 testCmdArg = 100;
          U32 testContext = 13;
          this->clearEvents();
          this->m_seqStatusRcvd = false;
          Fw::ComBuffer buff;
          ASSERT_EQ(buff.serialize(FwPacketDescriptorType(Fw::ComPacket::FW_PACKET_COMMAND)),Fw::FW_SERIALIZE_OK);
          ASSERT_EQ(buff.serialize(FwOpcodeType(testOpCode + 1)),Fw::FW_SERIALIZE_OK);
          ASSERT_EQ(buff.serialize(testCmdArg),Fw::FW_SERIALIZE_OK);
  
          this->clearEvents();
          this->invoke_to_seqCmdBuff(0,buff,testContext);
  
          // verify dispatch event
          ASSERT_EVENTS_SIZE(1);
          ASSERT_EVENTS_InvalidCommand_SIZE(1);
          ASSERT_EVENTS_InvalidCommand(0,(U32)testOpCode+1);
  
          // Verify status passed back to port
  
          ASSERT_TRUE(this->m_seqStatusRcvd);
          ASSERT_EQ(this->m_seqStatusOpCode,(U32)testOpCode+1);
          ASSERT_EQ(this->m_seqStatusCmdSeq,testContext);
          ASSERT_EQ(this->m_seqStatusCmdResponse,Fw::COMMAND_INVALID_OPCODE);
      }
  
      void LLCmdDispatcherImplTester::runFailedCommand(void) {
  
          // verify dispatch table is empty
          for (NATIVE_UINT_TYPE entry = 0; entry < FW_NUM_ARRAY_ELEMENTS(this->m_impl.m_entryTable); entry++) {
              ASSERT_TRUE(this->m_impl.m_entryTable[entry].used == false);
          }
  
          // verify sequence tracker table is empty
  
          for (NATIVE_UINT_TYPE entry = 0; entry < FW_NUM_ARRAY_ELEMENTS(this->m_impl.m_sequenceTracker); entry++) {
              ASSERT_TRUE(this->m_impl.m_sequenceTracker[entry].used == false);
          }
          // clear reg events
          this->clearEvents();
          // register built-in commands
          this->m_impl.regCommands();
          // verify registrations
          ASSERT_TRUE(this->m_impl.m_entryTable[0].used);
          ASSERT_EQ(this->m_impl.m_entryTable[0].opcode,LLCmdDispatcherImpl::OPCODE_CMD_NO_OP);
          ASSERT_EQ(this->m_impl.m_entryTable[0].port,1);
  
          ASSERT_TRUE(this->m_impl.m_entryTable[1].used);
          ASSERT_EQ(this->m_impl.m_entryTable[1].opcode,LLCmdDispatcherImpl::OPCODE_CMD_NO_OP_STRING);
          ASSERT_EQ(this->m_impl.m_entryTable[1].port,1);
  
          ASSERT_TRUE(this->m_impl.m_entryTable[2].used);
          ASSERT_EQ(this->m_impl.m_entryTable[2].opcode,LLCmdDispatcherImpl::OPCODE_CMD_TEST_CMD_1);
          ASSERT_EQ(this->m_impl.m_entryTable[2].port,1);
  
          ASSERT_TRUE(this->m_impl.m_entryTable[3].used);
          ASSERT_EQ(this->m_impl.m_entryTable[3].opcode,LLCmdDispatcherImpl::OPCODE_CMD_CLEAR_TRACKING);
          ASSERT_EQ(this->m_impl.m_entryTable[3].port,1);
  
          // verify event
          ASSERT_EVENTS_SIZE(4);
          ASSERT_EVENTS_OpCodeRegistered_SIZE(4);
          ASSERT_EVENTS_OpCodeRegistered(0,LLCmdDispatcherImpl::OPCODE_CMD_NO_OP,1,0);
          ASSERT_EVENTS_OpCodeRegistered(1,LLCmdDispatcherImpl::OPCODE_CMD_NO_OP_STRING,1,1);
          ASSERT_EVENTS_OpCodeRegistered(2,LLCmdDispatcherImpl::OPCODE_CMD_TEST_CMD_1,1,2);
          ASSERT_EVENTS_OpCodeRegistered(3,LLCmdDispatcherImpl::OPCODE_CMD_CLEAR_TRACKING,1,3);
          // register our own command
          FwOpcodeType testOpCode = 0x50;
  
          this->clearEvents();
          this->invoke_to_compCmdReg(0,0x50);
          ASSERT_TRUE(this->m_impl.m_entryTable[4].used);
          ASSERT_EQ(this->m_impl.m_entryTable[4].opcode,testOpCode);
          ASSERT_EQ(this->m_impl.m_entryTable[4].port,0);
  
          // verify registration event
          ASSERT_EVENTS_SIZE(1);
          ASSERT_EVENTS_OpCodeRegistered_SIZE(1);
          ASSERT_EVENTS_OpCodeRegistered(0,(U32)testOpCode,0,4);
  
          U32 currSeq = 0;
  
          // dispatch a test command
          U32 testCmdArg = 100;
          U32 testContext = 13;
          this->clearEvents();
          Fw::ComBuffer buff;
          ASSERT_EQ(buff.serialize(FwPacketDescriptorType(Fw::ComPacket::FW_PACKET_COMMAND)),Fw::FW_SERIALIZE_OK);
          ASSERT_EQ(buff.serialize(testOpCode),Fw::FW_SERIALIZE_OK);
          ASSERT_EQ(buff.serialize(testCmdArg),Fw::FW_SERIALIZE_OK);
  
          this->invoke_to_seqCmdBuff(0,buff,testContext);
  
          // verify dispatch event
          ASSERT_EVENTS_SIZE(1);
          ASSERT_EVENTS_OpCodeDispatched_SIZE(1);
          ASSERT_EVENTS_OpCodeDispatched(0,(U32)testOpCode,0);
  
          // verify sequence table entry
          ASSERT_TRUE(this->m_impl.m_sequenceTracker[0].used);
          ASSERT_EQ(currSeq,this->m_impl.m_sequenceTracker[0].seq);
          ASSERT_EQ(this->m_impl.m_sequenceTracker[0].opCode,testOpCode);
          ASSERT_EQ(this->m_impl.m_sequenceTracker[0].context,testContext);
          ASSERT_EQ(this->m_impl.m_sequenceTracker[0].callerPort,(NATIVE_INT_TYPE)0);
  
          // verify command received
          ASSERT_TRUE(this->m_cmdSendRcvd);
          ASSERT_EQ(this->m_cmdSendOpCode,testOpCode);
          ASSERT_EQ(currSeq,this->m_cmdSendCmdSeq);
          // check argument
          U32 checkVal;
          ASSERT_EQ(this->m_cmdSendArgs.deserialize(checkVal),Fw::FW_SERIALIZE_OK);
          ASSERT_EQ(checkVal,testCmdArg);
  
          this->clearEvents();
          this->m_seqStatusRcvd = false;
          // perform command response
          this->invoke_to_compCmdStat(0,testOpCode,this->m_cmdSendCmdSeq,Fw::COMMAND_EXECUTION_ERROR);
  
          // Check dispatch table
          ASSERT_FALSE(this->m_impl.m_sequenceTracker[0].used);
          ASSERT_EQ(currSeq,this->m_impl.m_sequenceTracker[0].seq);
          ASSERT_EQ(this->m_impl.m_sequenceTracker[0].opCode,testOpCode);
          ASSERT_EQ(this->m_impl.m_sequenceTracker[0].callerPort,(NATIVE_INT_TYPE)0);
  
          // Verify completed event
          ASSERT_EVENTS_SIZE(1);
          ASSERT_EVENTS_OpCodeError_SIZE(1);
          ASSERT_EVENTS_OpCodeError(0,(U32)testOpCode, LLCmdDispatcherComponentBase::ERR_EXECUTION_ERROR);
  
          // Verify status passed back to port
          ASSERT_TRUE(this->m_seqStatusRcvd);
          ASSERT_EQ(this->m_seqStatusCmdSeq,testContext);
          ASSERT_EQ(this->m_seqStatusCmdResponse,Fw::COMMAND_EXECUTION_ERROR);
  
          // dispatch a test command
          currSeq++;
          this->clearEvents();
          buff.resetSer();
          ASSERT_EQ(buff.serialize(FwPacketDescriptorType(Fw::ComPacket::FW_PACKET_COMMAND)),Fw::FW_SERIALIZE_OK);
          ASSERT_EQ(buff.serialize(testOpCode),Fw::FW_SERIALIZE_OK);
          ASSERT_EQ(buff.serialize(testCmdArg),Fw::FW_SERIALIZE_OK);
  
          this->invoke_to_seqCmdBuff(0,buff,testContext);
  
          // verify dispatch event
          ASSERT_EVENTS_SIZE(1);
          ASSERT_EVENTS_OpCodeDispatched_SIZE(1);
          ASSERT_EVENTS_OpCodeDispatched(0,(U32)testOpCode,0);
  
          // verify sequence table entry
          ASSERT_TRUE(this->m_impl.m_sequenceTracker[0].used);
          ASSERT_EQ(currSeq,this->m_impl.m_sequenceTracker[0].seq);
          ASSERT_EQ(this->m_impl.m_sequenceTracker[0].opCode,testOpCode);
          ASSERT_EQ(this->m_impl.m_sequenceTracker[0].context,testContext);
          ASSERT_EQ(this->m_impl.m_sequenceTracker[0].callerPort,(NATIVE_INT_TYPE)0);
  
          // verify command received
          ASSERT_TRUE(this->m_cmdSendRcvd);
          ASSERT_EQ(this->m_cmdSendOpCode,testOpCode);
          ASSERT_EQ(currSeq,this->m_cmdSendCmdSeq);
          // check argument
          ASSERT_EQ(this->m_cmdSendArgs.deserialize(checkVal),Fw::FW_SERIALIZE_OK);
          ASSERT_EQ(checkVal,testCmdArg);
  
          this->clearEvents();
          this->m_seqStatusRcvd = false;
          // perform command response
          this->invoke_to_compCmdStat(0,testOpCode,this->m_cmdSendCmdSeq,Fw::COMMAND_INVALID_OPCODE);
  
          // Check dispatch table
          ASSERT_FALSE(this->m_impl.m_sequenceTracker[0].used);
          ASSERT_EQ(currSeq,this->m_impl.m_sequenceTracker[0].seq);
          ASSERT_EQ(this->m_impl.m_sequenceTracker[0].opCode,testOpCode);
          ASSERT_EQ(this->m_impl.m_sequenceTracker[0].callerPort,(NATIVE_INT_TYPE)0);
  
          // Verify completed event
          ASSERT_EVENTS_SIZE(1);
          ASSERT_EVENTS_OpCodeError_SIZE(1);
          ASSERT_EVENTS_OpCodeError(0,(U32)testOpCode,LLCmdDispatcherComponentBase::ERR_INVALID_OPCODE);
  
          // Verify status passed back to port
          ASSERT_TRUE(this->m_seqStatusRcvd);
          ASSERT_EQ(this->m_seqStatusOpCode,(U32)testOpCode);
          ASSERT_EQ(testContext,this->m_seqStatusCmdSeq);
          ASSERT_EQ(this->m_seqStatusCmdResponse,Fw::COMMAND_INVALID_OPCODE);
  
          currSeq++;
          // dispatch a test command
          this->clearEvents();
          buff.resetSer();
          ASSERT_EQ(buff.serialize(FwPacketDescriptorType(Fw::ComPacket::FW_PACKET_COMMAND)),Fw::FW_SERIALIZE_OK);
          ASSERT_EQ(buff.serialize(testOpCode),Fw::FW_SERIALIZE_OK);
          ASSERT_EQ(buff.serialize(testCmdArg),Fw::FW_SERIALIZE_OK);
  
          this->invoke_to_seqCmdBuff(0,buff,testContext);
  
          // verify dispatch event
          ASSERT_EVENTS_SIZE(1);
          ASSERT_EVENTS_OpCodeDispatched_SIZE(1);
          ASSERT_EVENTS_OpCodeDispatched(0,(U32)testOpCode,0);
  
          // verify sequence table entry
          ASSERT_TRUE(this->m_impl.m_sequenceTracker[0].used);
          ASSERT_EQ(currSeq,this->m_impl.m_sequenceTracker[0].seq);
          ASSERT_EQ(this->m_impl.m_sequenceTracker[0].opCode,testOpCode);
          ASSERT_EQ(this->m_impl.m_sequenceTracker[0].callerPort,(NATIVE_INT_TYPE)0);
          ASSERT_EQ(this->m_impl.m_sequenceTracker[0].context,testContext);
  
          // verify command received
          ASSERT_TRUE(this->m_cmdSendRcvd);
          ASSERT_EQ(this->m_cmdSendOpCode,testOpCode);
          ASSERT_EQ(currSeq,this->m_cmdSendCmdSeq);
          // check argument
          ASSERT_EQ(this->m_cmdSendArgs.deserialize(checkVal),Fw::FW_SERIALIZE_OK);
          ASSERT_EQ(checkVal,testCmdArg);
  
          this->clearEvents();
          this->m_seqStatusRcvd = false;
          // perform command response
          this->invoke_to_compCmdStat(0,testOpCode,this->m_cmdSendCmdSeq,Fw::COMMAND_VALIDATION_ERROR);
          
  
          // Check dispatch table
          ASSERT_FALSE(this->m_impl.m_sequenceTracker[0].used);
          ASSERT_EQ(currSeq,this->m_impl.m_sequenceTracker[0].seq);
          ASSERT_EQ(this->m_impl.m_sequenceTracker[0].opCode,testOpCode);
          ASSERT_EQ(this->m_impl.m_sequenceTracker[0].callerPort,(NATIVE_INT_TYPE)0);
  
          // Verify completed event
          ASSERT_EVENTS_SIZE(1);
          ASSERT_EVENTS_OpCodeError_SIZE(1);
          ASSERT_EVENTS_OpCodeError(0,(U32)testOpCode,LLCmdDispatcherComponentBase::ERR_VALIDATION_ERROR);
  
          // Verify status passed back to port
          ASSERT_TRUE(this->m_seqStatusRcvd);
          ASSERT_EQ(this->m_seqStatusOpCode,(U32)testOpCode);
          ASSERT_EQ(testContext,this->m_seqStatusCmdSeq);
          ASSERT_EQ(this->m_seqStatusCmdResponse,Fw::COMMAND_VALIDATION_ERROR);
      }
  
      void LLCmdDispatcherImplTester::runInvalidCommand(void) {
          // verify dispatch table is empty
          for (NATIVE_UINT_TYPE entry = 0; entry < FW_NUM_ARRAY_ELEMENTS(this->m_impl.m_entryTable); entry++) {
              ASSERT_TRUE(this->m_impl.m_entryTable[entry].used == false);
          }
  
          // verify sequence tracker table is empty
  
          for (NATIVE_UINT_TYPE entry = 0; entry < FW_NUM_ARRAY_ELEMENTS(this->m_impl.m_sequenceTracker); entry++) {
              ASSERT_TRUE(this->m_impl.m_sequenceTracker[entry].used == false);
          }
          // clear reg events
          this->clearEvents();
  
          // dispatch a flawed command
          U32 testCmdArg = 100;
          U32 testContext = 13;
          FwOpcodeType testOpCode = 0x50;
          this->clearEvents();
          Fw::ComBuffer buff;
          ASSERT_EQ(buff.serialize((U32)100),Fw::FW_SERIALIZE_OK);
          ASSERT_EQ(buff.serialize(testOpCode),Fw::FW_SERIALIZE_OK);
          ASSERT_EQ(buff.serialize(testCmdArg),Fw::FW_SERIALIZE_OK);
  
          this->invoke_to_seqCmdBuff(0,buff,testContext);
          
  
          // verify dispatch event
          ASSERT_EVENTS_SIZE(1);
          ASSERT_EVENTS_MalformedCommand_SIZE(1);
          ASSERT_EVENTS_MalformedCommand(0,LLCmdDispatcherComponentBase::ERR_TYPE_MISMATCH);
  
      }
  
      void LLCmdDispatcherImplTester::runOverflowCommands(void) {
  
          // verify dispatch table is empty
          for (NATIVE_UINT_TYPE entry = 0; entry < FW_NUM_ARRAY_ELEMENTS(this->m_impl.m_entryTable); entry++) {
              ASSERT_TRUE(this->m_impl.m_entryTable[entry].used == false);
          }
  
          // verify sequence tracker table is empty
  
          for (NATIVE_UINT_TYPE entry = 0; entry < FW_NUM_ARRAY_ELEMENTS(this->m_impl.m_sequenceTracker); entry++) {
              ASSERT_TRUE(this->m_impl.m_sequenceTracker[entry].used == false);
          }
          // clear reg events
          this->clearEvents();
          // register built-in commands
          this->m_impl.regCommands();
          // verify registrations
          ASSERT_TRUE(this->m_impl.m_entryTable[0].used);
          ASSERT_EQ(this->m_impl.m_entryTable[0].opcode,LLCmdDispatcherImpl::OPCODE_CMD_NO_OP);
          ASSERT_EQ(this->m_impl.m_entryTable[0].port,1);
  
          ASSERT_TRUE(this->m_impl.m_entryTable[1].used);
          ASSERT_EQ(this->m_impl.m_entryTable[1].opcode,LLCmdDispatcherImpl::OPCODE_CMD_NO_OP_STRING);
          ASSERT_EQ(this->m_impl.m_entryTable[1].port,1);
  
          ASSERT_TRUE(this->m_impl.m_entryTable[2].used);
          ASSERT_EQ(this->m_impl.m_entryTable[2].opcode,LLCmdDispatcherImpl::OPCODE_CMD_TEST_CMD_1);
          ASSERT_EQ(this->m_impl.m_entryTable[2].port,1);
  
          ASSERT_TRUE(this->m_impl.m_entryTable[3].used);
          ASSERT_EQ(this->m_impl.m_entryTable[3].opcode,LLCmdDispatcherImpl::OPCODE_CMD_CLEAR_TRACKING);
          ASSERT_EQ(this->m_impl.m_entryTable[3].port,1);
  
          // verify event
          ASSERT_EVENTS_SIZE(4);
          ASSERT_EVENTS_OpCodeRegistered_SIZE(4);
          ASSERT_EVENTS_OpCodeRegistered(0,LLCmdDispatcherImpl::OPCODE_CMD_NO_OP,1,0);
          ASSERT_EVENTS_OpCodeRegistered(1,LLCmdDispatcherImpl::OPCODE_CMD_NO_OP_STRING,1,1);
          ASSERT_EVENTS_OpCodeRegistered(2,LLCmdDispatcherImpl::OPCODE_CMD_TEST_CMD_1,1,2);
          ASSERT_EVENTS_OpCodeRegistered(3,LLCmdDispatcherImpl::OPCODE_CMD_CLEAR_TRACKING,1,3);
  
          // register our own command
          FwOpcodeType testOpCode = 0x50;
  
          this->clearEvents();
          this->invoke_to_compCmdReg(0,0x50);
          ASSERT_TRUE(this->m_impl.m_entryTable[4].used);
          ASSERT_EQ(this->m_impl.m_entryTable[4].opcode,testOpCode);
          ASSERT_EQ(this->m_impl.m_entryTable[4].port,0);
  
          // verify registration event
          ASSERT_EVENTS_SIZE(1);
          ASSERT_EVENTS_OpCodeRegistered_SIZE(1);
          ASSERT_EVENTS_OpCodeRegistered(0,(U32)testOpCode,0,4);
  
          for (NATIVE_UINT_TYPE disp = 0; disp < LLCMD_DISPATCHER_SEQUENCER_TABLE_SIZE + 1; disp++) {
              // dispatch a test command
              U32 testCmdArg = 100;
              U32 testContext = 13;
              this->clearEvents();
              Fw::ComBuffer buff;
              ASSERT_EQ(buff.serialize(FwPacketDescriptorType(Fw::ComPacket::FW_PACKET_COMMAND)),Fw::FW_SERIALIZE_OK);
              ASSERT_EQ(buff.serialize(testOpCode),Fw::FW_SERIALIZE_OK);
              ASSERT_EQ(buff.serialize(testCmdArg),Fw::FW_SERIALIZE_OK);
  
              this->invoke_to_seqCmdBuff(0,buff,testContext);
              
  
              if (disp < LLCMD_DISPATCHER_SEQUENCER_TABLE_SIZE) {
                  // verify dispatch event
                  ASSERT_EVENTS_SIZE(1);
                  ASSERT_EVENTS_OpCodeDispatched_SIZE(1);
                  ASSERT_EVENTS_OpCodeDispatched(0,(U32)testOpCode,0);
  
                  // verify sequence table entry
                  ASSERT_TRUE(this->m_impl.m_sequenceTracker[disp].used);
                  ASSERT_EQ(disp,this->m_impl.m_sequenceTracker[disp].seq);
                  ASSERT_EQ(this->m_impl.m_sequenceTracker[disp].opCode,testOpCode);
                  ASSERT_EQ(this->m_impl.m_sequenceTracker[disp].context,testContext);
                  ASSERT_EQ(this->m_impl.m_sequenceTracker[disp].callerPort,(NATIVE_INT_TYPE)0);
  
                  // verify command received
                  ASSERT_TRUE(this->m_cmdSendRcvd);
                  ASSERT_EQ(this->m_cmdSendOpCode,testOpCode);
                  ASSERT_EQ(disp,this->m_cmdSendCmdSeq);
                  // check argument
                  U32 checkVal;
                  ASSERT_EQ(this->m_cmdSendArgs.deserialize(checkVal),Fw::FW_SERIALIZE_OK);
                  ASSERT_EQ(checkVal,testCmdArg);
              } else {
                  // verify failed to find slot
                  ASSERT_EVENTS_SIZE(1);
                  ASSERT_EVENTS_TooManyCommands_SIZE(1);
              }
          }
  
      }
  
      void LLCmdDispatcherImplTester::runClearCommandTracking(void) {
  
          // verify dispatch table is empty
          for (NATIVE_UINT_TYPE entry = 0; entry < FW_NUM_ARRAY_ELEMENTS(this->m_impl.m_entryTable); entry++) {
              ASSERT_TRUE(this->m_impl.m_entryTable[entry].used == false);
          }
  
          // verify sequence tracker table is empty
          for (NATIVE_UINT_TYPE entry = 0; entry < FW_NUM_ARRAY_ELEMENTS(this->m_impl.m_sequenceTracker); entry++) {
              ASSERT_TRUE(this->m_impl.m_sequenceTracker[entry].used == false);
          }
          // clear reg events
          this->clearEvents();
          // register built-in commands
          this->m_impl.regCommands();
          // verify registrations
          ASSERT_TRUE(this->m_impl.m_entryTable[0].used);
          ASSERT_EQ(this->m_impl.m_entryTable[0].opcode,LLCmdDispatcherImpl::OPCODE_CMD_NO_OP);
          ASSERT_EQ(this->m_impl.m_entryTable[0].port,1);
  
          ASSERT_TRUE(this->m_impl.m_entryTable[1].used);
          ASSERT_EQ(this->m_impl.m_entryTable[1].opcode,LLCmdDispatcherImpl::OPCODE_CMD_NO_OP_STRING);
          ASSERT_EQ(this->m_impl.m_entryTable[1].port,1);
  
          ASSERT_TRUE(this->m_impl.m_entryTable[2].used);
          ASSERT_EQ(this->m_impl.m_entryTable[2].opcode,LLCmdDispatcherImpl::OPCODE_CMD_TEST_CMD_1);
          ASSERT_EQ(this->m_impl.m_entryTable[2].port,1);
  
          ASSERT_TRUE(this->m_impl.m_entryTable[3].used);
          ASSERT_EQ(this->m_impl.m_entryTable[3].opcode,LLCmdDispatcherImpl::OPCODE_CMD_CLEAR_TRACKING);
          ASSERT_EQ(this->m_impl.m_entryTable[3].port,1);
  
          // verify event
          ASSERT_EVENTS_SIZE(4);
          ASSERT_EVENTS_OpCodeRegistered_SIZE(4);
          ASSERT_EVENTS_OpCodeRegistered(0,LLCmdDispatcherImpl::OPCODE_CMD_NO_OP,1,0);
          ASSERT_EVENTS_OpCodeRegistered(1,LLCmdDispatcherImpl::OPCODE_CMD_NO_OP_STRING,1,1);
          ASSERT_EVENTS_OpCodeRegistered(2,LLCmdDispatcherImpl::OPCODE_CMD_TEST_CMD_1,1,2);
          ASSERT_EVENTS_OpCodeRegistered(3,LLCmdDispatcherImpl::OPCODE_CMD_CLEAR_TRACKING,1,3);
  
          // register our own command
          FwOpcodeType testOpCode = 0x50;
          U32 testContext = 13;
  
          this->clearEvents();
          this->invoke_to_compCmdReg(0,testOpCode);
          ASSERT_TRUE(this->m_impl.m_entryTable[4].used);
          ASSERT_EQ(this->m_impl.m_entryTable[4].opcode,testOpCode);
          ASSERT_EQ(this->m_impl.m_entryTable[4].port,0);
  
          // verify registration event
          ASSERT_EVENTS_SIZE(1);
          ASSERT_EVENTS_OpCodeRegistered_SIZE(1);
          ASSERT_EVENTS_OpCodeRegistered(0,(U32)testOpCode,0,4);
  
          // dispatch a test command
          U32 testCmdArg = 100;
          this->clearEvents();
          Fw::ComBuffer buff;
          ASSERT_EQ(buff.serialize(FwPacketDescriptorType(Fw::ComPacket::FW_PACKET_COMMAND)),Fw::FW_SERIALIZE_OK);
          ASSERT_EQ(buff.serialize(testOpCode),Fw::FW_SERIALIZE_OK);
          ASSERT_EQ(buff.serialize(testCmdArg),Fw::FW_SERIALIZE_OK);
  
          this->invoke_to_seqCmdBuff(0,buff,testContext);
          
  
          // verify dispatch event
          ASSERT_EVENTS_SIZE(1);
          ASSERT_EVENTS_OpCodeDispatched_SIZE(1);
          ASSERT_EVENTS_OpCodeDispatched(0,(U32)testOpCode,0);
  
          // verify sequence table entry
          ASSERT_TRUE(this->m_impl.m_sequenceTracker[0].used);
          ASSERT_EQ((U32)0,this->m_impl.m_sequenceTracker[0].seq);
          ASSERT_EQ(this->m_impl.m_sequenceTracker[0].opCode,testOpCode);
          ASSERT_EQ(this->m_impl.m_sequenceTracker[0].context,testContext);
          ASSERT_EQ(this->m_impl.m_sequenceTracker[0].callerPort,(NATIVE_INT_TYPE)0);
  
          // verify command received
          ASSERT_TRUE(this->m_cmdSendRcvd);
          ASSERT_EQ(this->m_cmdSendOpCode,testOpCode);
          ASSERT_EQ((U32)0,this->m_cmdSendCmdSeq);
          // check argument
          U32 checkVal;
          ASSERT_EQ(this->m_cmdSendArgs.deserialize(checkVal),Fw::FW_SERIALIZE_OK);
          ASSERT_EQ(checkVal,testCmdArg);
          this->clearEvents();
  
          // dispatch command to clear sequence tracker table
  
          buff.resetSer();
          ASSERT_EQ(buff.serialize(FwPacketDescriptorType(Fw::ComPacket::FW_PACKET_COMMAND)),Fw::FW_SERIALIZE_OK);
          ASSERT_EQ(buff.serialize((FwOpcodeType)LLCmdDispatcherImpl::OPCODE_CMD_CLEAR_TRACKING),Fw::FW_SERIALIZE_OK);
  
          this->invoke_to_seqCmdBuff(0,buff,testContext);
          // send buffer to command dispatcher
          
  
          // verify dispatch event
          ASSERT_EVENTS_SIZE(1);
          ASSERT_EVENTS_OpCodeDispatched_SIZE(1);
          ASSERT_EVENTS_OpCodeDispatched(0,LLCmdDispatcherImpl::OPCODE_CMD_CLEAR_TRACKING,1);
  
          // dispatch command from dispatcher to command handler
          
          // verify tracking table empty
          for (NATIVE_UINT_TYPE entry = 0; entry < FW_NUM_ARRAY_ELEMENTS(this->m_impl.m_sequenceTracker); entry++) {
              ASSERT_TRUE(this->m_impl.m_sequenceTracker[entry].used == false);
          }
  
          clearHistory();
          // send command complete
          this->invoke_to_compCmdStat(0,testOpCode,this->m_cmdSendCmdSeq,Fw::COMMAND_OK);
          
  
          // verify no status returned
          ASSERT_CMD_RESPONSE_SIZE(0);
  
      }
  
  
  } /* namespace LLProc */
  