#include <gtest/gtest.h>
#include <stdint.h>

extern "C" {
  #include "PaDriverCommand.h"
  #include "PaDriverCommandResponse.h"
  #include "PaDriverCommandAuthenticate.h"
  #include "PaDriverCommandAuthenticateResponse.h"
}

class PaTzSerializeTest : public ::testing::Test {
protected:
  virtual void SetUp() { }

  virtual void TearDown() { }
};

enum {
  kSizeOfData = 4096
};

TEST_F(PaTzSerializeTest, PaTzDriverCommandAuthenticate_EncodeDecode) {
  uint8_t data_encode[kSizeOfData];

  const char kHandler[] = "handler";
  const int kResultExecuteCommand = 0;
  const char kTestProcessName[] = "test_pa";

  PaDriverCommandAuthenticate_t encode_command_authenticate = {0};

  OCTET_STRING_fromBuf(&encode_command_authenticate.handler, kHandler, sizeof(kHandler));

  EXPECT_TRUE(encode_command_authenticate.processName.buf == NULL);
  EXPECT_EQ(encode_command_authenticate.processName.size, 0);
  OCTET_STRING_fromString(&encode_command_authenticate.processName, kTestProcessName);
  ASSERT_TRUE(encode_command_authenticate.processName.buf != NULL);
  ASSERT_TRUE(encode_command_authenticate.processName.size > 0);
  EXPECT_STREQ((const char*)encode_command_authenticate.processName.buf, kTestProcessName);

  // Encode the command type as DER(BER)
  asn_enc_rval_t result_encode = der_encode_to_buffer(
      &asn_DEF_PaDriverCommandAuthenticate,
      &encode_command_authenticate,
      data_encode,
      kSizeOfData);

  ASSERT_TRUE(-1 != result_encode.encoded);

  // Decode the command type as DER(BER)
  PaDriverCommandAuthenticate_t *decode_command_authenticate = NULL;
  asn_dec_rval_t result_decode = ber_decode(
      0,
      &asn_DEF_PaDriverCommandAuthenticate,
      (void**) &decode_command_authenticate,
      data_encode,
      kSizeOfData);

  ASSERT_TRUE(RC_OK == result_decode.code);
  ASSERT_TRUE(NULL != decode_command_authenticate);

  EXPECT_TRUE(decode_command_authenticate->handler.size > 0);
  EXPECT_STREQ((const char*)decode_command_authenticate->handler.buf, kHandler);

  EXPECT_TRUE(decode_command_authenticate->processName.size > 0);
  EXPECT_STREQ((const char*)decode_command_authenticate->processName.buf, kTestProcessName);

  ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_PaDriverCommandAuthenticate, &encode_command_authenticate);
  ASN_STRUCT_FREE(asn_DEF_PaDriverCommandAuthenticate, decode_command_authenticate);
}

TEST_F(PaTzSerializeTest, PaTzDriverCommandAuthenticateResponse_EncodeDecode) {
  uint8_t data_encode[kSizeOfData];

  const int kResultExecuteCommand = 5;
  const char kTestProcessId[] = "test_pa_id";

  PaDriverCommandAuthenticateResponse_t encode_authenticate_response = {0};

  OCTET_STRING_fromBuf(&encode_authenticate_response.processInfo, kTestProcessId, sizeof(kTestProcessId));
  ASSERT_TRUE(encode_authenticate_response.processInfo.buf != NULL);
  ASSERT_TRUE(encode_authenticate_response.processInfo.size > 0);
  EXPECT_STREQ((const char*)encode_authenticate_response.processInfo.buf, kTestProcessId);

  encode_authenticate_response.result = kResultExecuteCommand;

  // Encode the command type as DER(BER)
  asn_enc_rval_t result_encode = der_encode_to_buffer(
      &asn_DEF_PaDriverCommandAuthenticateResponse,
      &encode_authenticate_response,
      data_encode,
      kSizeOfData);

  ASSERT_TRUE(-1 != result_encode.encoded);

  // Decode the command type as DER(BER)
  PaDriverCommandAuthenticateResponse_t *decode_authenticate_response = NULL;
  asn_dec_rval_t result_decode = ber_decode(
      0,
      &asn_DEF_PaDriverCommandAuthenticateResponse,
      (void**) &decode_authenticate_response,
      data_encode,
      kSizeOfData);

  ASSERT_TRUE(RC_OK == result_decode.code);
  ASSERT_TRUE(NULL != decode_authenticate_response);

  EXPECT_TRUE(decode_authenticate_response->processInfo.size > 0);
  EXPECT_STREQ((const char*)decode_authenticate_response->processInfo.buf, kTestProcessId);

  EXPECT_TRUE(decode_authenticate_response->result == kResultExecuteCommand);

  ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_PaDriverCommandAuthenticateResponse, &encode_authenticate_response);
  ASN_STRUCT_FREE(asn_DEF_PaDriverCommandAuthenticateResponse, decode_authenticate_response);
}

TEST_F(PaTzSerializeTest, PaTzDriverCommandEmpty_EncodeDecode) {
  uint8_t data_encode[kSizeOfData];

  PaDriverCommand_t encode_command;

  encode_command.present = PaDriverCommand_PR_NOTHING;

  // Encode the command type as DER(BER)
  asn_enc_rval_t result_encode = der_encode_to_buffer(
      &asn_DEF_PaDriverCommand,
      &encode_command,
      data_encode,
      kSizeOfData);

  ASSERT_TRUE(-1 == result_encode.encoded);
}

TEST_F(PaTzSerializeTest, PaTzDriverCommand_EncodeDecode) {
  uint8_t data_encode[kSizeOfData];

  PaDriverCommand_t encode_command = {PaDriverCommand_PR_NOTHING};

  const char kHandler[] = "handler";
  const char kTestProcessName[] = "test_pa";

  PaDriverCommandAuthenticate_t encode_command_authenticate = {0};

  OCTET_STRING_fromBuf(&encode_command_authenticate.handler, kHandler, sizeof(kHandler));
  OCTET_STRING_fromString(&encode_command_authenticate.processName, kTestProcessName);

  encode_command.choice.authenticateCommand = encode_command_authenticate;
  encode_command.present = PaDriverCommand_PR_authenticateCommand;

  // Encode the command type as DER(BER)
  asn_enc_rval_t result_encode = der_encode_to_buffer(
      &asn_DEF_PaDriverCommand,
      &encode_command,
      data_encode,
      kSizeOfData);

  ASSERT_TRUE(-1 != result_encode.encoded);

  // Decode the command type as DER(BER)
  PaDriverCommand_t *decode_command = NULL;
  asn_dec_rval_t result_decode = ber_decode(
      0,
      &asn_DEF_PaDriverCommand,
      (void**) &decode_command,
      data_encode,
      kSizeOfData);

  ASSERT_TRUE(RC_OK == result_decode.code);
  ASSERT_TRUE(NULL != decode_command);

  ASSERT_TRUE(decode_command->present == PaDriverCommand_PR_authenticateCommand);

  EXPECT_TRUE(decode_command->choice.authenticateCommand.handler.size > 0);
  EXPECT_STREQ((const char*)decode_command->choice.authenticateCommand.handler.buf, kHandler);

  EXPECT_TRUE(decode_command->choice.authenticateCommand.processName.size > 0);
  EXPECT_STREQ((const char*)decode_command->choice.authenticateCommand.processName.buf, kTestProcessName);

  ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_PaDriverCommand, &encode_command);
  ASN_STRUCT_FREE(asn_DEF_PaDriverCommand, decode_command);
}

TEST_F(PaTzSerializeTest, PaTzDriverCommandResponseResult_EncodeDecode) {
  uint8_t data_encode[kSizeOfData];

  const long kResult = 5;

  PaDriverCommandResponse_t encode_command_response = {
      PaDriverCommandResponse_PR_NOTHING};

  encode_command_response.present = PaDriverCommandResponse_PR_result;
  encode_command_response.choice.result = kResult;

  // Encode the command type as DER(BER)
  asn_enc_rval_t result_encode = der_encode_to_buffer(
      &asn_DEF_PaDriverCommandResponse,
      &encode_command_response,
      data_encode,
      kSizeOfData);

  ASSERT_TRUE(-1 != result_encode.encoded);

  // Decode the command type as DER(BER)
  PaDriverCommandResponse_t *decode_command_response = NULL;
  asn_dec_rval_t result_decode = ber_decode(
      0,
      &asn_DEF_PaDriverCommandResponse,
      (void**) &decode_command_response,
      data_encode,
      kSizeOfData);

  ASSERT_TRUE(RC_OK == result_decode.code);
  ASSERT_TRUE(NULL != decode_command_response);

  ASSERT_TRUE(decode_command_response->present == PaDriverCommandResponse_PR_result);
  ASSERT_TRUE(decode_command_response->choice.result == kResult);


  ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_PaDriverCommandResponse, &encode_command_response);
  ASN_STRUCT_FREE(asn_DEF_PaDriverCommandResponse, decode_command_response);
}

TEST_F(PaTzSerializeTest, PaTzDriverCommandResponseEmpty_EncodeDecode) {
  uint8_t data_encode[kSizeOfData];

  PaDriverCommandResponse_t encode_command_response;

  encode_command_response.present = PaDriverCommandResponse_PR_NOTHING;

  // Encode the command type as DER(BER)
  asn_enc_rval_t result_encode = der_encode_to_buffer(
      &asn_DEF_PaDriverCommandResponse,
      &encode_command_response,
      data_encode,
      kSizeOfData);

  ASSERT_TRUE(-1 == result_encode.encoded);
}

TEST_F(PaTzSerializeTest, PaTzDriverCommandResponseAuthenticate_EncodeDecode) {
  uint8_t data_encode[kSizeOfData];

  const long kResult = 5;
  const char kTestProcessId[] = "sample_pa_id";

  PaDriverCommandResponse_t encode_command_response = {PaDriverCommandResponse_PR_NOTHING};

  encode_command_response.present = PaDriverCommandResponse_PR_authenticateResponse;
  encode_command_response.choice.authenticateResponse.result = kResult;
  OCTET_STRING_fromString(&encode_command_response.choice.authenticateResponse.processInfo, kTestProcessId);

  // Encode the command type as DER(BER)
  asn_enc_rval_t result_encode = der_encode_to_buffer(
      &asn_DEF_PaDriverCommandResponse,
      &encode_command_response,
      data_encode,
      kSizeOfData);

  ASSERT_TRUE(-1 != result_encode.encoded);

  // Decode the command type as DER(BER)
  PaDriverCommandResponse_t *decode_command_response = NULL;
  asn_dec_rval_t result_decode = ber_decode(
      0,
      &asn_DEF_PaDriverCommandResponse,
      (void**) &decode_command_response,
      data_encode,
      kSizeOfData);

  ASSERT_TRUE(RC_OK == result_decode.code);
  ASSERT_TRUE(NULL != decode_command_response);

  ASSERT_TRUE(decode_command_response->present == PaDriverCommandResponse_PR_authenticateResponse);
  ASSERT_TRUE(decode_command_response->choice.authenticateResponse.result == kResult);

  ASSERT_TRUE(decode_command_response->choice.authenticateResponse.processInfo.size > 0);
  ASSERT_STREQ((char *)decode_command_response->choice.authenticateResponse.processInfo.buf, kTestProcessId);

  ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_PaDriverCommandResponse, &encode_command_response);
  ASN_STRUCT_FREE(asn_DEF_PaDriverCommandResponse, decode_command_response);
}
