/**
 * Copyright (c) 2021 OceanBase
 * OceanBase CE is licensed under Mulan PubL v2.
 * You can use this software according to the terms and conditions of the Mulan PubL v2.
 * You may obtain a copy of Mulan PubL v2 at:
 *          http://license.coscl.org.cn/MulanPubL-2.0
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PubL v2 for more details.
 */

#include <gtest/gtest.h>
#include "lib/allocator/ob_malloc.h"
#include "lib/utility/utility.h"
#include "lib/number/ob_number_v2.h"

using namespace oceanbase::common;
using namespace std;

TEST(utility, load_file_to_string)
{
  const char* path = NULL;
  CharArena alloc;
  ObString str;

  ASSERT_NE(OB_SUCCESS, load_file_to_string(path, alloc, str));
  ASSERT_EQ(OB_SUCCESS, load_file_to_string(__FILE__, alloc, str));
  ASSERT_EQ(0, str.ptr()[str.length()]);
}

TEST(utility, get_ethernet_speed)
{
  int64_t speed = 0;
  ASSERT_NE(OB_SUCCESS, get_ethernet_speed(NULL, speed));

  ASSERT_EQ(OB_SUCCESS, get_ethernet_speed("bond0", speed));
  ASSERT_GE(speed, 1 << 20);
  _OB_LOG(INFO, "speed %ld", speed);
}

TEST(utility, wild_compare)
{
  const bool STR_IS_NOT_PATTERN = false;
  const bool STR_IS_PATTERN = true;
  //----wild one test----
  const int NUM = 10;
  char str[NUM];
  char str_ne[NUM];
  char str_wild_one[NUM];
  // char str_ne[NUM];
  snprintf(str, NUM, "0123456789");
  snprintf(str_ne, NUM, "0213456789");
  snprintf(str_wild_one, NUM, "01234567_9");

  // arguments with 'char *' type
  // str: "012345678", str_ne: "021345678", str_wild_one: "01234567_"
  ASSERT_EQ(0, wild_compare(str, str_wild_one, STR_IS_NOT_PATTERN));
  ASSERT_NE(0, wild_compare(str_ne, str_wild_one, STR_IS_NOT_PATTERN));

  str[NUM - 1] = '9';
  str_wild_one[NUM - 1] = '9';
  str_ne[NUM - 1] = '0';
  ObString ob_str(NUM, str);
  ObString ob_str_wild(NUM, str_wild_one);
  ObString ob_str_ne(NUM, str_ne);
  // arguments with 'ObString' type
  // ob_str: "0123456789", ob_str_ne: "0213456789" ob_str_wild: "01234567_9"
  ASSERT_EQ(0, wild_compare(ob_str, ob_str_wild, STR_IS_NOT_PATTERN));
  ASSERT_NE(0, wild_compare(ob_str_ne, ob_str_wild, STR_IS_NOT_PATTERN));

  //----wild many test----
  const int MANY_STR_NUM = 6;
  char str_wild_many[6];
  snprintf(str_wild_many, MANY_STR_NUM, "012%%89");
  str[NUM - 1] = '\0';
  str_ne[NUM - 1] = '\0';
  // arguments with 'char *' type
  // str: "012345678", str_ne: "021345678" str_wild_many: "012%8"
  ASSERT_EQ(0, wild_compare(str, str_wild_many, STR_IS_NOT_PATTERN));
  ASSERT_NE(0, wild_compare(str_ne, str_wild_many, STR_IS_NOT_PATTERN));

  str[NUM - 1] = '9';
  str_ne[NUM - 1] = '9';
  str_wild_many[MANY_STR_NUM - 1] = '9';
  // arguments with 'ObString' type
  // ob_str: "0123456789", ob_str_ne:"0213456789" ob_str_wild: "012%89"
  ob_str.assign_ptr(str, NUM);
  ob_str_wild.assign_ptr(str_wild_many, MANY_STR_NUM);
  ob_str_ne.assign_ptr(str_ne, NUM);
  ASSERT_EQ(0, wild_compare(ob_str, ob_str_wild, STR_IS_NOT_PATTERN));
  ASSERT_NE(0, wild_compare(ob_str_ne, ob_str_wild, STR_IS_NOT_PATTERN));

  //----wild one test. Str is pattern.----
  snprintf(str, NUM, "01234567%%");
  snprintf(str_wild_many, MANY_STR_NUM, "0123%%");
  snprintf(str_ne, NUM, "012%%34567");
  // arguments with 'char *' type
  // str: "01234567%", str_ne: "012%34567", str_wild_many: "0123%"
  ASSERT_EQ(0, wild_compare(str, str_wild_many, STR_IS_PATTERN));
  ASSERT_NE(0, wild_compare(str_ne, str_wild_many, STR_IS_PATTERN));
  str[NUM - 1] = '9';
  str_wild_many[MANY_STR_NUM - 1] = '9';
  ob_str.assign_ptr(str, NUM);
  ob_str_wild.assign_ptr(str_wild_many, MANY_STR_NUM);
  ob_str_ne.assign_ptr(str_ne, NUM);
  // arguments with 'ObString' type
  // ob_str: "01234567%9", ob_str_ne: "012%345679", ob_str_wild: "0123%9"
  ASSERT_EQ(0, wild_compare(ob_str, ob_str_wild, STR_IS_PATTERN));
  ASSERT_NE(0, wild_compare(ob_str_ne, ob_str_wild, STR_IS_PATTERN));

  snprintf(str, NUM, "012345%%%%");
  snprintf(str_wild_many, MANY_STR_NUM, "012%%%%");
  ASSERT_EQ(0, wild_compare(str, str_wild_many, STR_IS_PATTERN));
  ob_str.assign_ptr(str, (int32_t)strlen(str));
  ob_str_wild.assign_ptr(str_wild_many, (int32_t)strlen(str_wild_many));
  ASSERT_EQ(0, wild_compare(ob_str, ob_str_wild, STR_IS_PATTERN));
}

TEST(utility, get_sort)
{
  uint64_t sort_value = 128;
  sort_value = (sort_value << 8) + 1;
  sort_value = (sort_value << 8) + 5;
  sort_value = (sort_value << 8) + 9;
  ASSERT_EQ(sort_value, get_sort(4, "user", "%user", "user%", "useruser%"));

  sort_value = 5;
  sort_value = (sort_value << 8) + 0;
  sort_value = (sort_value << 8) + 128;
  ASSERT_EQ(sort_value, get_sort(3, "user%", "", "user"));

  sort_value = 5;
  sort_value = (sort_value << 8) + 0;
  ASSERT_EQ(sort_value, get_sort(2, "user_", ""));
  sort_value = 0;
  ASSERT_EQ(sort_value, get_sort(1, ""));

  const int NUM = 10;
  char str[NUM] = "123456%89";
  str[NUM - 1] = '0';
  ObString ob_str(NUM, str);
  sort_value = 7;
  ASSERT_EQ(sort_value, get_sort(ob_str));

  snprintf(str, NUM, "_12345");
  ob_str.assign_ptr(str, 6);
  sort_value = 1;
  ASSERT_EQ(sort_value, get_sort(ob_str));
}

TEST(utility, ltoa10)
{
  char sp_buff[35];
  char ltoa_buff[OB_LTOA10_CHAR_LEN];
  int64_t check_value = INT64_MIN;
  ltoa10(check_value, ltoa_buff, true);
  snprintf(sp_buff, sizeof(sp_buff), "%ld", check_value);
  ASSERT_EQ(strcasecmp(ltoa_buff, sp_buff), 0);
  check_value = INT64_MAX;
  ltoa10(check_value, ltoa_buff, true);
  snprintf(sp_buff, sizeof(sp_buff), "%ld", check_value);
  ASSERT_EQ(strcasecmp(ltoa_buff, sp_buff), 0);
  uint64_t uvalue = UINT64_MAX;
  ltoa10(uvalue, ltoa_buff, false);
  snprintf(sp_buff, sizeof(sp_buff), "%lu", uvalue);
  ASSERT_EQ(strcasecmp(ltoa_buff, sp_buff), 0);
  uvalue = 0;
  ltoa10(uvalue, ltoa_buff, false);
  snprintf(sp_buff, sizeof(sp_buff), "%lu", uvalue);
  ASSERT_EQ(strcasecmp(ltoa_buff, sp_buff), 0);
  srand((int)time(NULL));
  for (int64_t idx = 0; idx < 2000; ++idx) {
    check_value = rand();
    ltoa10(check_value, ltoa_buff, true);
    snprintf(sp_buff, sizeof(sp_buff), "%ld", check_value);
    ASSERT_EQ(strcasecmp(ltoa_buff, sp_buff), 0);
  }
  for (int64_t idx = 0; idx < 2000; ++idx) {
    check_value = rand() - INT32_MAX;
    ltoa10(check_value, ltoa_buff, true);
    snprintf(sp_buff, sizeof(sp_buff), "%ld", check_value);
    ASSERT_EQ(strcasecmp(ltoa_buff, sp_buff), 0);
  }
  for (int64_t idx = 0; idx < 2000; ++idx) {
    check_value = rand() - INT64_MAX;
    ltoa10(check_value, ltoa_buff, true);
    snprintf(sp_buff, sizeof(sp_buff), "%ld", check_value);
    ASSERT_EQ(strcasecmp(ltoa_buff, sp_buff), 0);
  }
  for (int64_t idx = 0; idx < 2000; ++idx) {
    uvalue = rand();
    ltoa10(uvalue, ltoa_buff, false);
    snprintf(sp_buff, sizeof(sp_buff), "%lu", uvalue);
    ASSERT_EQ(strcasecmp(ltoa_buff, sp_buff), 0);
  }
  for (int64_t idx = 0; idx < 2000; ++idx) {
    uvalue = rand() + INT32_MAX;
    ltoa10(uvalue, ltoa_buff, false);
    snprintf(sp_buff, sizeof(sp_buff), "%lu", uvalue);
    ASSERT_EQ(strcasecmp(ltoa_buff, sp_buff), 0);
  }
  for (int64_t idx = 0; idx < 2000; ++idx) {
    uvalue = rand() + INT64_MAX;
    ltoa10(uvalue, ltoa_buff, false);
    snprintf(sp_buff, sizeof(sp_buff), "%lu", uvalue);
    ASSERT_EQ(strcasecmp(ltoa_buff, sp_buff), 0);
  }
}

TEST(utility, long_to_str10)
{
  // correct
  char sp_buff[35];
  char str10[OB_LTOA10_CHAR_LEN];
  int64_t check_value = INT64_MIN;
  int64_t length = INT64_MIN;
  long_to_str10(check_value, str10, sizeof(str10), true, length);
  snprintf(sp_buff, sizeof(sp_buff), "%ld", check_value);
  ASSERT_EQ(strcasecmp(str10, sp_buff), 0);
  check_value = INT64_MAX;
  long_to_str10(check_value, str10, sizeof(str10), true, length);
  snprintf(sp_buff, sizeof(sp_buff), "%ld", check_value);
  ASSERT_EQ(strcasecmp(str10, sp_buff), 0);
  ASSERT_EQ(length, strlen(sp_buff));
  uint64_t uvalue = UINT64_MAX;
  long_to_str10(uvalue, str10, sizeof(str10), false, length);
  snprintf(sp_buff, sizeof(sp_buff), "%lu", uvalue);
  ASSERT_EQ(strcasecmp(str10, sp_buff), 0);
  ASSERT_EQ(length, strlen(sp_buff));
  uvalue = 0;
  long_to_str10(uvalue, str10, sizeof(str10), false, length);
  snprintf(sp_buff, sizeof(sp_buff), "%lu", uvalue);
  ASSERT_EQ(strcasecmp(str10, sp_buff), 0);
  ASSERT_EQ(length, strlen(sp_buff));
  srand((int)time(NULL));
  for (int64_t idx = 0; idx < 2000; ++idx) {
    check_value = rand();
    long_to_str10(check_value, str10, sizeof(str10), true, length);
    snprintf(sp_buff, sizeof(sp_buff), "%ld", check_value);
    ASSERT_EQ(strcasecmp(str10, sp_buff), 0);
    ASSERT_EQ(length, strlen(sp_buff));
  }
  for (int64_t idx = 0; idx < 2000; ++idx) {
    check_value = rand() - INT32_MAX;
    long_to_str10(check_value, str10, sizeof(str10), true, length);
    snprintf(sp_buff, sizeof(sp_buff), "%ld", check_value);
    ASSERT_EQ(strcasecmp(str10, sp_buff), 0);
    ASSERT_EQ(length, strlen(sp_buff));
  }
  for (int64_t idx = 0; idx < 2000; ++idx) {
    check_value = rand() - INT64_MAX;
    long_to_str10(check_value, str10, sizeof(str10), true, length);
    snprintf(sp_buff, sizeof(sp_buff), "%ld", check_value);
    ASSERT_EQ(strcasecmp(str10, sp_buff), 0);
    ASSERT_EQ(length, strlen(sp_buff));
  }
  for (int64_t idx = 0; idx < 2000; ++idx) {
    uvalue = rand();
    long_to_str10(uvalue, str10, sizeof(str10), false, length);
    snprintf(sp_buff, sizeof(sp_buff), "%lu", uvalue);
    ASSERT_EQ(strcasecmp(str10, sp_buff), 0);
    ASSERT_EQ(length, strlen(sp_buff));
  }
  for (int64_t idx = 0; idx < 2000; ++idx) {
    uvalue = rand() + INT32_MAX;
    long_to_str10(uvalue, str10, sizeof(str10), false, length);
    snprintf(sp_buff, sizeof(sp_buff), "%lu", uvalue);
    ASSERT_EQ(strcasecmp(str10, sp_buff), 0);
    ASSERT_EQ(length, strlen(sp_buff));
  }
  for (int64_t idx = 0; idx < 2000; ++idx) {
    uvalue = rand() + INT64_MAX;
    long_to_str10(uvalue, str10, sizeof(str10), false, length);
    snprintf(sp_buff, sizeof(sp_buff), "%lu", uvalue);
    ASSERT_EQ(strcasecmp(str10, sp_buff), 0);
    ASSERT_EQ(length, strlen(sp_buff));
  }

  check_value = 3;
  char str10_t1[1];
  ASSERT_EQ(OB_INVALID_ARGUMENT, long_to_str10(check_value, str10_t1, sizeof(str10_t1), true, length));
  char str10_t2[2];
  ASSERT_EQ(OB_SUCCESS, long_to_str10(check_value, str10_t2, sizeof(str10_t2), true, length));
  snprintf(sp_buff, sizeof(sp_buff), "%ld", check_value);
  ASSERT_EQ(length, strlen(sp_buff));
  char str10_t3[3];
  ASSERT_EQ(OB_SUCCESS, long_to_str10(check_value, str10_t3, sizeof(str10_t3), true, length));
  ASSERT_EQ(length, strlen(sp_buff));
  check_value = 345;
  ASSERT_EQ(OB_SIZE_OVERFLOW, long_to_str10(check_value, str10_t3, sizeof(str10_t3), true, length));
  check_value = 3456;
  ASSERT_EQ(OB_SIZE_OVERFLOW, long_to_str10(check_value, str10_t3, sizeof(str10_t3), true, length));
  uvalue = UINT64_MAX;
  char str10_t5[5];
  ASSERT_EQ(OB_SIZE_OVERFLOW, long_to_str10(uvalue, str10_t5, sizeof(str10_t5), false, length));
  uvalue = UINT32_MAX;
  ASSERT_EQ(OB_SIZE_OVERFLOW, long_to_str10(uvalue, str10_t5, sizeof(str10_t5), false, length));
}

void test_max_speed(const int64_t rate, const int64_t total_size, const int64_t buf_size)
{
  COMMON_LOG(INFO, "test_max_speed", K(rate), K(total_size), K(buf_size));
  ASSERT_NE(0, rate);
  ObBandwidthThrottle throttle;
  int64_t cur_buf_size = 0;
  // int64_t avaliable_ts = 0;
  if (total_size * 1000 * 1000 > INT64_MAX) {
    COMMON_LOG(ERROR, "total size is too large", K(total_size));
    FAIL();
  }
  ASSERT_EQ(OB_SUCCESS, throttle.init(rate));

  int64_t start_time = ObTimeUtility::current_time();
  // int64_t sleep_time = 0;
  int64_t expect_time = 0;
  int64_t count = 0;
  int64_t cost_time = 0;
  int64_t speed = 0;
  int64_t sleep_us = 0;
  for (int64_t cur_size = 0; cur_size < total_size; cur_size += cur_buf_size) {
    ++count;
    if (buf_size > 0) {
      cur_buf_size = buf_size;
    } else {
      cur_buf_size = ObRandom::rand(1, 1024);
    }
    ASSERT_EQ(OB_SUCCESS, throttle.limit_and_sleep(cur_buf_size, start_time, INT64_MAX, sleep_us));
  }
  cost_time = ObTimeUtility::current_time() - start_time;
  expect_time = 1000 * 1000 * total_size / rate;
  if (cost_time > 0) {
    speed = total_size * 1000 * 1000 / cost_time;
  }
  int64_t diff = (speed - rate) * 100 / rate;
  COMMON_LOG(INFO,
      "finish check",
      K(cost_time),
      K(expect_time),
      K(total_size),
      K(rate),
      K(buf_size),
      K(count),
      K(speed),
      K(diff));
  if (diff > 0 || diff < -20) {
    COMMON_LOG(WARN,
        "check time",
        K(cost_time),
        K(expect_time),
        K(total_size),
        K(rate),
        K(buf_size),
        K(count),
        K(speed),
        K(diff));
    FAIL();
  }
}

TEST(utility, bandwidth_throttle)
{
  ObBandwidthThrottle throttle;
  ASSERT_EQ(OB_NOT_INIT, throttle.set_rate(1024 * 1024));  // 1m/s
  ASSERT_EQ(OB_SUCCESS, throttle.init(0));
  throttle.destroy();
  ASSERT_EQ(OB_SUCCESS, throttle.init(1024 * 1024));     // 1m/s
  ASSERT_EQ(OB_INIT_TWICE, throttle.init(1024 * 1024));  // 1m/s
  ASSERT_EQ(OB_INVALID_ARGUMENT, throttle.set_rate(-1));
  ASSERT_EQ(OB_SUCCESS, throttle.set_rate(0));
  ASSERT_EQ(OB_SUCCESS, throttle.set_rate(1024 * 1024));  // 1m/s

  test_max_speed(100 * 1024 * 1024, 60 * 1024 * 1024, 2 * 1024 * 1024);
  test_max_speed(1 * 1024, 1 * 1024, 32);
  test_max_speed(512 * 1024 * 1024 * 1024LL, 1024 * 1024 * 1024 * 1024LL, 600 * 1024 * 1024);
  test_max_speed(100 * 1024 * 1024, 60 * 1024 * 1024, -1);
}

TEST(utility, ob_localtime)
{
  struct tm std_tm;
  struct tm ob_tm;

  time_t last_sec = 0;
  struct tm last_tm;
  struct timeval tv;
  (void)gettimeofday(&tv, NULL);

  // check next five year, need 180s
  const int64_t min_time = static_cast<int64_t>(tv.tv_sec);
  const int64_t max_time = min_time + 5 * 365 * 24 * 60 * 60;
  for (int64_t i = min_time; i < max_time; i += 1) {
    ::localtime_r((const time_t*)&i, &std_tm);
    ob_localtime((const time_t*)&i, &ob_tm);

    //    _COMMON_LOG(WARN, "check time, std_tm=%d %d-%d %d:%d:%d, ob_tm=%d %d-%d %d:%d:%d, value=%ld",
    //        std_tm.tm_year, std_tm.tm_mon, std_tm.tm_mday, std_tm.tm_hour, std_tm.tm_min, std_tm.tm_sec,
    //        ob_tm.tm_year, ob_tm.tm_mon, ob_tm.tm_mday, ob_tm.tm_hour, ob_tm.tm_min, ob_tm.tm_sec,
    //        i);

    EXPECT_EQ(std_tm.tm_sec, ob_tm.tm_sec);
    EXPECT_EQ(std_tm.tm_min, ob_tm.tm_min);
    EXPECT_EQ(std_tm.tm_hour, ob_tm.tm_hour);
    EXPECT_EQ(std_tm.tm_mday, ob_tm.tm_mday);
    EXPECT_EQ(std_tm.tm_mon, ob_tm.tm_mon);
    EXPECT_EQ(std_tm.tm_year, ob_tm.tm_year);

    ob_fast_localtime(last_sec, last_tm, (const time_t)i, &std_tm);
    EXPECT_EQ(i, last_sec);
    EXPECT_EQ(std_tm.tm_sec, last_tm.tm_sec);
    EXPECT_EQ(std_tm.tm_min, last_tm.tm_min);
    EXPECT_EQ(std_tm.tm_hour, last_tm.tm_hour);
    EXPECT_EQ(std_tm.tm_mday, last_tm.tm_mday);
    EXPECT_EQ(std_tm.tm_mon, last_tm.tm_mon);
    EXPECT_EQ(std_tm.tm_year, last_tm.tm_year);
  }

  int64_t special_value[18] = {
      825523199,  // 1996.02.28 23.59.59
      825523200,  // 1996.02.29 00.00.00
      825609599,  // 1996.02.29 23.59.59
      825609600,  // 1996.03.01 00.00.00

      951753599,  // 2000.02.28 23.59.59
      951753600,  // 2000.02.29 00.00.00
      951839999,  // 2000.02.29 23.59.59
      951840000,  // 2000.03.01 00.00.00

      4107513599,  // 2100.02.28 23:59:59
      4107513600,  // 2100.03.01 00:00:00
      920217599,   // 1999.02.28 23.59.59
      920217600,   // 1999.03.01 00.00.00

      946655999,  // 1999.12.31 23.59.59
      946656000,  // 2000.01.01 0:0:0

      0,            // 1970.01.01 08:00:00
      -1,           // 1970.01.01 07:59:59
      -2203920344,  // 1900.02.28 23.59.59
      -2203920343   // 1900.03.01 00.00.00
  };

  for (int64_t i = 0; i < 14; ++i) {
    ::localtime_r((const time_t*)(special_value + i), &std_tm);
    ob_localtime((const time_t*)(special_value + i), &ob_tm);

    _COMMON_LOG(WARN,
        "check time, std_tm=%d %d-%d %d:%d:%d, ob_tm=%d %d-%d %d:%d:%d, value=%ld, __time=%ld",
        std_tm.tm_year,
        std_tm.tm_mon,
        std_tm.tm_mday,
        std_tm.tm_hour,
        std_tm.tm_min,
        std_tm.tm_sec,
        ob_tm.tm_year,
        ob_tm.tm_mon,
        ob_tm.tm_mday,
        ob_tm.tm_hour,
        ob_tm.tm_min,
        ob_tm.tm_sec,
        special_value[i],
        __timezone / 60);

    EXPECT_EQ(std_tm.tm_sec, ob_tm.tm_sec);
    EXPECT_EQ(std_tm.tm_min, ob_tm.tm_min);
    EXPECT_EQ(std_tm.tm_hour, ob_tm.tm_hour);
    EXPECT_EQ(std_tm.tm_mday, ob_tm.tm_mday);
    EXPECT_EQ(std_tm.tm_mon, ob_tm.tm_mon);
    EXPECT_EQ(std_tm.tm_year, ob_tm.tm_year);

    ob_fast_localtime(last_sec, last_tm, (const time_t)i, &std_tm);
    EXPECT_EQ(i, last_sec);
    EXPECT_EQ(std_tm.tm_sec, last_tm.tm_sec);
    EXPECT_EQ(std_tm.tm_min, last_tm.tm_min);
    EXPECT_EQ(std_tm.tm_hour, last_tm.tm_hour);
    EXPECT_EQ(std_tm.tm_mday, last_tm.tm_mday);
    EXPECT_EQ(std_tm.tm_mon, last_tm.tm_mon);
    EXPECT_EQ(std_tm.tm_year, last_tm.tm_year);
  }

  ob_tm.tm_sec = 0;
  ob_tm.tm_min = 0;
  ob_tm.tm_hour = 0;
  ob_tm.tm_mday = 0;
  ob_tm.tm_mon = 0;
  ob_tm.tm_year = 0;

  for (int64_t i = 14; i < 18; ++i) {
    ob_localtime((const time_t*)(special_value + i), &ob_tm);

    EXPECT_EQ(0, ob_tm.tm_sec);
    EXPECT_EQ(0, ob_tm.tm_min);
    EXPECT_EQ(0, ob_tm.tm_hour);
    EXPECT_EQ(0, ob_tm.tm_mday);
    EXPECT_EQ(0, ob_tm.tm_mon);
    EXPECT_EQ(0, ob_tm.tm_year);
  }
}

TEST(utility, ob_localtime_performance)
{
  struct tm ob_tm;

  const int64_t MAX_COUNT = 10000000;
  const int64_t WEIGHT = 1000000;
  struct timeval time_begin, time_end;

  gettimeofday(&time_begin, NULL);
  for (int64_t i = 1; i < MAX_COUNT; i += 1) {
    ::localtime_r((const time_t*)&i, &ob_tm);
  }
  gettimeofday(&time_end, NULL);
  OB_LOG(INFO,
      "performance average(ns)",
      "localtime_r",
      (WEIGHT * (time_end.tv_sec - time_begin.tv_sec) + time_end.tv_usec - time_begin.tv_usec) / (MAX_COUNT / 1000),
      "cost_sec",
      time_end.tv_sec - time_begin.tv_sec,
      "cost_us",
      time_end.tv_usec - time_begin.tv_usec);

  gettimeofday(&time_begin, NULL);
  for (int64_t i = 1; i < MAX_COUNT; i += 1) {
    ob_localtime((const time_t*)&i, &ob_tm);
  }
  gettimeofday(&time_end, NULL);
  OB_LOG(INFO,
      "performance average(ns)",
      "ob_localtime",
      (WEIGHT * (time_end.tv_sec - time_begin.tv_sec) + time_end.tv_usec - time_begin.tv_usec) / (MAX_COUNT / 1000),
      "cost_sec",
      time_end.tv_sec - time_begin.tv_sec,
      "cost_us",
      time_end.tv_usec - time_begin.tv_usec);
}

struct TestCheckStruct {
  TestCheckStruct() : is_ob_localtime_(false), stop_(false)
  {}
  bool is_ob_localtime_;
  volatile bool stop_;
};

void* ob_localtime_pthread_op_func(void* arg)
{
  TestCheckStruct* tmp = static_cast<TestCheckStruct*>(arg);
  struct tm ob_tm;
  //  OB_LOG(INFO, "thread begin");
  if (tmp->is_ob_localtime_) {
    for (int64_t i = 0; !tmp->stop_; i += 1) {
      ob_localtime((const time_t*)&i, &ob_tm);
    }
  } else {
    for (int64_t i = 0; !tmp->stop_; i += 1) {
      ::localtime_r((const time_t*)&i, &ob_tm);
    }
  }
  //  OB_LOG(INFO, "thread end");
  return NULL;
}

TEST(utility, multi_thread_sys)
{
  const int64_t max_thread_count[] = {10, 100};
  for (int64_t j = 0; j < 2; ++j) {
    vector<pthread_t> pid_vector;
    struct TestCheckStruct tmp;
    tmp.is_ob_localtime_ = false;
    for (int64_t i = 0; i < max_thread_count[j]; ++i) {
      pthread_t pid = 0;
      pthread_create(&pid, NULL, ob_localtime_pthread_op_func, &tmp);
      pid_vector.push_back(pid);
    }

    sleep(2);

    OB_LOG(INFO, "after sleep");

    struct tm ob_tm;

    const int64_t MAX_COUNT = 1000000;
    const int64_t WEIGHT = 1000000;
    struct timeval time_begin, time_end;

    gettimeofday(&time_begin, NULL);
    for (int64_t i = 1; i < MAX_COUNT; i += 1) {
      ::localtime_r((const time_t*)&i, &ob_tm);
    }
    gettimeofday(&time_end, NULL);
    OB_LOG(INFO,
        "performance average(ns)",
        "localtime_r",
        (WEIGHT * (time_end.tv_sec - time_begin.tv_sec) + time_end.tv_usec - time_begin.tv_usec) / (MAX_COUNT / 1000),
        "thread_count",
        max_thread_count[j]);

    tmp.stop_ = true;
    for (int64_t i = 0; i < max_thread_count[j]; ++i) {
      pthread_join(pid_vector[i], NULL);
    }
  }
}

TEST(utility, multi_thread_ob)
{
  const int64_t max_thread_count[] = {10, 100};
  for (int64_t j = 0; j < 2; ++j) {
    vector<pthread_t> pid_vector;
    struct TestCheckStruct tmp;
    tmp.is_ob_localtime_ = true;
    for (int64_t i = 0; i < max_thread_count[j]; ++i) {
      pthread_t pid = 0;
      pthread_create(&pid, NULL, ob_localtime_pthread_op_func, &tmp);
      pid_vector.push_back(pid);
    }

    sleep(2);

    OB_LOG(INFO, "after sleep");

    struct tm ob_tm;

    const int64_t MAX_COUNT = 1000000;
    const int64_t WEIGHT = 1000000;
    struct timeval time_begin, time_end;

    gettimeofday(&time_begin, NULL);
    for (int64_t i = 1; i < MAX_COUNT; i += 1) {
      ob_localtime((const time_t*)&i, &ob_tm);
    }
    gettimeofday(&time_end, NULL);
    OB_LOG(INFO,
        "performance average(ns)",
        "ob_localtime",
        (WEIGHT * (time_end.tv_sec - time_begin.tv_sec) + time_end.tv_usec - time_begin.tv_usec) / (MAX_COUNT / 1000),
        "thread_count",
        max_thread_count[j]);

    tmp.stop_ = true;
    for (int64_t i = 0; i < max_thread_count[j]; ++i) {
      pthread_join(pid_vector[i], NULL);
    }
  }
}

TEST(utility, ob_atoll_overflow)
{
  int ret = OB_SUCCESS;
  const char* digital_num = "99999999999999999999999999";
  int64_t val = 0;
  ret = ob_atoll(digital_num, val);
  ASSERT_EQ(OB_SIZE_OVERFLOW, ret);
  ret = OB_SUCCESS;
}

TEST(utility, ob_strtoull_overflow)
{
  int ret = OB_SUCCESS;
  const char* digital_num = "99999999999999999999999999";
  char* endptr = NULL;
  uint64_t val = 0;
  ret = ob_strtoull(digital_num, endptr, val);
  ASSERT_EQ(OB_SIZE_OVERFLOW, ret);
}

int main(int argc, char** argv)
{
  oceanbase::common::ObLogger::get_logger().set_log_level("INFO");
  testing::InitGoogleTest(&argc, argv);
  return RUN_ALL_TESTS();
}
