#include <gtest/gtest.h>

#include <stdint.h>
#include <scl/string.h>

extern "C" {
  #include "pa_tz_api.h"
}

static const uint32_t kIncorrectProcessNameLength = 1050;

typedef enum {
  kMaximalSizeNameRule = 1024
} UtilsLimits;

typedef struct {
  char *process_names;
  uint32_t names_number;
  uint32_t name_size;
} PaRulesInternal;

class PaTzRulesTest : public ::testing::Test {
protected:
  virtual void SetUp() {
    mRules = PaTzRulesCreate();
  }

  virtual void TearDown() {
    PaTzRulesDestroy(mRules);
  }

  PaTzRules mRules;
};

TEST_F(PaTzRulesTest, PaTzRulesAddProcessName) {
  PaTzResult res = PaTzRulesAddProcessName(mRules, "/system/bin/secure_storage");
  ASSERT_EQ(PA_TZ_SUCCESS, res);
}

TEST_F(PaTzRulesTest, PaTzRulesAddProcessName_RulesIsNULL_Failed) {
  PaTzResult res = PaTzRulesAddProcessName(NULL, "/system/bin/secure_storage");
  ASSERT_EQ(PA_TZ_GENERAL_ERROR, res);
}

TEST_F(PaTzRulesTest, PaTzRulesAddManyProcessName_Failed) {
  PaTzResult res;
  for (uint32_t number = 0; number < kMaximalNameNumbers; number++) {
    res = PaTzRulesAddProcessName(mRules, "/system/bin/secure_storage");
    ASSERT_EQ(PA_TZ_SUCCESS, res);
  }

  // Add 11th name but allowed not more than 10
  res = PaTzRulesAddProcessName(mRules, "/system/bin/secure_storage");
  ASSERT_EQ(PA_TZ_AF_APPNAME_IS_INCORRECT, res);
}

TEST_F(PaTzRulesTest, PaTzRulesAddHugeProcessName_Failed) {
  static char huge_process_name[kIncorrectProcessNameLength] = "";
  for (int i = 0; i < kIncorrectProcessNameLength; i++) {
    huge_process_name[i] = 'x';
  }

  PaTzResult res = PaTzRulesAddProcessName(mRules, huge_process_name);
  ASSERT_EQ(PA_TZ_AF_APPNAME_IS_INCORRECT, res);
}

TEST_F(PaTzRulesTest, PaTzRulesAddProcessName_ParseResult_Success) {
  PaTzResult res;
  uint32_t number = 0;
  char process_name[kMaximalSizeNameRule];
  for (number = 0; number < kMaximalNameNumbers; number++) {
    res = PaTzRulesAddProcessName(mRules, "/system/bin/secure_storage" + number);
    ASSERT_EQ(PA_TZ_SUCCESS, res);
  }

  number = 0;

  PaRulesInternal *rules_internal = (PaRulesInternal *)mRules;
  uint32_t names_size = 0;
  for (unsigned i = 0; i < kMaximalNameNumbers; ++i) {
    scl_bool result = scl_strlen(rules_internal->process_names + names_size,
        kMaximalSizeNameRule, (scl_size_t *)&rules_internal->name_size);
    ASSERT_TRUE(result);
    if (!rules_internal->name_size) {
      break;
    }

    result = scl_strcpy(process_name, kMaximalSizeNameRule,
                        rules_internal->process_names + names_size);
    ASSERT_TRUE(result);

    ASSERT_STREQ("/system/bin/secure_storage" + number, process_name);

    names_size += rules_internal->name_size + 1;
    number++;
  }

  ASSERT_EQ(kMaximalNameNumbers, number) <<
      "Name quantity after parsing is not coincided";
}

TEST_F(PaTzRulesTest, PaTzRulesAddMemoryRange) {
  PaTzMemoryRange memRange = {0, 0, PA_MEMORY_PHYS};
  PaTzResult res = PaTzRulesAddMemoryRange(mRules, &memRange);
  ASSERT_EQ(PA_TZ_SUCCESS, res);
}
