/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2021-2024. All rights reserved.
 * Description: function test
 */
#include <string>
#include <vector>
#include <chrono>
#include <thread>
#include "gtest/gtest.h"
#include "expression/expressions.h"
#include "codegen/functions/stringfunctions.h"
#include "codegen/functions/mathfunctions.h"
#include "codegen/functions/murmur3_hash.h"
#include "codegen/functions/xxhash64_hash.h"
#include "codegen/functions/dictionaryfunctions.h"
#include "codegen/functions/udffunctions.h"
#include "codegen/functions/datetime_functions.h"
#include "codegen/functions/json_functions.h"
#include "jni_mock.h"
#include "udf/cplusplus/jni_util.h"
#include "../util/test_util.h"

namespace omniruntime {
using namespace omniruntime::op;
using namespace omniruntime::expressions;
using namespace omniruntime::codegen::function;

void Date32TruncTest(const std::string &input, const std::string &level, const std::string &expect, bool expectIsNull)
{
    int64_t date32Value;
    Date32::StringToDate32(input.c_str(), input.length(), date32Value);
    bool isNull = false;
    int32_t result = DateTruncRetNull(&isNull, static_cast<int32_t>(date32Value), level.c_str(), level.length());
    Date32 resDate(result);
    char resStr[16];
    resDate.ToString(resStr, 16);
    if (!expectIsNull) {
        EXPECT_EQ(expect, std::string(resStr, 10));
    }
    EXPECT_EQ(isNull, expectIsNull);
}

TEST(FunctionTest, ToTimestampLtz) {
  bool retIsNull = false;

  // Normal cases: precision=3 (milliseconds)
  EXPECT_EQ(1625097600000L,
            ToTimestampLtz(1625097600000L, false, 3, false, &retIsNull));
  EXPECT_FALSE(retIsNull);

  // Normal cases: precision=0 (seconds)
  EXPECT_EQ(1625097600000L,
            ToTimestampLtz(1625097600L, false, 0, false, &retIsNull));
  EXPECT_FALSE(retIsNull);

  // Null input cases
  EXPECT_EQ(0L, ToTimestampLtz(1625097600000L, true, 3, false, &retIsNull));
  EXPECT_TRUE(retIsNull);

  EXPECT_EQ(0L, ToTimestampLtz(1625097600000L, false, 3, true, &retIsNull));
  EXPECT_TRUE(retIsNull);

  // Boundary values for precision=3 (milliseconds)
  // MIN_EPOCH_MILLS = -62167219200000LL ('0000-01-01 00:00:00.000 UTC+0')
  EXPECT_EQ(-62167219200000LL,
            ToTimestampLtz(-62167219200000LL, false, 3, false, &retIsNull));
  EXPECT_FALSE(retIsNull);

  // MAX_EPOCH_MILLS = 253402300799999LL ('9999-12-31 23:59:59.999 UTC+0')
  EXPECT_EQ(253402300799999LL,
            ToTimestampLtz(253402300799999LL, false, 3, false, &retIsNull));
  EXPECT_FALSE(retIsNull);

  // Boundary values for precision=0 (seconds)
  // MIN_EPOCH_SECONDS = -62167219200LL ('0000-01-01 00:00:00 UTC+0')
  EXPECT_EQ(-62167219200000LL,
            ToTimestampLtz(-62167219200LL, false, 0, false, &retIsNull));
  EXPECT_FALSE(retIsNull);

  // MAX_EPOCH_SECONDS = 253402300799LL ('9999-12-31 23:59:59 UTC+0')
  EXPECT_EQ(253402300799000LL,
            ToTimestampLtz(253402300799LL, false, 0, false, &retIsNull));
  EXPECT_FALSE(retIsNull);

  // Out of range values should return null
  // Below MIN_EPOCH_MILLS for precision=3
  EXPECT_EQ(0L, ToTimestampLtz(-62167219200001LL, false, 3, false, &retIsNull));
  EXPECT_TRUE(retIsNull);

  // Above MAX_EPOCH_MILLS for precision=3
  EXPECT_EQ(0L, ToTimestampLtz(253402300800000LL, false, 3, false, &retIsNull));
  EXPECT_TRUE(retIsNull);

  // Below MIN_EPOCH_SECONDS for precision=0
  EXPECT_EQ(0L, ToTimestampLtz(-62167219201LL, false, 0, false, &retIsNull));
  EXPECT_TRUE(retIsNull);

  // Above MAX_EPOCH_SECONDS for precision=0
  EXPECT_EQ(0L, ToTimestampLtz(253402300800LL, false, 0, false, &retIsNull));
  EXPECT_TRUE(retIsNull);

  // Unsupported precision values should return null
  EXPECT_EQ(0L, ToTimestampLtz(1625097600000L, false, 1, false, &retIsNull));
  EXPECT_TRUE(retIsNull);

  EXPECT_EQ(0L, ToTimestampLtz(1625097600000L, false, 6, false, &retIsNull));
  EXPECT_TRUE(retIsNull);

  EXPECT_EQ(0L, ToTimestampLtz(1625097600000L, false, -1, false, &retIsNull));
  EXPECT_TRUE(retIsNull);

  // Zero value test
  EXPECT_EQ(0L, ToTimestampLtz(0L, false, 3, false, &retIsNull));
  EXPECT_FALSE(retIsNull);

  EXPECT_EQ(0L, ToTimestampLtz(0L, false, 0, false, &retIsNull));
  EXPECT_FALSE(retIsNull);
}

TEST(FunctionTest, ToTimestampLtzInt) {
  bool retIsNull = false;

  // Normal cases: precision=0 (seconds) - INT can represent epoch seconds
  EXPECT_EQ(1625097600000L,
            ToTimestampLtzInt(1625097600, false, 0, false, &retIsNull));
  EXPECT_FALSE(retIsNull);

  // Null input cases
  EXPECT_EQ(0L, ToTimestampLtzInt(1625097600, true, 0, false, &retIsNull));
  EXPECT_TRUE(retIsNull);

  EXPECT_EQ(0L, ToTimestampLtzInt(1625097600, false, 0, true, &retIsNull));
  EXPECT_TRUE(retIsNull);

  // Boundary values for precision=0 (seconds) within INT range
  // INT_MAX = 2147483647 seconds (approximately 2038-01-19)
  // Note: INT_MAX seconds * 1000 = 2147483647000 milliseconds, which is within valid range
  EXPECT_EQ(2147483647000LL,
            ToTimestampLtzInt(2147483647, false, 0, false, &retIsNull));
  EXPECT_FALSE(retIsNull);

  // INT_MIN = -2147483648 seconds (approximately 1930-03-19)
  // Note: INT_MIN seconds * 1000 = -2147483648000 milliseconds, which is within valid range
  EXPECT_EQ(-2147483648000LL,
            ToTimestampLtzInt(-2147483648, false, 0, false, &retIsNull));
  EXPECT_FALSE(retIsNull);

  // Zero value test for precision=0
  EXPECT_EQ(0L, ToTimestampLtzInt(0, false, 0, false, &retIsNull));
  EXPECT_FALSE(retIsNull);

  // For precision=3 (milliseconds), INT range is very limited
  // INT can only represent timestamps from approximately 1969-12-31 to 1970-01-26
  // Valid INT milliseconds values within the broader timestamp range
  // precision=3 means input is already milliseconds, so it returns directly
  EXPECT_EQ(1LL, ToTimestampLtzInt(1, false, 3, false, &retIsNull));
  EXPECT_FALSE(retIsNull);

  EXPECT_EQ(0LL, ToTimestampLtzInt(0, false, 3, false, &retIsNull));
  EXPECT_FALSE(retIsNull);

  // Unsupported precision values should return null
  EXPECT_EQ(0L, ToTimestampLtzInt(1625097600, false, 1, false, &retIsNull));
  EXPECT_TRUE(retIsNull);

  EXPECT_EQ(0L, ToTimestampLtzInt(1625097600, false, 6, false, &retIsNull));
  EXPECT_TRUE(retIsNull);

  EXPECT_EQ(0L, ToTimestampLtzInt(1625097600, false, -1, false, &retIsNull));
  EXPECT_TRUE(retIsNull);
}
/*
 * context helper tests
 */

static void Md5StringTest(const std::string &input, const std::string &expect)
{
    auto context = new ExecutionContext();
    int64_t contextPtr = reinterpret_cast<int64_t>(context);
    int32_t outLen;
    char *res = Md5Str(contextPtr, input.c_str(), input.size(), false, &outLen);
    EXPECT_EQ(expect, std::string(res, outLen));
    delete context;
}

TEST(FunctionTest, ArenaAllocatorMalloc)
{
    auto execContext = new ExecutionContext();
    int64_t contextptr = reinterpret_cast<int64_t>(execContext);
    char *ptr;
    for (uint64_t i = 1; i <= execContext->GetArena()->TotalBytes() / 256; ++i) {
        ptr = ArenaAllocatorMalloc(contextptr, 256);
        EXPECT_NE(ptr, nullptr);
        // check 256 is allocated each call;
        EXPECT_EQ(256 * i, execContext->GetArena()->TotalBytes() - execContext->GetArena()->AvailBytes());
    }
    delete execContext;
}

TEST(FunctionTest, ArenaAllocatorReset)
{
    auto execContext = new ExecutionContext();
    int64_t contextptr = reinterpret_cast<int64_t>(execContext);

    ArenaAllocatorMalloc(contextptr, 1);
    EXPECT_EQ(execContext->GetArena()->AvailBytes(), execContext->GetArena()->TotalBytes() - 1);
    ArenaAllocatorReset(contextptr);
    EXPECT_EQ(execContext->GetArena()->AvailBytes(), execContext->GetArena()->TotalBytes());

    ArenaAllocatorMalloc(contextptr, execContext->GetArena()->TotalBytes());
    EXPECT_EQ(execContext->GetArena()->AvailBytes(), 0);
    ArenaAllocatorReset(contextptr);
    EXPECT_EQ(execContext->GetArena()->AvailBytes(), execContext->GetArena()->TotalBytes());
    delete execContext;
}

/*
 * Murmur3 hash tests
 */
TEST(FunctionTest, Mm3Int32)
{
    EXPECT_EQ(Mm3Int32(-2147483648, false, 42, false), 723455942);
}

TEST(FunctionTest, Mm3Int64)
{
    EXPECT_EQ(Mm3Int64(static_cast<int64_t>(-2147483648), false, 42, false), -1889108749);
}

TEST(FunctionTest, Mm3Double)
{
    EXPECT_EQ(Mm3Double(123.456, false, 42, false), -39269148);
}

TEST(FunctionTest, Mm3String)
{
    std::string value("hello world");
    EXPECT_EQ(Mm3String(const_cast<char *>(value.c_str()), 11, false, 42, false), -1528836094);
}

TEST(FunctionTest, Md5String)
{
    Md5StringTest("hellow world!", "df6a571d99e454e99be79a258ca3a57d");
    Md5StringTest("123412345892376487612983", "1eac0a767ccdf782870bac35db9af264");
    Md5StringTest("1eac0a767ccdf782870bac35db9af2642345", "582aa488923f89ea825358ffe387f5ae");
    Md5StringTest("", "d41d8cd98f00b204e9800998ecf8427e");
    Md5StringTest("  1", "37705de0752d1027f8fc3b3f390c448d");
    Md5StringTest("1  ", "42609f6cf2cbebfe205241bf26e2e0ef");
    Md5StringTest("1", "c4ca4238a0b923820dcc509a6f75849b");
    Md5StringTest("uwefbuiwef7821ho;o;lhf8923golecg288823pfhl;hsf2893fgOIHDWQIUHFGEWF7823GHQDFddj2",
        "03f2ace2c433c4b743787d96b41ed1b6");
}

static void EmptyToNullTest(const std::string &input)
{
    int32_t outLen;
    const char *res = EmptyToNull(input.c_str(), input.size(), true, &outLen);
    EXPECT_EQ(nullptr, res);
    EXPECT_EQ(outLen, 0);
    res = EmptyToNull(input.c_str(), input.size(), false, &outLen);
    EXPECT_EQ(outLen, 0);
}

static void EmptyToNullNotNullTest(const std::string &input, const std::string &expect)
{
    int32_t outLen;
    const char *res = EmptyToNull(input.c_str(), input.size(), false, &outLen);
    EXPECT_EQ(expect, std::string(res, outLen));
}

TEST(FunctionTest, EmptyToNull)
{
    EmptyToNullNotNullTest("hellow world!", "hellow world!");
    EmptyToNullNotNullTest("123412345892376487612983", "123412345892376487612983");
    EmptyToNullNotNullTest("   ", "   ");
    EmptyToNullTest("");
}

/*
 * XxHash64 hash tests
 */
TEST(FunctionTest, XxH64Short)
{
    EXPECT_EQ(XxH64Int16(1, false, 42, false), -6698625589789238999);
}

TEST(FunctionTest, XxH64Int)
{
    EXPECT_EQ(XxH64Int32(123, false, 42, false), 5513549449271372758);
}

TEST(FunctionTest, XxH64Long)
{
    EXPECT_EQ(XxH64Int64(123L, false, 42, false), -3178482946328430151);
}

TEST(FunctionTest, XxH64Double)
{
    EXPECT_EQ(XxH64Double(123.456, false, 42, false), -6938331816624033461);
}
TEST(FunctionTest, XxH64Boolean)
{
    EXPECT_EQ(XxH64Boolean(true, false, 42, false), -6698625589789238999);
}

TEST(FunctionTest, XxH64String)
{
    EXPECT_EQ(XxH64String("hello world", 11, false, 42, false), 7620854247404556961);
}

TEST(FunctionTest, XxH64Decimal64)
{
    EXPECT_EQ(XxH64Decimal64(430, 7, 0, false, 42, false), -3069041474468904433);
}

TEST(FunctionTest, XxH64Decimal128)
{
    auto value1 = Decimal128(0x80111e8f827844e5, 0x7c03905da66c0000);
    auto value2 = Decimal128(0x00002bd35ae79a49, 0xf98f65489dd30001);
    EXPECT_EQ(XxH64Decimal128(value1.HighBits(), value1.LowBits(), 38, 16, false, 42, false), -216624505269361667);
    EXPECT_EQ(XxH64Decimal128(value2.HighBits(), value2.LowBits(), 38, 16, false, 42, false), 8484287969139273592);
    auto value3 = Decimal128(0x0, 0x29a2241af62bffff);
    auto value4 = Decimal128(0x8000000000000000, 0x0de0b6b3a763ffff);
    EXPECT_EQ(XxH64Decimal128(value3.HighBits(), value3.LowBits(), 38, 18, false, 42, false), -5056633277332826927);
    EXPECT_EQ(XxH64Decimal128(value4.HighBits(), value4.LowBits(), 38, 18, false, 42, false), -6640857474798889004);
}

/*
 * Math functions:
 */
TEST(FunctionTest, Abs)
{
    EXPECT_EQ(10, Abs<int32_t>(10));
    EXPECT_EQ(24, Abs<int32_t>(-24));
    EXPECT_EQ(0, Abs<int32_t>(0));
    EXPECT_EQ(10, Abs<int64_t>(10));
    EXPECT_EQ(24, Abs<int64_t>(-24));
    EXPECT_EQ(0, Abs<int64_t>(0));
}

TEST(FunctionTest, CastInt8ToInt64)
{
    int8_t test1 = 10;
    int8_t test2 = -24;
    int8_t test3 = 0;
    int8_t test4 = std::numeric_limits<int8_t>::min();
    int8_t test5 = std::numeric_limits<int8_t>::max();
    int64_t baseline = 1;
    auto result = CastInt8ToInt64(test1);
    bool isSameType = std::is_same<decltype(baseline), decltype(result)>::value;
    EXPECT_TRUE(isSameType);
    EXPECT_EQ(10, CastInt8ToInt64(result));

    result = CastInt8ToInt64(test2);
    isSameType = std::is_same<decltype(baseline), decltype(result)>::value;
    EXPECT_TRUE(isSameType);
    EXPECT_EQ(-24, result);

    result = CastInt8ToInt64(test3);
    isSameType = std::is_same<decltype(baseline), decltype(result)>::value;
    EXPECT_TRUE(isSameType);
    EXPECT_EQ(0, CastInt8ToInt64(result));

    result = CastInt8ToInt64(test4);
    isSameType = std::is_same<decltype(baseline), decltype(result)>::value;
    EXPECT_TRUE(isSameType);
    EXPECT_EQ(std::numeric_limits<int8_t>::min(), result);

    result = CastInt8ToInt64(test5);
    isSameType = std::is_same<decltype(baseline), decltype(result)>::value;
    EXPECT_TRUE(isSameType);
    EXPECT_EQ(std::numeric_limits<int8_t>::max(), result);
}

TEST(FunctionTest, CastInt8ToInt32)
{
    int8_t test1 = 10;
    int8_t test2 = -24;
    int8_t test3 = 0;
    int8_t test4 = std::numeric_limits<int8_t>::min();
    int8_t test5 = std::numeric_limits<int8_t>::max();
    int32_t baseline = 1;
    auto result = CastInt8ToInt32(test1);
    bool isSameType = std::is_same<decltype(baseline), decltype(result)>::value;
    EXPECT_TRUE(isSameType);
    EXPECT_EQ(10, CastInt8ToInt32(result));

    result = CastInt8ToInt32(test2);
    isSameType = std::is_same<decltype(baseline), decltype(result)>::value;
    EXPECT_TRUE(isSameType);
    EXPECT_EQ(-24, result);

    result = CastInt8ToInt32(test3);
    isSameType = std::is_same<decltype(baseline), decltype(result)>::value;
    EXPECT_TRUE(isSameType);
    EXPECT_EQ(0, CastInt8ToInt32(result));

    result = CastInt8ToInt32(test4);
    isSameType = std::is_same<decltype(baseline), decltype(result)>::value;
    EXPECT_TRUE(isSameType);
    EXPECT_EQ(std::numeric_limits<int8_t>::min(), result);

    result = CastInt8ToInt32(test5);
    isSameType = std::is_same<decltype(baseline), decltype(result)>::value;
    EXPECT_TRUE(isSameType);
    EXPECT_EQ(std::numeric_limits<int8_t>::max(), result);
}

TEST(FunctionTest, CastInt16ToInt64)
{
    int16_t test1 = 10;
    int16_t test2 = -24;
    int16_t test3 = 0;
    int16_t test4 = std::numeric_limits<int16_t>::min();
    int16_t test5 = std::numeric_limits<int16_t>::max();
    int64_t baseline = 1;
    auto result = CastInt16ToInt64(test1);
    bool isSameType = std::is_same<decltype(baseline), decltype(result)>::value;
    EXPECT_TRUE(isSameType);
    EXPECT_EQ(10, CastInt16ToInt64(result));

    result = CastInt16ToInt64(test2);
    isSameType = std::is_same<decltype(baseline), decltype(result)>::value;
    EXPECT_TRUE(isSameType);
    EXPECT_EQ(-24, result);

    result = CastInt16ToInt64(test3);
    isSameType = std::is_same<decltype(baseline), decltype(result)>::value;
    EXPECT_TRUE(isSameType);
    EXPECT_EQ(0, CastInt16ToInt64(result));

    result = CastInt16ToInt64(test4);
    isSameType = std::is_same<decltype(baseline), decltype(result)>::value;
    EXPECT_TRUE(isSameType);
    EXPECT_EQ(std::numeric_limits<int16_t>::min(), result);

    result = CastInt16ToInt64(test5);
    isSameType = std::is_same<decltype(baseline), decltype(result)>::value;
    EXPECT_TRUE(isSameType);
    EXPECT_EQ(std::numeric_limits<int16_t>::max(), result);
}

TEST(FunctionTest, CastInt16ToInt32)
{
    int16_t test1 = 10;
    int16_t test2 = -24;
    int16_t test3 = 0;
    int16_t test4 = std::numeric_limits<int16_t>::min();
    int16_t test5 = std::numeric_limits<int16_t>::max();
    int32_t baseline = 1;
    auto result = CastInt16ToInt32(test1);
    bool isSameType = std::is_same<decltype(baseline), decltype(result)>::value;
    EXPECT_TRUE(isSameType);
    EXPECT_EQ(10, CastInt16ToInt32(result));

    result = CastInt16ToInt32(test2);
    isSameType = std::is_same<decltype(baseline), decltype(result)>::value;
    EXPECT_TRUE(isSameType);
    EXPECT_EQ(-24, result);

    result = CastInt16ToInt32(test3);
    isSameType = std::is_same<decltype(baseline), decltype(result)>::value;
    EXPECT_TRUE(isSameType);
    EXPECT_EQ(0, CastInt16ToInt32(result));

    result = CastInt16ToInt32(test4);
    isSameType = std::is_same<decltype(baseline), decltype(result)>::value;
    EXPECT_TRUE(isSameType);
    EXPECT_EQ(std::numeric_limits<int16_t>::min(), result);

    result = CastInt16ToInt32(test5);
    isSameType = std::is_same<decltype(baseline), decltype(result)>::value;
    EXPECT_TRUE(isSameType);
    EXPECT_EQ(std::numeric_limits<int16_t>::max(), result);
}


TEST(FunctionTest, CastInt16ToDouble)
{
    int16_t test1 = 10;
    int16_t test2 = -24;
    int16_t test3 = 0;
    int16_t test4 = std::numeric_limits<int16_t>::min();
    int16_t test5 = std::numeric_limits<int16_t>::max();
    double baseline = 11.13;
    auto result = CastInt16ToDouble(test1);
    bool isSameType = std::is_same<decltype(baseline), decltype(result)>::value;
    EXPECT_TRUE(isSameType);
    EXPECT_EQ(10.00, result);

    result = CastInt16ToDouble(test2);
    isSameType = std::is_same<decltype(baseline), decltype(result)>::value;
    EXPECT_TRUE(isSameType);
    EXPECT_EQ(-24.00, result);

    result = CastInt16ToDouble(test3);
    isSameType = std::is_same<decltype(baseline), decltype(result)>::value;
    EXPECT_TRUE(isSameType);
    EXPECT_EQ(0.00, result);

    result = CastInt16ToDouble(test4);
    isSameType = std::is_same<decltype(baseline), decltype(result)>::value;
    EXPECT_TRUE(isSameType);
    EXPECT_EQ(static_cast<double>(std::numeric_limits<int16_t>::min()), result);

    result = CastInt16ToDouble(test5);
    isSameType = std::is_same<decltype(baseline), decltype(result)>::value;
    EXPECT_TRUE(isSameType);
    EXPECT_EQ(static_cast<double>(std::numeric_limits<int16_t>::max()), result);
}

TEST(FunctionTest, CastInt8ToDouble)
{
    int8_t test1 = 10;
    int8_t test2 = -24;
    int8_t test3 = 0;
    int8_t test4 = std::numeric_limits<int8_t>::min();
    int8_t test5 = std::numeric_limits<int8_t>::max();
    double baseline = 11.13;
    auto result = CastInt8ToDouble(test1);
    bool isSameType = std::is_same<decltype(baseline), decltype(result)>::value;
    EXPECT_TRUE(isSameType);
    EXPECT_EQ(10.00, result);

    result = CastInt8ToDouble(test2);
    isSameType = std::is_same<decltype(baseline), decltype(result)>::value;
    EXPECT_TRUE(isSameType);
    EXPECT_EQ(-24.00, result);

    result = CastInt8ToDouble(test3);
    isSameType = std::is_same<decltype(baseline), decltype(result)>::value;
    EXPECT_TRUE(isSameType);
    EXPECT_EQ(0.00, result);

    result = CastInt8ToDouble(test4);
    isSameType = std::is_same<decltype(baseline), decltype(result)>::value;
    EXPECT_TRUE(isSameType);
    EXPECT_EQ(static_cast<double>(std::numeric_limits<int8_t>::min()), result);

    result = CastInt8ToDouble(test5);
    isSameType = std::is_same<decltype(baseline), decltype(result)>::value;
    EXPECT_TRUE(isSameType);
    EXPECT_EQ(static_cast<double>(std::numeric_limits<int8_t>::max()), result);
}

TEST(FunctionTest, CastInt32ToInt16)
{
    int32_t test1 = 10;
    int32_t test2 = -24;
    int32_t test3 = 0;
    int16_t baseline = 1;
    auto result = CastInt32ToInt16(test1);
    bool isSameType = std::is_same<decltype(baseline), decltype(result)>::value;
    EXPECT_TRUE(isSameType);
    EXPECT_EQ(10, CastInt32ToInt16(result));

    result = CastInt32ToInt16(test2);
    isSameType = std::is_same<decltype(baseline), decltype(result)>::value;
    EXPECT_TRUE(isSameType);
    EXPECT_EQ(-24, result);

    result = CastInt32ToInt16(test3);
    isSameType = std::is_same<decltype(baseline), decltype(result)>::value;
    EXPECT_TRUE(isSameType);
    EXPECT_EQ(0, CastInt32ToInt16(result));
}

TEST(FunctionTest, CastInt32ToInt8)
{
    int32_t test1 = 10;
    int32_t test2 = -24;
    int32_t test3 = 0;
    int8_t baseline = 1;
    auto result = CastInt32ToInt8(test1);
    bool isSameType = std::is_same<decltype(baseline), decltype(result)>::value;
    EXPECT_TRUE(isSameType);
    EXPECT_EQ(10, CastInt32ToInt8(result));

    result = CastInt32ToInt8(test2);
    isSameType = std::is_same<decltype(baseline), decltype(result)>::value;
    EXPECT_TRUE(isSameType);
    EXPECT_EQ(-24, result);

    result = CastInt32ToInt8(test3);
    isSameType = std::is_same<decltype(baseline), decltype(result)>::value;
    EXPECT_TRUE(isSameType);
    EXPECT_EQ(0, CastInt32ToInt8(result));
}

TEST(FunctionTest, CastDoubleToInt16)
{
    double test1 = 10.00;
    double test2 = -24.00;
    double test3 = 0.0;
    double test4 = 113.1313;
    double test5 = -2000.989;
    int16_t baseline = 1;
    auto result = CastDoubleToInt16HalfUp(test1);
    bool isSameType = std::is_same<decltype(baseline), decltype(result)>::value;
    EXPECT_TRUE(isSameType);
    EXPECT_EQ(10, result);

    result = CastDoubleToInt16HalfUp(test2);
    isSameType = std::is_same<decltype(baseline), decltype(result)>::value;
    EXPECT_TRUE(isSameType);
    EXPECT_EQ(-24, result);

    result = CastDoubleToInt16HalfUp(test3);
    isSameType = std::is_same<decltype(baseline), decltype(result)>::value;
    EXPECT_TRUE(isSameType);
    EXPECT_EQ(0, result);

    result = CastDoubleToInt16HalfUp(test4);
    isSameType = std::is_same<decltype(baseline), decltype(result)>::value;
    EXPECT_TRUE(isSameType);
    EXPECT_EQ(113, result);

    result = CastDoubleToInt16HalfUp(test5);
    isSameType = std::is_same<decltype(baseline), decltype(result)>::value;
    EXPECT_TRUE(isSameType);
    EXPECT_EQ(-2001, result);

    result = CastDoubleToInt16Down(test4);
    isSameType = std::is_same<decltype(baseline), decltype(result)>::value;
    EXPECT_TRUE(isSameType);
    EXPECT_EQ(113, result);
}

TEST(FunctionTest, CastDoubleToInt8)
{
    double test1 = 10.00;
    double test2 = -24.00;
    double test3 = 0.0;
    double test4 = 113.1313;
    int8_t baseline = 1;
    auto result = CastDoubleToInt8HalfUp(test1);
    bool isSameType = std::is_same<decltype(baseline), decltype(result)>::value;
    EXPECT_TRUE(isSameType);
    EXPECT_EQ(10, result);

    result = CastDoubleToInt8HalfUp(test2);
    isSameType = std::is_same<decltype(baseline), decltype(result)>::value;
    EXPECT_TRUE(isSameType);
    EXPECT_EQ(-24, result);

    result = CastDoubleToInt8HalfUp(test3);
    isSameType = std::is_same<decltype(baseline), decltype(result)>::value;
    EXPECT_TRUE(isSameType);
    EXPECT_EQ(0, result);

    result = CastDoubleToInt8HalfUp(test4);
    isSameType = std::is_same<decltype(baseline), decltype(result)>::value;
    EXPECT_TRUE(isSameType);
    EXPECT_EQ(113, result);

    result = CastDoubleToInt8Down(test4);
    isSameType = std::is_same<decltype(baseline), decltype(result)>::value;
    EXPECT_TRUE(isSameType);
    EXPECT_EQ(113, result);
}

TEST(FunctionTest, CastStringToInt16)
{
    auto context = new ExecutionContext();
    auto contextPtr = reinterpret_cast<int64_t>(context);

    std::string s = " 23423 ";
    int16_t result = CastStringToShort(contextPtr, s.c_str(), static_cast<int32_t>(s.size()), false);
    EXPECT_EQ(result, 23423);
    s = "100123";
    result = CastStringToShort(contextPtr, s.c_str(), static_cast<int32_t>(s.size()), false);
    EXPECT_TRUE(context->HasError());
    context->ResetError();
    s = "123.123";
    result = CastStringToShort(contextPtr, s.c_str(), static_cast<int32_t>(s.size()), false);
    EXPECT_EQ(result, 0);
    s = "2147483648";
    result = CastStringToShort(contextPtr, s.c_str(), static_cast<int32_t>(s.size()), false);
    EXPECT_TRUE(context->HasError());
    context->ResetError();
    s = "2a147483648";
    result = CastStringToShort(contextPtr, s.c_str(), static_cast<int32_t>(s.size()), false);
    EXPECT_TRUE(context->HasError());
    context->ResetError();
    s = " -10078 ";
    result = CastStringToShort(contextPtr, s.c_str(), static_cast<int32_t>(s.size()), false);
    EXPECT_EQ(result, -10078);
    EXPECT_FALSE(context->HasError());
    s = "2123123123147483648";
    result = CastStringToShort(contextPtr, s.c_str(), static_cast<int32_t>(s.size()), false);
    EXPECT_TRUE(context->HasError());
    context->ResetError();
    s = "-2123123123147483648";
    result = CastStringToShort(contextPtr, s.c_str(), static_cast<int32_t>(s.size()), false);
    EXPECT_TRUE(context->HasError());
    context->ResetError();
    s = "-2123123123147-483648";
    result = CastStringToShort(contextPtr, s.c_str(), static_cast<int32_t>(s.size()), false);
    EXPECT_TRUE(context->HasError());
    delete context;
}

TEST(FunctionTest, CastStringToInt8)
{
    auto context = new ExecutionContext();
    auto contextPtr = reinterpret_cast<int64_t>(context);

    std::string s = " 127 ";
    int8_t result = CastStringToByte(contextPtr, s.c_str(), static_cast<int32_t>(s.size()), false);
    EXPECT_EQ(result, 127);
    s = "100123";
    result = CastStringToByte(contextPtr, s.c_str(), static_cast<int32_t>(s.size()), false);
    EXPECT_TRUE(context->HasError());
    context->ResetError();
    s = "123.123";
    result = CastStringToByte(contextPtr, s.c_str(), static_cast<int32_t>(s.size()), false);
    EXPECT_EQ(result, 0);
    s = "2147483648";
    result = CastStringToByte(contextPtr, s.c_str(), static_cast<int32_t>(s.size()), false);
    EXPECT_TRUE(context->HasError());
    context->ResetError();
    s = "2a147483648";
    result = CastStringToByte(contextPtr, s.c_str(), static_cast<int32_t>(s.size()), false);
    EXPECT_TRUE(context->HasError());
    context->ResetError();
    s = " -78 ";
    result = CastStringToByte(contextPtr, s.c_str(), static_cast<int32_t>(s.size()), false);
    EXPECT_EQ(result, -78);
    context->ResetError();
    s = "2123123123147483648";
    result = CastStringToByte(contextPtr, s.c_str(), static_cast<int32_t>(s.size()), false);
    EXPECT_TRUE(context->HasError());
    context->ResetError();
    s = "-2123123123147483648";
    result = CastStringToByte(contextPtr, s.c_str(), static_cast<int32_t>(s.size()), false);
    EXPECT_TRUE(context->HasError());
    context->ResetError();
    s = "-2123123123147-483648";
    result = CastStringToByte(contextPtr, s.c_str(), static_cast<int32_t>(s.size()), false);
    EXPECT_TRUE(context->HasError());
    delete context;
}

TEST(FunctionTest, CastInt32ToInt64)
{
    int32_t test1 = 10;
    int32_t test2 = -24;
    int32_t test3 = 0;
    int32_t test4 = std::numeric_limits<int32_t>::min();
    int32_t test5 = std::numeric_limits<int32_t>::max();
    int64_t baseline = 1;
    auto result = CastInt32ToInt64(test1);
    bool isSameType = std::is_same<decltype(baseline), decltype(result)>::value;
    EXPECT_TRUE(isSameType);
    EXPECT_EQ(10, CastInt32ToInt64(result));

    result = CastInt32ToInt64(test2);
    isSameType = std::is_same<decltype(baseline), decltype(result)>::value;
    EXPECT_TRUE(isSameType);
    EXPECT_EQ(-24, result);

    result = CastInt32ToInt64(test3);
    isSameType = std::is_same<decltype(baseline), decltype(result)>::value;
    EXPECT_TRUE(isSameType);
    EXPECT_EQ(0, CastInt32ToInt64(result));

    result = CastInt32ToInt64(test4);
    isSameType = std::is_same<decltype(baseline), decltype(result)>::value;
    EXPECT_TRUE(isSameType);
    EXPECT_EQ(std::numeric_limits<int32_t>::min(), result);

    result = CastInt32ToInt64(test5);
    isSameType = std::is_same<decltype(baseline), decltype(result)>::value;
    EXPECT_TRUE(isSameType);
    EXPECT_EQ(std::numeric_limits<int32_t>::max(), result);
}

TEST(FunctionTest, CastInt64ToInt8)
{
    int64_t test1 = 10;
    int64_t test2 = -24;
    int64_t test3 = 0;
    int64_t test4 = std::numeric_limits<int64_t>::min();
    int64_t test5 = std::numeric_limits<int64_t>::max();
    int8_t baseline = 1;
    auto result = CastInt64ToInt8(test1);
    bool isSameType = std::is_same<decltype(baseline), decltype(result)>::value;
    EXPECT_TRUE(isSameType);
    EXPECT_EQ(10, result);

    result = CastInt64ToInt8(test2);
    isSameType = std::is_same<decltype(baseline), decltype(result)>::value;
    EXPECT_TRUE(isSameType);
    EXPECT_EQ(-24, result);

    result = CastInt64ToInt8(test3);
    isSameType = std::is_same<decltype(baseline), decltype(result)>::value;
    EXPECT_TRUE(isSameType);
    EXPECT_EQ(0, CastInt64ToInt8(result));

    result = CastInt64ToInt8(test4);
    isSameType = std::is_same<decltype(baseline), decltype(result)>::value;
    EXPECT_TRUE(isSameType);
    EXPECT_EQ(0, result);

    result = CastInt64ToInt8(test5);
    isSameType = std::is_same<decltype(baseline), decltype(result)>::value;
    EXPECT_TRUE(isSameType);
    EXPECT_EQ(-1, result);
}

TEST(FunctionTest, CastInt64ToInt16)
{
    int64_t test1 = 10;
    int64_t test2 = -24;
    int64_t test3 = 0;
    int64_t test4 = std::numeric_limits<int64_t>::min();
    int64_t test5 = std::numeric_limits<int64_t>::max();
    int16_t baseline = 1;
    auto result = CastInt64ToInt16(test1);
    bool isSameType = std::is_same<decltype(baseline), decltype(result)>::value;
    EXPECT_TRUE(isSameType);
    EXPECT_EQ(10, result);

    result = CastInt64ToInt16(test2);
    isSameType = std::is_same<decltype(baseline), decltype(result)>::value;
    EXPECT_TRUE(isSameType);
    EXPECT_EQ(-24, result);

    result = CastInt64ToInt16(test3);
    isSameType = std::is_same<decltype(baseline), decltype(result)>::value;
    EXPECT_TRUE(isSameType);
    EXPECT_EQ(0, CastInt64ToInt16(result));

    result = CastInt64ToInt16(test4);
    isSameType = std::is_same<decltype(baseline), decltype(result)>::value;
    EXPECT_TRUE(isSameType);
    EXPECT_EQ(0, result);

    result = CastInt64ToInt16(test5);
    isSameType = std::is_same<decltype(baseline), decltype(result)>::value;
    EXPECT_TRUE(isSameType);
    EXPECT_EQ(-1, result);
}

TEST(FunctionTest, CastInt64ToInt32)
{
    int64_t test1 = 10;
    int64_t test2 = -24;
    int64_t test3 = 0;
    int64_t test4 = std::numeric_limits<int64_t>::min();
    int64_t test5 = std::numeric_limits<int64_t>::max();
    int32_t baseline = 1;
    auto result = CastInt64ToInt32(test1);
    bool isSameType = std::is_same<decltype(baseline), decltype(result)>::value;
    EXPECT_TRUE(isSameType);
    EXPECT_EQ(10, result);

    result = CastInt64ToInt32(test2);
    isSameType = std::is_same<decltype(baseline), decltype(result)>::value;
    EXPECT_TRUE(isSameType);
    EXPECT_EQ(-24, result);

    result = CastInt64ToInt32(test3);
    isSameType = std::is_same<decltype(baseline), decltype(result)>::value;
    EXPECT_TRUE(isSameType);
    EXPECT_EQ(0, CastInt64ToInt32(result));

    result = CastInt64ToInt32(test4);
    isSameType = std::is_same<decltype(baseline), decltype(result)>::value;
    EXPECT_TRUE(isSameType);
    EXPECT_EQ(0, result);

    result = CastInt64ToInt32(test5);
    isSameType = std::is_same<decltype(baseline), decltype(result)>::value;
    EXPECT_TRUE(isSameType);
    EXPECT_EQ(-1, result);
}

TEST(FunctionTest, CastInt32ToDouble)
{
    int32_t test1 = 10;
    int32_t test2 = -24;
    int32_t test3 = 0;
    int32_t test4 = std::numeric_limits<int32_t>::min();
    int32_t test5 = std::numeric_limits<int32_t>::max();
    double baseline = 11.13;
    auto result = CastInt32ToDouble(test1);
    bool isSameType = std::is_same<decltype(baseline), decltype(result)>::value;
    EXPECT_TRUE(isSameType);
    EXPECT_EQ(10.00, result);

    result = CastInt32ToDouble(test2);
    isSameType = std::is_same<decltype(baseline), decltype(result)>::value;
    EXPECT_TRUE(isSameType);
    EXPECT_EQ(-24.00, result);

    result = CastInt32ToDouble(test3);
    isSameType = std::is_same<decltype(baseline), decltype(result)>::value;
    EXPECT_TRUE(isSameType);
    EXPECT_EQ(0.00, result);

    result = CastInt32ToDouble(test4);
    isSameType = std::is_same<decltype(baseline), decltype(result)>::value;
    EXPECT_TRUE(isSameType);
    EXPECT_EQ(static_cast<double>(std::numeric_limits<int32_t>::min()), result);

    result = CastInt32ToDouble(test5);
    isSameType = std::is_same<decltype(baseline), decltype(result)>::value;
    EXPECT_TRUE(isSameType);
    EXPECT_EQ(static_cast<double>(std::numeric_limits<int32_t>::max()), result);
}

TEST(FunctionTest, CastInt64ToDouble)
{
    int64_t test1 = 10;
    int64_t test2 = -24;
    int64_t test3 = 0;
    int64_t test4 = std::numeric_limits<int64_t>::min();
    int64_t test5 = std::numeric_limits<int64_t>::max();
    double baseline = 11.13;
    auto result = CastInt64ToDouble(test1);
    bool isSameType = std::is_same<decltype(baseline), decltype(result)>::value;
    EXPECT_TRUE(isSameType);
    EXPECT_EQ(10.00, result);

    result = CastInt64ToDouble(test2);
    isSameType = std::is_same<decltype(baseline), decltype(result)>::value;
    EXPECT_TRUE(isSameType);
    EXPECT_EQ(-24.00, result);

    result = CastInt64ToDouble(test3);
    isSameType = std::is_same<decltype(baseline), decltype(result)>::value;
    EXPECT_TRUE(isSameType);
    EXPECT_EQ(0.00, result);

    result = CastInt64ToDouble(test4);
    isSameType = std::is_same<decltype(baseline), decltype(result)>::value;
    EXPECT_TRUE(isSameType);
    EXPECT_EQ(static_cast<double>(std::numeric_limits<int64_t>::min()), result);

    result = CastInt64ToDouble(test5);
    isSameType = std::is_same<decltype(baseline), decltype(result)>::value;
    EXPECT_TRUE(isSameType);
    EXPECT_EQ(static_cast<double>(std::numeric_limits<int64_t>::max()), result);
}

TEST(FunctionTest, CastDoubleToInt32)
{
    double test1 = 10.00;
    double test2 = -24.00;
    double test3 = 0.0;
    double test4 = 113.1313;
    double test5 = -2000.989;
    int32_t baseline = 1;
    auto result = CastDoubleToInt32HalfUp(test1);
    bool isSameType = std::is_same<decltype(baseline), decltype(result)>::value;
    EXPECT_TRUE(isSameType);
    EXPECT_EQ(10, result);

    result = CastDoubleToInt32HalfUp(test2);
    isSameType = std::is_same<decltype(baseline), decltype(result)>::value;
    EXPECT_TRUE(isSameType);
    EXPECT_EQ(-24, result);

    result = CastDoubleToInt32HalfUp(test3);
    isSameType = std::is_same<decltype(baseline), decltype(result)>::value;
    EXPECT_TRUE(isSameType);
    EXPECT_EQ(0, result);

    result = CastDoubleToInt32HalfUp(test4);
    isSameType = std::is_same<decltype(baseline), decltype(result)>::value;
    EXPECT_TRUE(isSameType);
    EXPECT_EQ(113, result);

    result = CastDoubleToInt32HalfUp(test5);
    isSameType = std::is_same<decltype(baseline), decltype(result)>::value;
    EXPECT_TRUE(isSameType);
    EXPECT_EQ(-2001, result);
}

TEST(FunctionTest, CastDoubleToInt64)
{
    double test1 = 10.00;
    double test2 = -24.00;
    double test3 = 0.0;
    double test4 = 113.1313;
    double test5 = -2000.989;
    int64_t baseline = 1;
    auto result = CastDoubleToInt64HalfUp(test1);
    bool isSameType = std::is_same<decltype(baseline), decltype(result)>::value;
    EXPECT_TRUE(isSameType);
    EXPECT_EQ(10, result);

    result = CastDoubleToInt64HalfUp(test2);
    isSameType = std::is_same<decltype(baseline), decltype(result)>::value;
    EXPECT_TRUE(isSameType);
    EXPECT_EQ(-24, result);

    result = CastDoubleToInt64HalfUp(test3);
    isSameType = std::is_same<decltype(baseline), decltype(result)>::value;
    EXPECT_TRUE(isSameType);
    EXPECT_EQ(0, result);

    result = CastDoubleToInt64HalfUp(test4);
    isSameType = std::is_same<decltype(baseline), decltype(result)>::value;
    EXPECT_TRUE(isSameType);
    EXPECT_EQ(113, result);

    result = CastDoubleToInt64HalfUp(test5);
    isSameType = std::is_same<decltype(baseline), decltype(result)>::value;
    EXPECT_TRUE(isSameType);
    EXPECT_EQ(-2001, result);
}

bool CompareDoubleBits(double d1, double d2)
{
    uint64_t bits1;
    uint64_t bits2;
    memcpy_s(&bits1, sizeof bits1, &d1, sizeof(double));
    memcpy_s(&bits2, sizeof bits2, &d2, sizeof(double));
    return bits1 == bits2;
}

TEST(FunctionTest, NormalizeNaNAndZero)
{
    EXPECT_FALSE(CompareDoubleBits(-0.0, NormalizeNaNAndZero(-0.0)));
    EXPECT_TRUE(CompareDoubleBits(0.0, NormalizeNaNAndZero(-0.0)));
    EXPECT_TRUE(CompareDoubleBits(0.0, NormalizeNaNAndZero(0.0)));
    uint64_t nanBits = 0xFFF8000000000001L;
    double nanDouble = 0;
    memcpy_s(&nanDouble, sizeof nanDouble, &nanBits, sizeof(nanBits));
    EXPECT_FALSE(CompareDoubleBits(nanDouble, NormalizeNaNAndZero(nanDouble)));
    EXPECT_TRUE(CompareDoubleBits(0.0 / 0.0, NormalizeNaNAndZero(nanDouble)));
    EXPECT_TRUE(CompareDoubleBits(0.0 / 0.0, NormalizeNaNAndZero(0.0 / 0.0)));
    double value = 3.5;
    EXPECT_TRUE(CompareDoubleBits(value, NormalizeNaNAndZero(value)));
}

TEST(FunctionTest, PowerDouble)
{
    for (int i = -10; i <= 10; ++i) {
        double b = i;
        EXPECT_EQ(b * b, PowerDouble(b, 2.0));
    }
}

TEST(FunctionTest, Pmod)
{
    EXPECT_EQ(0, Pmod(4589732, 0));
    int n = 100;
    for (int i = 1; i <= n; ++i) {
        EXPECT_EQ(n % i, Pmod(n, i));
    }
    n = -100;
    for (int i = -1; i >= n; --i) {
        EXPECT_EQ(n - (n / i) * i, Pmod(n, i));
    }
}

TEST(FunctionTest, Add)
{
    auto res1 = AddInt8(3, 5);
    EXPECT_EQ(res1, 8);

    auto res2 = AddInt16(111, 1000);
    EXPECT_EQ(res2, 1111);

    auto res3 = AddInt32(10240, 2);
    EXPECT_EQ(res3, 10242);

    auto res4 = AddInt64(3000000, 5000000);
    EXPECT_EQ(res4, 8000000);
}

TEST(FunctionTest, Sub)
{
    auto res1 = SubtractInt8(3, 5);
    EXPECT_EQ(res1, -2);

    auto res2 = SubtractInt16(111, 1000);
    EXPECT_EQ(res2, -889);

    auto res3 = SubtractInt32(10240, 2);
    EXPECT_EQ(res3, 10238);

    auto res4 = SubtractInt64(3000000, 5000000);
    EXPECT_EQ(res4, -2000000);
}

TEST(FunctionTest, TryAdd)
{
    bool overflowFlag = false;
    EXPECT_EQ(AddInt8RetNull(&overflowFlag, 127, 1), -128);
    EXPECT_TRUE(overflowFlag);

    overflowFlag = false;
    EXPECT_EQ(AddInt16RetNull(&overflowFlag, 32767, 1), -32768);
    EXPECT_TRUE(overflowFlag);

    overflowFlag = false;
    EXPECT_EQ(AddInt32RetNull(&overflowFlag, 2147483647, 1), -2147483648);
    EXPECT_TRUE(overflowFlag);

    overflowFlag = false;
    EXPECT_EQ(AddInt32RetNull(&overflowFlag, -2147483648, -1), 2147483647);
    EXPECT_TRUE(overflowFlag);

    overflowFlag = false;
    EXPECT_EQ(AddInt64RetNull(&overflowFlag, 9223372036854775807L, 1L), -9223372036854775808L);
    EXPECT_TRUE(overflowFlag);

    overflowFlag = false;
    EXPECT_EQ(AddInt64RetNull(&overflowFlag, -9223372036854775808L, -1L), 9223372036854775807L);
    EXPECT_TRUE(overflowFlag);
}

TEST(FunctionTest, TrySubtract)
{
    bool overflowFlag = false;
    EXPECT_EQ(SubtractInt8RetNull(&overflowFlag, 127, -1), -128);
    EXPECT_TRUE(overflowFlag);

    overflowFlag = false;
    EXPECT_EQ(SubtractInt16RetNull(&overflowFlag, 32767, -1), -32768);
    EXPECT_TRUE(overflowFlag);

    overflowFlag = false;
    EXPECT_EQ(SubtractInt32RetNull(&overflowFlag, 2147483647, -1), -2147483648);
    EXPECT_TRUE(overflowFlag);

    overflowFlag = false;
    EXPECT_EQ(SubtractInt32RetNull(&overflowFlag, -2147483648, 1), 2147483647);
    EXPECT_TRUE(overflowFlag);

    overflowFlag = false;
    EXPECT_EQ(SubtractInt64RetNull(&overflowFlag, 9223372036854775807L, -1L), -9223372036854775808L);
    EXPECT_TRUE(overflowFlag);

    overflowFlag = false;
    EXPECT_EQ(SubtractInt64RetNull(&overflowFlag, -9223372036854775808L, 1L), 9223372036854775807L);
    EXPECT_TRUE(overflowFlag);
}

TEST(FunctionTest, TryMultiply)
{
    bool overflowFlag = false;

    EXPECT_EQ(MultiplyInt8RetNull(&overflowFlag, 64, 2), -128);
    EXPECT_TRUE(overflowFlag);

    overflowFlag = false;
    EXPECT_EQ(MultiplyInt16RetNull(&overflowFlag, 16384, 2), -32768);
    EXPECT_TRUE(overflowFlag);

    overflowFlag = false;
    EXPECT_EQ(MultiplyInt32RetNull(&overflowFlag, 1073741824, 2), -2147483648);
    EXPECT_TRUE(overflowFlag);

    overflowFlag = false;
    EXPECT_EQ(MultiplyInt32RetNull(&overflowFlag, -1073741825, 2), 2147483646);
    EXPECT_TRUE(overflowFlag);

    overflowFlag = false;
    EXPECT_EQ(MultiplyInt64RetNull(&overflowFlag, 4611686018427387904L, 2L), -9223372036854775808L);
    EXPECT_TRUE(overflowFlag);

    overflowFlag = false;
    EXPECT_EQ(MultiplyInt64RetNull(&overflowFlag, -4611686018427387905L, 2L), 9223372036854775806L);
    EXPECT_TRUE(overflowFlag);
}

TEST(FunctionTest, Multiply)
{
    auto res1 = MultiplyInt8(3, 5);
    EXPECT_EQ(res1, 15);

    auto res2 = MultiplyInt16(16, 16);
    EXPECT_EQ(res2, 256);
}

TEST(FunctionTest, Divide)
{
    bool nullFlag = false;

    DivideInt8(&nullFlag, 1, 0);
    EXPECT_TRUE(nullFlag);

    nullFlag = false;
    DivideInt16(&nullFlag, 1, 0);
    EXPECT_TRUE(nullFlag);

    nullFlag = false;
    DivideInt32(&nullFlag, 1, 0);
    EXPECT_TRUE(nullFlag);

    nullFlag = false;
    EXPECT_EQ(1, DivideInt32(&nullFlag, 3, 2));
    EXPECT_FALSE(nullFlag);

    nullFlag = false;
    DivideInt64(&nullFlag, 1, 0);
    EXPECT_TRUE(nullFlag);

    nullFlag = false;
    DivideDouble(&nullFlag, 1, 0);
    EXPECT_TRUE(nullFlag);

    nullFlag = false;
    auto res1 = DivideInt8(&nullFlag, 111, 3);
    EXPECT_FALSE(nullFlag);
    EXPECT_EQ(res1, 37);

    nullFlag = false;
    auto res2 = DivideInt16(&nullFlag, 1024, 16);
    EXPECT_FALSE(nullFlag);
    EXPECT_EQ(res2, 64);

    nullFlag = false;
    auto res3 = DivideInt32(&nullFlag, 65536, 4);
    EXPECT_FALSE(nullFlag);
    EXPECT_EQ(res3, 16384);

    nullFlag = false;
    auto res4 = DivideInt64(&nullFlag, 10000000, 1000);
    EXPECT_FALSE(nullFlag);
    EXPECT_EQ(res4, 10000);

    nullFlag = false;
    auto res5 = DivideDouble(&nullFlag, 6.4, 3.2);
    EXPECT_FALSE(nullFlag);
    EXPECT_EQ(res5, 2.0);
}

TEST(FunctionTest, Mod)
{
    bool nullFlag = false;

    ModulusInt8(&nullFlag, 1, 0);
    EXPECT_TRUE(nullFlag);

    nullFlag = false;
    EXPECT_EQ(1, ModulusInt8(&nullFlag, 16, 3));
    EXPECT_FALSE(nullFlag);

    nullFlag = false;
    ModulusInt16(&nullFlag, 1, 0);
    EXPECT_TRUE(nullFlag);

    nullFlag = false;
    EXPECT_EQ(2, ModulusInt16(&nullFlag, 29, 3));
    EXPECT_FALSE(nullFlag);

    nullFlag = false;
    ModulusInt32(&nullFlag, 1, 0);
    EXPECT_TRUE(nullFlag);

    nullFlag = false;
    EXPECT_EQ(2, ModulusInt32(&nullFlag, 5, 3));
    EXPECT_FALSE(nullFlag);

    nullFlag = false;
    ModulusInt64(&nullFlag, 1, 0);
    EXPECT_TRUE(nullFlag);
}

TEST(FunctionTest, LT)
{
    bool ans = LessThanInt8(3, 7);
    EXPECT_TRUE(ans);
    ans = LessThanInt8(11, 1);
    EXPECT_FALSE(ans);

    ans = LessThanInt16(13, 10210);
    EXPECT_TRUE(ans);
    ans = LessThanInt16(12311, 1123);
    EXPECT_FALSE(ans);

    ans = LessThanInt32(123456, 1234567);
    EXPECT_TRUE(ans);
    ans = LessThanInt32(10, 2);
    EXPECT_FALSE(ans);

    ans = LessThanInt64(10, 10000000);
    EXPECT_TRUE(ans);
    ans = LessThanInt64(10000000, 1);
    EXPECT_FALSE(ans);
}

TEST(FunctionTest, GT)
{
    bool ans = GreaterThanInt8(3, 7);
    EXPECT_FALSE(ans);
    ans = GreaterThanInt8(11, 1);
    EXPECT_TRUE(ans);

    ans = GreaterThanInt16(13, 10210);
    EXPECT_FALSE(ans);
    ans = GreaterThanInt16(12311, 1123);
    EXPECT_TRUE(ans);

    ans = GreaterThanInt32(123456, 1234567);
    EXPECT_FALSE(ans);
    ans = GreaterThanInt32(10, 2);
    EXPECT_TRUE(ans);

    ans = GreaterThanInt64(10, 10000000);
    EXPECT_FALSE(ans);
    ans = GreaterThanInt64(10000000, 1);
    EXPECT_TRUE(ans);
}

TEST(FunctionTest, LTE)
{
    bool ans = LessThanEqualInt8(3, 7);
    EXPECT_TRUE(ans);
    ans = LessThanEqualInt8(11, 1);
    EXPECT_FALSE(ans);
    ans = LessThanEqualInt8(100, 100);
    EXPECT_TRUE(ans);

    ans = LessThanEqualInt16(13, 10210);
    EXPECT_TRUE(ans);
    ans = LessThanEqualInt16(12311, 1123);
    EXPECT_FALSE(ans);
    ans = LessThanEqualInt16(8192, 8192);
    EXPECT_TRUE(ans);

    ans = LessThanEqualInt32(123456, 1234567);
    EXPECT_TRUE(ans);
    ans = LessThanEqualInt32(10, 2);
    EXPECT_FALSE(ans);
    ans = LessThanEqualInt32(65536, 65536);
    EXPECT_TRUE(ans);

    ans = LessThanEqualInt64(10, 10000000);
    EXPECT_TRUE(ans);
    ans = LessThanEqualInt64(10000000, 1);
    EXPECT_FALSE(ans);
    ans = LessThanEqualInt64(123456789, 123456789);
    EXPECT_TRUE(ans);
}

TEST(FunctionTest, GTE)
{
    bool ans = GreaterThanEqualInt8(3, 7);
    EXPECT_FALSE(ans);
    ans = GreaterThanEqualInt8(11, 1);
    EXPECT_TRUE(ans);
    ans = GreaterThanEqualInt8(100, 100);
    EXPECT_TRUE(ans);

    ans = GreaterThanEqualInt16(13, 10210);
    EXPECT_FALSE(ans);
    ans = GreaterThanEqualInt16(12311, 1123);
    EXPECT_TRUE(ans);
    ans = GreaterThanEqualInt16(8192, 8192);
    EXPECT_TRUE(ans);

    ans = GreaterThanEqualInt32(123456, 1234567);
    EXPECT_FALSE(ans);
    ans = GreaterThanEqualInt32(10, 2);
    EXPECT_TRUE(ans);
    ans = GreaterThanEqualInt32(65536, 65536);
    EXPECT_TRUE(ans);

    ans = GreaterThanEqualInt64(10, 10000000);
    EXPECT_FALSE(ans);
    ans = GreaterThanEqualInt64(10000000, 1);
    EXPECT_TRUE(ans);
    ans = GreaterThanEqualInt64(123456789, 123456789);
    EXPECT_TRUE(ans);
}

TEST(FunctionTest, EQ)
{
    bool ans;
    ans = EqualInt8(17, 17);
    EXPECT_TRUE(ans);
    ans = EqualInt8(11, 123);
    EXPECT_FALSE(ans);

    ans = EqualInt16(171, 171);
    EXPECT_TRUE(ans);
    ans = EqualInt16(11, 12345);
    EXPECT_FALSE(ans);

    ans = EqualInt32(123456, 123456);
    EXPECT_TRUE(ans);
    ans = EqualInt32(0, 123456);
    EXPECT_FALSE(ans);

    ans = EqualInt64(123456000, 123456000);
    EXPECT_TRUE(ans);
    ans = EqualInt64(11, 12348765);
    EXPECT_FALSE(ans);
}

TEST(FunctionTest, NEQ)
{
    bool ans;
    ans = NotEqualInt8(17, 17);
    EXPECT_FALSE(ans);
    ans = NotEqualInt8(11, 123);
    EXPECT_TRUE(ans);

    ans = NotEqualInt16(171, 171);
    EXPECT_FALSE(ans);
    ans = NotEqualInt16(11, 12345);
    EXPECT_TRUE(ans);

    ans = NotEqualInt32(123456, 123456);
    EXPECT_FALSE(ans);
    ans = NotEqualInt32(0, 123456);
    EXPECT_TRUE(ans);

    ans = NotEqualInt64(123456000, 123456000);
    EXPECT_FALSE(ans);
    ans = NotEqualInt64(11, 12348765);
    EXPECT_TRUE(ans);
}

TEST(FunctionTest, LessThanEqualDouble)
{
    double left = 3.5;
    double right = 3.0;
    EXPECT_FALSE(LessThanEqualDouble(left, right));
}

TEST(FunctionTest, CastNumToString)
{
    auto context = new ExecutionContext();
    int64_t contextptr = reinterpret_cast<int64_t>(context);

    int8_t int_8 = -12;
    int16_t int_16 = 123;
    int32_t int_32 = 456;
    int64_t int_64 = 789;
    double num_double = 3.56;

    int outLen = 0;
    std::string actual;
    const char *result;

    result = CastInt8ToString(contextptr, int_8, false, &outLen);
    actual = std::string(result, outLen);
    EXPECT_EQ("-12", actual);
    EXPECT_EQ(3, outLen);

    result = CastInt16ToString(contextptr, int_16, false, &outLen);
    actual = std::string(result, outLen);
    EXPECT_EQ("123", actual);
    EXPECT_EQ(3, outLen);

    result = CastIntToString(contextptr, int_32, false, &outLen);
    actual = std::string(result, outLen);
    EXPECT_EQ("456", actual);
    EXPECT_EQ(3, outLen);

    result = CastLongToString(contextptr, int_64, false, &outLen);
    actual = std::string(result, outLen);
    EXPECT_EQ("789", actual);
    EXPECT_EQ(3, outLen);

    result = CastDoubleToString(contextptr, num_double, false, &outLen);
    actual = std::string(result, outLen);
    EXPECT_EQ("3.56", actual);
    EXPECT_EQ(4, outLen);
    delete context;
}

TEST(FunctionTest, Round)
{
    EXPECT_EQ(10, Round<int32_t>(10, 0));
    EXPECT_EQ(10, Round<int32_t>(10, 5));
    EXPECT_EQ(-10, Round<int32_t>(-10, 0));
    EXPECT_EQ(-10, Round<int32_t>(-10, 5));

    EXPECT_EQ(10, RoundLong(10, 0));
    EXPECT_EQ(10, RoundLong(10, 5));
    EXPECT_EQ(-10, RoundLong(-10, 0));
    EXPECT_EQ(-10, RoundLong(-10, 5));

    EXPECT_EQ(10.00, Round<double>(10.12345, 0));
    EXPECT_EQ(10.12, Round<double>(10.12345, 2));
    EXPECT_EQ(10.13, Round<double>(10.12945, 2));
    EXPECT_EQ(-10.00, Round<double>(-10.12345, 0));
    EXPECT_EQ(-10.12, Round<double>(-10.12345, 2));
    EXPECT_EQ(-10.13, Round<double>(-10.12945, 2));
}

TEST(FunctionTest, CombineHash)
{
    EXPECT_EQ(342, CombineHash(10, false, 32, false));
}

/*
 * std::string functions:
 */
TEST(FunctionTest, CountChar)
{
    int64_t result;

    result = CountChar("hello", 5, "l", 1, 1, false);
    EXPECT_EQ(result, 2);

    result = CountChar("aAaA", 4, "a", 1, 1, false);
    EXPECT_EQ(result, 2);

    result = CountChar("abcd", 4, "e", 1, 1, false);
    EXPECT_EQ(result, 0);

    result = CountChar("hello", 5, "", 0, 0, false);
    EXPECT_EQ(result, 0);

    result = CountChar("", 0, "a", 1, 1, false);
    EXPECT_EQ(result, 0);
}

TEST(FunctionTest, SplitIndexRetNull)
{
    int outlen = 0;
    bool outIsNull = false;
    const char *result;
    std::string actual;

    result = SplitIndexRetNull("Jack,John,Mary", 14, false, ",", 1, 1, false, 2, false, &outIsNull, &outlen);
    EXPECT_EQ(outlen, 4);
    EXPECT_EQ(outIsNull, false);
    actual = std::string(result, outlen);
    EXPECT_EQ(actual, "Mary");

    result = SplitIndexRetNull("Jack,Johnny,Mary", 16, false, ",", 1, 1, false, 1, false, &outIsNull, &outlen);
    EXPECT_EQ(outlen, 6);
    EXPECT_EQ(outIsNull, false);
    actual = std::string(result, outlen);
    EXPECT_EQ(actual, "Johnny");

    result = SplitIndexRetNull("Jack,John,Mary", 14, false, ",", 1, 1, false, -1, false, &outIsNull, &outlen);
    EXPECT_EQ(outlen, 0);
    EXPECT_EQ(outIsNull, true);
    EXPECT_EQ(result, nullptr);

    result = SplitIndexRetNull("Jack,John,Mary", 14, false, ",", 1, 1, false, 3, false, &outIsNull, &outlen);
    EXPECT_EQ(outlen, 0);
    EXPECT_EQ(outIsNull, true);
    EXPECT_EQ(result, nullptr);

    result = SplitIndexRetNull(nullptr, 0, false, ",", 1, 1, false, 1, true, &outIsNull, &outlen);
    EXPECT_EQ(outlen, 0);
    EXPECT_EQ(outIsNull, true);
    EXPECT_EQ(result, nullptr);

    result = SplitIndexRetNull("Jack,John,Mary", 14, false, nullptr, 0, 0, true, 1, true, &outIsNull, &outlen);
    EXPECT_EQ(outlen, 0);
    EXPECT_EQ(outIsNull, true);
    EXPECT_EQ(result, nullptr);

    // When strings are concatinated, make sure data from next row isnt included when picking last element
    result = SplitIndexRetNull("Jack,John,MaryPaul,Nathan", 14, false, ",", 1, 1, false, 2, false, &outIsNull, &outlen);
    EXPECT_EQ(outlen, 4);
    actual = std::string(result, outlen);
    EXPECT_EQ(outIsNull, false);
    EXPECT_EQ(actual, "Mary");

    result = SplitIndexRetNull("''", 2, false, ",", 1, 1, false, 0, false, &outIsNull, &outlen);
    EXPECT_EQ(outlen, 2);
    actual = std::string(result, outlen);
    EXPECT_EQ(outIsNull, false);
    EXPECT_EQ(actual, "''");
}

TEST(FunctionTest, ConcatCharChar)
{
    auto context = new ExecutionContext();
    int64_t contextptr = reinterpret_cast<int64_t>(context);
    int outlen = 0;
    const char *result;
    std::string actual;

    result = ConcatCharChar(contextptr, "hello", 5, 5, "world", 5, 5, false, &outlen);
    actual = std::string(result, outlen);
    EXPECT_EQ(actual, "helloworld");
    EXPECT_EQ(outlen, 10);

    result = ConcatCharChar(contextptr, "hello", 5, 5, "world", 10, 5, false, &outlen);
    actual = std::string(result, outlen);
    EXPECT_EQ(actual, "helloworld");
    EXPECT_EQ(outlen, 10);

    result = ConcatCharChar(contextptr, "hello", 10, 5, "world", 5, 5, false, &outlen);
    actual = std::string(result, outlen);
    EXPECT_EQ(actual, "hello     world");
    EXPECT_EQ(outlen, 15);

    result = ConcatCharChar(contextptr, "hello", 10, 5, "world", 5, 5, false, &outlen);
    actual = std::string(result, outlen);
    EXPECT_EQ(actual, "hello     world");
    EXPECT_EQ(outlen, 15);

    result = ConcatCharChar(contextptr, "", 0, 0, "", 0, 0, false, &outlen);
    actual = std::string(result, outlen);
    EXPECT_EQ(actual, "");
    EXPECT_EQ(outlen, 0);

    delete context;
}

TEST(FunctionTest, ConcatStrChar)
{
    auto context = new ExecutionContext();
    int64_t contextptr = reinterpret_cast<int64_t>(context);
    int outlen = 0;
    const char *result;
    std::string actual;

    result = ConcatStrChar(contextptr, "hello", 5, "world", 5, 5, false, &outlen);
    actual = std::string(result, outlen);
    EXPECT_EQ(actual, "helloworld");
    EXPECT_EQ(outlen, 10);

    result = ConcatStrChar(contextptr, "hello", 5, "world", 10, 5, false, &outlen);
    actual = std::string(result, outlen);
    EXPECT_EQ(actual, "helloworld");
    EXPECT_EQ(outlen, 10);

    result = ConcatStrChar(contextptr, "hello", 5, "world     ", 10, 10, false, &outlen);
    actual = std::string(result, outlen);
    EXPECT_EQ(actual, "helloworld     ");
    EXPECT_EQ(outlen, 15);

    result = ConcatStrChar(contextptr, "", 0, "", 0, 0, false, &outlen);
    actual = std::string(result, outlen);
    EXPECT_EQ(actual, "");
    EXPECT_EQ(outlen, 0);

    result = ConcatStrChar(contextptr, "hello", 5, "     ", 5, 5, false, &outlen);
    actual = std::string(result, outlen);
    EXPECT_EQ(actual, "hello     ");
    EXPECT_EQ(outlen, 10);
    delete context;
}

TEST(FunctionTest, ConcatCharStr)
{
    auto context = new ExecutionContext();
    int64_t contextptr = reinterpret_cast<int64_t>(context);
    int outlen = 0;
    const char *result;
    std::string actual;

    result = ConcatCharStr(contextptr, "hello", 5, 5, "world", 5, false, &outlen);
    actual = std::string(result, outlen);
    EXPECT_EQ(actual, "helloworld");
    EXPECT_EQ(outlen, 10);

    result = ConcatCharStr(contextptr, "hello", 10, 5, "world", 5, false, &outlen);
    actual = std::string(result, outlen);
    EXPECT_EQ(actual, "hello     world");
    EXPECT_EQ(outlen, 15);

    result = ConcatCharStr(contextptr, "hello     ", 10, 10, "world", 5, false, &outlen);
    actual = std::string(result, outlen);
    EXPECT_EQ(actual, "hello     world");
    EXPECT_EQ(outlen, 15);

    result = ConcatCharStr(contextptr, "", 0, 0, "", 0, false, &outlen);
    actual = std::string(result, outlen);
    EXPECT_EQ(actual, "");
    EXPECT_EQ(outlen, 0);

    result = ConcatCharStr(contextptr, "", 5, 0, "world", 5, false, &outlen);
    actual = std::string(result, outlen);
    EXPECT_EQ(actual, "     world");
    EXPECT_EQ(outlen, 10);
    delete context;
}

TEST(FunctionTest, ConcatWsWithoutStr)
{
    auto context = new ExecutionContext();
    int64_t contextPtr = reinterpret_cast<int64_t>(context);
    int32_t outlen = 0;
    const char *result;
    std::string actual;
    bool retIsNull = false;

    // concat_ws("-") => "" (Spark SQL: separator only returns empty string)
    result = ConcatWsWithoutStr(contextPtr, "-", 1, false, &retIsNull, &outlen);
    EXPECT_FALSE(retIsNull);
    EXPECT_NE(result, nullptr);
    EXPECT_EQ(outlen, 0);
    actual = std::string(result, outlen);
    EXPECT_EQ(actual, "");

    // concat_ws(NULL) => NULL
    result = ConcatWsWithoutStr(contextPtr, "-", 1, true, &retIsNull, &outlen);
    EXPECT_TRUE(retIsNull);
    EXPECT_EQ(result, nullptr);
    EXPECT_EQ(outlen, 0);

    delete context;
}

TEST(FunctionTest, ConcatWsWith1Str)
{
    auto context = new ExecutionContext();
    int64_t contextPtr = reinterpret_cast<int64_t>(context);
    int32_t outlen = 0;
    const char *result;
    std::string actual;
    bool retIsNull = false;

    // concat_ws("-", "aa") => "aa" (Spark SQL: single string returns as-is)
    result = ConcatWsWith1Str(contextPtr, "-", 1, false, "aa", 2, false, &retIsNull, &outlen);
    EXPECT_FALSE(retIsNull);
    EXPECT_NE(result, nullptr);
    EXPECT_EQ(outlen, 2);
    actual = std::string(result, outlen);
    EXPECT_EQ(actual, "aa");

    // concat_ws("-", null) => ""
    result = ConcatWsWith1Str(contextPtr, "-", 1, false, nullptr, 0, true, &retIsNull, &outlen);
    EXPECT_FALSE(retIsNull);
    EXPECT_NE(result, nullptr);
    EXPECT_EQ(outlen, 0);
    actual = std::string(result, outlen);
    EXPECT_EQ(actual, "");

    // concat_ws(NULL, "aa") => NULL
    result = ConcatWsWith1Str(contextPtr, "-", 1, true, "aa", 2, false, &retIsNull, &outlen);
    EXPECT_TRUE(retIsNull);
    EXPECT_EQ(result, nullptr);
    EXPECT_EQ(outlen, 0);

    delete context;
}

TEST(FunctionTest, ConcatWsStr)
{
    auto context = new ExecutionContext();
    int64_t contextPtr = reinterpret_cast<int64_t>(context);
    int32_t outlen = 0;
    const char *result;
    std::string actual;
    bool retIsNull = false;

    result = ConcatWsStr(contextPtr, ",", 1, false, "hello", 5, false, "world", 5, false, &retIsNull, &outlen);
    EXPECT_FALSE(retIsNull);
    EXPECT_NE(result, nullptr);
    EXPECT_EQ(outlen, 11);
    actual = std::string(result, outlen);
    EXPECT_EQ(actual, "hello,world");

    result = ConcatWsStr(contextPtr, "", 0, false, "hello", 5, false, "world", 5, false, &retIsNull, &outlen);
    EXPECT_FALSE(retIsNull);
    EXPECT_NE(result, nullptr);
    EXPECT_EQ(outlen, 10);
    actual = std::string(result, outlen);
    EXPECT_EQ(actual, "helloworld");

    result = ConcatWsStr(contextPtr, "-", 1, false, "", 0, false, "world", 5, false, &retIsNull, &outlen);
    EXPECT_FALSE(retIsNull);
    EXPECT_NE(result, nullptr);
    EXPECT_EQ(outlen, 6);
    actual = std::string(result, outlen);
    EXPECT_EQ(actual, "-world");

    result = ConcatWsStr(contextPtr, "-", 1, false, "hello", 5, false, "", 0, false, &retIsNull, &outlen);
    EXPECT_FALSE(retIsNull);
    EXPECT_NE(result, nullptr);
    EXPECT_EQ(outlen, 6);
    actual = std::string(result, outlen);
    EXPECT_EQ(actual, "hello-");

    result = ConcatWsStr(contextPtr, "-", 1, false, "", 0, false, "", 0, false, &retIsNull, &outlen);
    EXPECT_FALSE(retIsNull);
    EXPECT_NE(result, nullptr);
    EXPECT_EQ(outlen, 1);
    actual = std::string(result, outlen);
    EXPECT_EQ(actual, "-");

    result = ConcatWsStr(contextPtr, "-", 1, false, "", 0, false, "world", 5, false, &retIsNull, &outlen);
    EXPECT_FALSE(retIsNull);
    EXPECT_NE(result, nullptr);
    EXPECT_EQ(outlen, 6);
    actual = std::string(result, outlen);
    EXPECT_EQ(actual, "-world");

    result = ConcatWsStr(contextPtr, "-", 1, true, "a", 1, false, "b", 1, false, &retIsNull, &outlen);
    EXPECT_TRUE(retIsNull);
    EXPECT_EQ(result, nullptr);
    EXPECT_EQ(outlen, 0);

    result = ConcatWsStr(contextPtr, "-", 1, false, nullptr, 0, true, "b", 1, false, &retIsNull, &outlen);
    EXPECT_FALSE(retIsNull);
    EXPECT_NE(result, nullptr);
    EXPECT_EQ(outlen, 1);
    actual = std::string(result, outlen);
    EXPECT_EQ(actual, "b");

    result = ConcatWsStr(contextPtr, "-", 1, false, nullptr, 0, true, nullptr, 0, true, &retIsNull, &outlen);
    EXPECT_FALSE(retIsNull);
    EXPECT_NE(result, nullptr);
    EXPECT_EQ(outlen, 0);
    actual = std::string(result, outlen);
    EXPECT_EQ(actual, "");

    delete context;
}

TEST(FunctionTest, ConcatWs3Str)
{
    auto context = new ExecutionContext();
    int64_t contextPtr = reinterpret_cast<int64_t>(context);
    int32_t outlen = 0;
    const char *result;
    std::string actual;
    bool retIsNull = false;

    result = ConcatWs3Str(contextPtr, ",", 1, false, "a", 1, false, "b", 1, false, "c", 1, false, &retIsNull, &outlen);
    EXPECT_FALSE(retIsNull);
    EXPECT_NE(result, nullptr);
    EXPECT_EQ(outlen, 5);
    actual = std::string(result, outlen);
    EXPECT_EQ(actual, "a,b,c");

    result = ConcatWs3Str(contextPtr, "=", 1, false, "a", 1, false, "", 0, false, "c", 1, false, &retIsNull, &outlen);
    EXPECT_FALSE(retIsNull);
    EXPECT_NE(result, nullptr);
    EXPECT_EQ(outlen, 4);
    actual = std::string(result, outlen);
    EXPECT_EQ(actual, "a==c");

    result = ConcatWs3Str(contextPtr, "=", 1, false, "", 0, false, "b", 1, false, "c", 1, false, &retIsNull, &outlen);
    EXPECT_FALSE(retIsNull);
    EXPECT_NE(result, nullptr);
    EXPECT_EQ(outlen, 4);
    actual = std::string(result, outlen);
    EXPECT_EQ(actual, "=b=c");

    result = ConcatWs3Str(contextPtr, "=", 1, false, "a", 1, false, "b", 1, false, "", 0, false, &retIsNull, &outlen);
    EXPECT_FALSE(retIsNull);
    EXPECT_NE(result, nullptr);
    EXPECT_EQ(outlen, 4);
    actual = std::string(result, outlen);
    EXPECT_EQ(actual, "a=b=");

    // concat_ws("-", "", null, "") => "-"
    result = ConcatWs3Str(contextPtr, "-", 1, false, "", 0, false, nullptr, 0, true, "", 0, false, &retIsNull, &outlen);
    EXPECT_FALSE(retIsNull);
    EXPECT_NE(result, nullptr);
    EXPECT_EQ(outlen, 1);
    actual = std::string(result, outlen);
    EXPECT_EQ(actual, "-");

    // concat_ws("-", "", null, null) => ""
    result = ConcatWs3Str(contextPtr, "-", 1, false, "", 0, false, nullptr, 0, true, nullptr, 0, true, &retIsNull, &outlen);
    EXPECT_FALSE(retIsNull);
    EXPECT_NE(result, nullptr);
    EXPECT_EQ(outlen, 0);
    actual = std::string(result, outlen);
    EXPECT_EQ(actual, "");

    // concat_ws("-", null, null, null) => ""
    result = ConcatWs3Str(contextPtr, "-", 1, false, nullptr, 0, true, nullptr, 0, true, nullptr, 0, true, &retIsNull, &outlen);
    EXPECT_FALSE(retIsNull);
    EXPECT_NE(result, nullptr);
    EXPECT_EQ(outlen, 0);
    actual = std::string(result, outlen);
    EXPECT_EQ(actual, "");

    // separator null => null
    result = ConcatWs3Str(contextPtr, "-", 1, true, "aa", 2, false, "dd", 2, false, "bb", 2, false, &retIsNull, &outlen);
    EXPECT_TRUE(retIsNull);
    EXPECT_EQ(result, nullptr);
    EXPECT_EQ(outlen, 0);

    // concat_ws("", "aa", "", "bb") => "aabb"
    result = ConcatWs3Str(contextPtr, "", 0, false, "aa", 2, false, "", 0, false, "bb", 2, false, &retIsNull, &outlen);
    EXPECT_FALSE(retIsNull);
    EXPECT_NE(result, nullptr);
    EXPECT_EQ(outlen, 4);
    actual = std::string(result, outlen);
    EXPECT_EQ(actual, "aabb");

    result = ConcatWs3Str(contextPtr, "", 0, false, "a", 1, false, "b", 1, false, "c", 1, false, &retIsNull, &outlen);
    EXPECT_FALSE(retIsNull);
    EXPECT_NE(result, nullptr);
    EXPECT_EQ(outlen, 3);
    actual = std::string(result, outlen);
    EXPECT_EQ(actual, "abc");

    delete context;
}

TEST(FunctionTest, ConcatWs4Str)
{
    auto context = new ExecutionContext();
    int64_t contextPtr = reinterpret_cast<int64_t>(context);
    int32_t outlen = 0;
    const char *result;
    std::string actual;
    bool retIsNull = false;

    result = ConcatWs4Str(contextPtr, ",", 1, false, "a", 1, false, "b", 1, false, "c", 1, false, "d", 1, false,
        &retIsNull, &outlen);
    EXPECT_FALSE(retIsNull);
    EXPECT_NE(result, nullptr);
    EXPECT_EQ(outlen, 7);
    actual = std::string(result, outlen);
    EXPECT_EQ(actual, "a,b,c,d");

    result = ConcatWs4Str(contextPtr, ",", 1, false, "a", 1, false, "b", 1, false, "", 0, false, "d", 1, false,
        &retIsNull, &outlen);
    EXPECT_FALSE(retIsNull);
    EXPECT_NE(result, nullptr);
    EXPECT_EQ(outlen, 6);
    actual = std::string(result, outlen);
    EXPECT_EQ(actual, "a,b,,d");

    result = ConcatWs4Str(contextPtr, ",", 1, false, "", 0, false, "b", 1, false, "c", 1, false, "", 0, false,
        &retIsNull, &outlen);
    EXPECT_FALSE(retIsNull);
    EXPECT_NE(result, nullptr);
    EXPECT_EQ(outlen, 5);
    actual = std::string(result, outlen);
    EXPECT_EQ(actual, ",b,c,");

    result = ConcatWs4Str(contextPtr, ",", 1, false, "", 0, false, "", 0, false, "", 0, false, "", 0, false,
        &retIsNull, &outlen);
    EXPECT_FALSE(retIsNull);
    EXPECT_NE(result, nullptr);
    EXPECT_EQ(outlen, 3);
    actual = std::string(result, outlen);
    EXPECT_EQ(actual, ",,,");

    result = ConcatWs4Str(contextPtr, ",", 1, true, "a", 1, false, "b", 1, false, "c", 1, false, "d", 1, false,
        &retIsNull, &outlen);
    EXPECT_TRUE(retIsNull);
    EXPECT_EQ(result, nullptr);
    EXPECT_EQ(outlen, 0);

    result = ConcatWs4Str(contextPtr, "", 0, false, "a", 1, false, "b", 1, false, "c", 1, false, "d", 1, false,
        &retIsNull, &outlen);
    EXPECT_FALSE(retIsNull);
    EXPECT_NE(result, nullptr);
    EXPECT_EQ(outlen, 4);
    actual = std::string(result, outlen);
    EXPECT_EQ(actual, "abcd");

    // skip nulls: concat_ws("-", "aa", null, "bb", null) => "aa-bb"
    result = ConcatWs4Str(contextPtr, "-", 1, false, "aa", 2, false, nullptr, 0, true, "bb", 2, false, nullptr, 0, true,
        &retIsNull, &outlen);
    EXPECT_FALSE(retIsNull);
    EXPECT_NE(result, nullptr);
    EXPECT_EQ(outlen, 5);
    actual = std::string(result, outlen);
    EXPECT_EQ(actual, "aa-bb");

    delete context;
}

TEST(FunctionTest, ConcatWs5Str)
{
    auto context = new ExecutionContext();
    int64_t contextPtr = reinterpret_cast<int64_t>(context);
    int32_t outlen = 0;
    const char *result;
    std::string actual;
    bool retIsNull = false;

    result = ConcatWs5Str(contextPtr, ",", 1, false, "a", 1, false, "b", 1, false, "c", 1, false, "d", 1, false,
        "e", 1, false, &retIsNull, &outlen);
    EXPECT_FALSE(retIsNull);
    EXPECT_NE(result, nullptr);
    EXPECT_EQ(outlen, 9);
    actual = std::string(result, outlen);
    EXPECT_EQ(actual, "a,b,c,d,e");

    result = ConcatWs5Str(contextPtr, ",", 1, false, "a", 1, false, "b", 1, false, "", 0, false, "d", 1, false,
        "e", 1, false, &retIsNull, &outlen);
    EXPECT_FALSE(retIsNull);
    EXPECT_NE(result, nullptr);
    EXPECT_EQ(outlen, 8);
    actual = std::string(result, outlen);
    EXPECT_EQ(actual, "a,b,,d,e");

    result = ConcatWs5Str(contextPtr, ",", 1, false, "", 0, false, "b", 1, false, "c", 1, false, "d", 1, false,
        "", 0, false, &retIsNull, &outlen);
    EXPECT_FALSE(retIsNull);
    EXPECT_NE(result, nullptr);
    EXPECT_EQ(outlen, 7);
    actual = std::string(result, outlen);
    EXPECT_EQ(actual, ",b,c,d,");

    result = ConcatWs5Str(contextPtr, ",", 1, false, "", 0, false, "", 0, false, "", 0, false, "", 0, false, "", 0,
        false, &retIsNull, &outlen);
    EXPECT_FALSE(retIsNull);
    EXPECT_NE(result, nullptr);
    EXPECT_EQ(outlen, 4);
    actual = std::string(result, outlen);
    EXPECT_EQ(actual, ",,,,");

    result = ConcatWs5Str(contextPtr, ",", 1, true, "a", 1, false, "b", 1, false, "c", 1, false, "d", 1, false,
        "e", 1, false, &retIsNull, &outlen);
    EXPECT_TRUE(retIsNull);
    EXPECT_EQ(result, nullptr);
    EXPECT_EQ(outlen, 0);

    result = ConcatWs5Str(contextPtr, "", 0, false, "a", 1, false, "b", 1, false, "c", 1, false, "d", 1, false,
        "e", 1, false, &retIsNull, &outlen);
    EXPECT_FALSE(retIsNull);
    EXPECT_NE(result, nullptr);
    EXPECT_EQ(outlen, 5);
    actual = std::string(result, outlen);
    EXPECT_EQ(actual, "abcde");

    result = ConcatWs5Str(contextPtr, "-", 1, false, nullptr, 0, true, nullptr, 0, true, nullptr, 0, true, nullptr, 0,
        true, nullptr, 0, true, &retIsNull, &outlen);
    EXPECT_FALSE(retIsNull);
    EXPECT_NE(result, nullptr);
    EXPECT_EQ(outlen, 0);
    actual = std::string(result, outlen);
    EXPECT_EQ(actual, "");

    delete context;
}

TEST(FunctionTest, Substr)
{
    auto context = new ExecutionContext();
    int64_t contextptr = reinterpret_cast<int64_t>(context);
    std::string str = "Magic Johnson 123@#$";
    int32_t strlen = static_cast<int32_t>(str.length());
    int32_t outlen = 0;
    const char *result;
    std::string actual;

    result = SubstrVarchar<int32_t, false, false>(contextptr, str.c_str(), strlen, 1, strlen, false, &outlen);
    actual = std::string(result, outlen);
    EXPECT_EQ(actual, str);
    EXPECT_EQ(outlen, strlen);

    result = SubstrVarchar<int32_t, false, false>(contextptr, str.c_str(), strlen, 1, 5, false, &outlen);
    actual = std::string(result, outlen);
    EXPECT_EQ(actual, "Magic");
    EXPECT_EQ(outlen, 5);

    result = SubstrVarchar<int32_t, false, false>(contextptr, str.c_str(), strlen, 10, 10, false, &outlen);
    actual = std::string(result, outlen);
    EXPECT_EQ(actual, "nson 123@#");
    EXPECT_EQ(outlen, 10);

    result = SubstrVarchar<int32_t, false, false>(contextptr, str.c_str(), strlen, -5, 7, false, &outlen);
    actual = std::string(result, outlen);
    EXPECT_EQ(actual, "23@#$");
    EXPECT_EQ(outlen, 5);

    result = SubstrVarchar<int32_t, false, false>(contextptr, str.c_str(), strlen, 0, 0, false, &outlen);
    actual = std::string(result, outlen);
    EXPECT_EQ(actual, "");
    EXPECT_EQ(outlen, 0);

    result = SubstrVarchar<int32_t, false, false>(contextptr, str.c_str(), strlen, strlen, strlen + 5, false, &outlen);
    actual = std::string(result, outlen);
    EXPECT_EQ(actual, "$");
    EXPECT_EQ(outlen, 1);
    delete context;
}

TEST(FunctionTest, SubstrZh)
{
    auto context = new ExecutionContext();
    int64_t contextPtr = reinterpret_cast<int64_t>(context);
    std::string str = "时欧基乌斯侧后解 hello! 回复哦黑色的and magic粉色的圣诞袜";
    int32_t strLen = static_cast<int32_t>(str.length());
    int32_t outLen = 0;
    const char *result;
    std::string actual;

    result = SubstrVarchar<int32_t, false, false>(contextPtr, str.c_str(), strLen, 1, 37, false, &outLen);
    actual = std::string(result, outLen);
    EXPECT_EQ(actual, str);
    EXPECT_EQ(outLen, strLen);

    result = SubstrVarchar<int32_t, false, true>(contextPtr, str.c_str(), strLen, 0, 37, false, &outLen);
    actual = std::string(result, outLen);
    EXPECT_EQ(actual, str);
    EXPECT_EQ(outLen, strLen);

    result = SubstrVarchar<int32_t, false, false>(contextPtr, str.c_str(), strLen, 1, 5, false, &outLen);
    actual = std::string(result, outLen);
    EXPECT_EQ(actual, "时欧基乌斯");
    EXPECT_EQ(outLen, 15);

    result = SubstrVarchar<int32_t, false, true>(contextPtr, str.c_str(), strLen, 0, 5, false, &outLen);
    actual = std::string(result, outLen);
    EXPECT_EQ(actual, "时欧基乌斯");
    EXPECT_EQ(outLen, 15);

    result = SubstrVarchar<int32_t, false, false>(contextPtr, str.c_str(), strLen, 10, 10, false, &outLen);
    actual = std::string(result, outLen);
    EXPECT_EQ(actual, "hello! 回复哦");
    EXPECT_EQ(outLen, 16);

    result = SubstrVarchar<int32_t, false, false>(contextPtr, str.c_str(), strLen, -5, 7, false, &outLen);
    actual = std::string(result, outLen);
    EXPECT_EQ(actual, "色的圣诞袜");
    EXPECT_EQ(outLen, 15);

    result = SubstrVarchar<int32_t, false, false>(contextPtr, str.c_str(), strLen, 0, 0, false, &outLen);
    actual = std::string(result, outLen);
    EXPECT_EQ(actual, "");
    EXPECT_EQ(outLen, 0);

    result = SubstrVarchar<int32_t, false, true>(contextPtr, str.c_str(), strLen, 0, 0, false, &outLen);
    actual = std::string(result, outLen);
    EXPECT_EQ(actual, "");
    EXPECT_EQ(outLen, 0);

    result = SubstrVarchar<int32_t, false, false>(contextPtr, str.c_str(), strLen, 37, strLen + 5, false, &outLen);
    actual = std::string(result, outLen);
    EXPECT_EQ(actual, "袜");
    EXPECT_EQ(outLen, 3);

    result = SubstrVarchar<int32_t, false, false>(contextPtr, str.c_str(), strLen, -38, 10, false, &outLen);
    actual = std::string(result, outLen);
    EXPECT_EQ(actual, "");
    EXPECT_EQ(outLen, 0);

    result = SubstrVarchar<int32_t, false, false>(contextPtr, str.c_str(), strLen, -37, 37, false, &outLen);
    actual = std::string(result, outLen);
    EXPECT_EQ(actual, str);
    EXPECT_EQ(outLen, strLen);

    delete context;
}

TEST(FunctionTest, SubstrChar)
{
    auto context = new ExecutionContext();
    int64_t contextptr = reinterpret_cast<int64_t>(context);
    std::string str = "Magic Johnson 123@#$       ";
    int32_t width = static_cast<int32_t>(str.length());
    int32_t strlen = width - 7;
    int32_t outlen = 0;
    const char *result;
    std::string actual;

    result = SubstrChar<int32_t, false, false>(contextptr, str.c_str(), width, strlen, 1, strlen, false, &outlen);
    actual = std::string(result, outlen);
    EXPECT_EQ(actual, "Magic Johnson 123@#$");
    EXPECT_EQ(outlen, strlen);

    result = SubstrChar<int32_t, false, true>(contextptr, str.c_str(), width, strlen, 0, strlen, false, &outlen);
    actual = std::string(result, outlen);
    EXPECT_EQ(actual, "Magic Johnson 123@#$");
    EXPECT_EQ(outlen, strlen);

    result = SubstrChar<int32_t, false, false>(contextptr, str.c_str(), width, strlen, 1, 5, false, &outlen);
    actual = std::string(result, outlen);
    EXPECT_EQ(actual, "Magic");
    EXPECT_EQ(outlen, 5);

    result = SubstrChar<int32_t, false, true>(contextptr, str.c_str(), width, strlen, 0, 5, false, &outlen);
    actual = std::string(result, outlen);
    EXPECT_EQ(actual, "Magic");
    EXPECT_EQ(outlen, 5);

    result = SubstrChar<int32_t, false, false>(contextptr, str.c_str(), width, strlen, 10, 10, false, &outlen);
    actual = std::string(result, outlen);
    EXPECT_EQ(actual, "nson 123@#");
    EXPECT_EQ(outlen, 10);

    result = SubstrChar<int32_t, false, false>(contextptr, str.c_str(), width, strlen, -5, 7, false, &outlen);
    actual = std::string(result, outlen);
    EXPECT_EQ(actual, "23@#$");
    EXPECT_EQ(outlen, 5);

    result = SubstrChar<int32_t, false, false>(contextptr, str.c_str(), width, strlen, 0, 0, false, &outlen);
    actual = std::string(result, outlen);
    EXPECT_EQ(actual, "");
    EXPECT_EQ(outlen, 0);

    result = SubstrChar<int32_t, false, true>(contextptr, str.c_str(), width, strlen, 0, 0, false, &outlen);
    actual = std::string(result, outlen);
    EXPECT_EQ(actual, "");
    EXPECT_EQ(outlen, 0);

    result =
        SubstrChar<int32_t, false, false>(contextptr, str.c_str(), width, strlen, strlen, strlen + 5, false, &outlen);
    actual = std::string(result, outlen);
    EXPECT_EQ(actual, "$");
    EXPECT_EQ(outlen, 1);

    delete context;
}

TEST(FunctionTest, SubstrCharZh)
{
    auto context = new ExecutionContext();
    int64_t contextPtr = reinterpret_cast<int64_t>(context);
    std::string str = "时欧基乌斯侧后解 hello! 回复哦黑色的and magic粉色的圣诞袜";
    int32_t width = 37;
    int32_t strLen = str.length();
    int32_t outLen = 0;
    const char *result;
    std::string actual;

    result = SubstrChar<int32_t, false, false>(contextPtr, str.c_str(), width, strLen, 1, 37, false, &outLen);
    actual = std::string(result, outLen);
    EXPECT_EQ(actual, str);
    EXPECT_EQ(outLen, strLen);

    result = SubstrChar<int32_t, false, true>(contextPtr, str.c_str(), width, strLen, 0, 37, false, &outLen);
    actual = std::string(result, outLen);
    EXPECT_EQ(actual, str);
    EXPECT_EQ(outLen, strLen);

    result = SubstrChar<int32_t, false, false>(contextPtr, str.c_str(), width, strLen, 1, 5, false, &outLen);
    actual = std::string(result, outLen);
    EXPECT_EQ(actual, "时欧基乌斯");
    EXPECT_EQ(outLen, 15);

    result = SubstrChar<int32_t, false, true>(contextPtr, str.c_str(), width, strLen, 0, 5, false, &outLen);
    actual = std::string(result, outLen);
    EXPECT_EQ(actual, "时欧基乌斯");
    EXPECT_EQ(outLen, 15);

    result = SubstrChar<int32_t, false, false>(contextPtr, str.c_str(), width, strLen, 10, 10, false, &outLen);
    actual = std::string(result, outLen);
    EXPECT_EQ(actual, "hello! 回复哦");
    EXPECT_EQ(outLen, 16);

    result = SubstrChar<int32_t, false, false>(contextPtr, str.c_str(), width, strLen, -5, 7, false, &outLen);
    actual = std::string(result, outLen);
    EXPECT_EQ(actual, "色的圣诞袜");
    EXPECT_EQ(outLen, 15);

    result = SubstrChar<int32_t, false, false>(contextPtr, str.c_str(), width, strLen, 0, 0, false, &outLen);
    actual = std::string(result, outLen);
    EXPECT_EQ(actual, "");
    EXPECT_EQ(outLen, 0);

    result = SubstrChar<int32_t, false, true>(contextPtr, str.c_str(), width, strLen, 0, 0, false, &outLen);
    actual = std::string(result, outLen);
    EXPECT_EQ(actual, "");
    EXPECT_EQ(outLen, 0);

    result = SubstrChar<int32_t, false, false>(contextPtr, str.c_str(), width, strLen, 37, strLen + 5, false, &outLen);
    actual = std::string(result, outLen);
    EXPECT_EQ(actual, "袜");
    EXPECT_EQ(outLen, 3);

    result = SubstrChar<int32_t, false, false>(contextPtr, str.c_str(), width, strLen, -38, 10, false, &outLen);
    actual = std::string(result, outLen);
    EXPECT_EQ(actual, "");
    EXPECT_EQ(outLen, 0);

    result = SubstrChar<int32_t, false, false>(contextPtr, str.c_str(), width, strLen, -37, 37, false, &outLen);
    actual = std::string(result, outLen);
    EXPECT_EQ(actual, str);
    EXPECT_EQ(outLen, strLen);

    delete context;
}

TEST(FunctionTest, SubstrWithStart)
{
    auto context = new ExecutionContext();
    int64_t contextptr = reinterpret_cast<int64_t>(context);
    std::string str = "ABC efg 123 $%^";
    int32_t strlen = static_cast<int32_t>(str.length());
    int32_t outlen = 0;
    const char *result;
    std::string actual;

    result = SubstrVarcharWithStart<int32_t, false, false>(contextptr, str.c_str(), strlen, 1, false, &outlen);
    actual = std::string(result, outlen);
    EXPECT_EQ(actual, str);
    EXPECT_EQ(outlen, strlen);

    result = SubstrVarcharWithStart<int32_t, false, true>(contextptr, str.c_str(), strlen, 0, false, &outlen);
    actual = std::string(result, outlen);
    EXPECT_EQ(actual, str);
    EXPECT_EQ(outlen, strlen);

    result = SubstrVarcharWithStart<int32_t, false, false>(contextptr, str.c_str(), strlen, 9, false, &outlen);
    actual = std::string(result, outlen);
    EXPECT_EQ(actual, "123 $%^");
    EXPECT_EQ(outlen, 7);

    result = SubstrVarcharWithStart<int32_t, false, false>(contextptr, str.c_str(), strlen, -3, false, &outlen);
    actual = std::string(result, outlen);
    EXPECT_EQ(actual, "$%^");
    EXPECT_EQ(outlen, 3);

    result = SubstrVarcharWithStart<int32_t, false, false>(contextptr, str.c_str(), strlen, 0, false, &outlen);
    actual = std::string(result, outlen);
    EXPECT_EQ(actual, "");
    EXPECT_EQ(outlen, 0);

    delete context;
}

TEST(FunctionTest, SubstrWithZh)
{
    auto context = new ExecutionContext();
    int64_t contextPtr = reinterpret_cast<int64_t>(context);
    std::string str = "时欧基乌斯侧后解 hello! 回复哦黑色的and magic粉色的圣诞袜";
    int32_t strLen = static_cast<int32_t>(str.length());
    int32_t outLen = 0;
    const char *result;
    std::string actual;

    result = SubstrVarcharWithStart<int32_t, false, false>(contextPtr, str.c_str(), strLen, 1, false, &outLen);
    actual = std::string(result, outLen);
    EXPECT_EQ(actual, str);
    EXPECT_EQ(outLen, strLen);

    result = SubstrVarcharWithStart<int32_t, false, true>(contextPtr, str.c_str(), strLen, 0, false, &outLen);
    actual = std::string(result, outLen);
    EXPECT_EQ(actual, str);
    EXPECT_EQ(outLen, strLen);

    result = SubstrVarcharWithStart<int32_t, false, false>(contextPtr, str.c_str(), strLen, 9, false, &outLen);
    actual = std::string(result, outLen);
    EXPECT_EQ(actual, " hello! 回复哦黑色的and magic粉色的圣诞袜");
    EXPECT_EQ(outLen, 53);

    result = SubstrVarcharWithStart<int32_t, false, false>(contextPtr, str.c_str(), strLen, -3, false, &outLen);
    actual = std::string(result, outLen);
    EXPECT_EQ(actual, "圣诞袜");
    EXPECT_EQ(outLen, 9);

    result = SubstrVarcharWithStart<int32_t, false, false>(contextPtr, str.c_str(), strLen, 0, false, &outLen);
    actual = std::string(result, outLen);
    EXPECT_EQ(actual, "");
    EXPECT_EQ(outLen, 0);

    result = SubstrVarcharWithStart<int32_t, false, false>(contextPtr, str.c_str(), strLen, 37, false, &outLen);
    actual = std::string(result, outLen);
    EXPECT_EQ(actual, "袜");
    EXPECT_EQ(outLen, 3);

    result = SubstrVarcharWithStart<int32_t, false, false>(contextPtr, str.c_str(), strLen, -38, false, &outLen);
    actual = std::string(result, outLen);
    EXPECT_EQ(actual, "");
    EXPECT_EQ(outLen, 0);

    result = SubstrVarcharWithStart<int32_t, false, false>(contextPtr, str.c_str(), strLen, -37, false, &outLen);
    actual = std::string(result, outLen);
    EXPECT_EQ(actual, str);
    EXPECT_EQ(outLen, strLen);

    delete context;
}

TEST(FunctionTest, SubstrWithZhForSpark)
{
    ConfigUtil::SetNegativeStartIndexOutOfBoundsRule(NegativeStartIndexOutOfBoundsRule::INTERCEPT_FROM_BEYOND);
    auto context = new ExecutionContext();
    int64_t contextPtr = reinterpret_cast<int64_t>(context);
    std::string str = "时欧基乌斯侧后解 h";
    int32_t strLen = static_cast<int32_t>(str.length());
    int32_t outLen = 0;
    const char *result;
    std::string actual;

    result = SubstrVarcharWithStart<int32_t, true, false>(contextPtr, str.c_str(), strLen, -15, false, &outLen);
    actual = std::string(result, outLen);
    EXPECT_EQ(actual, str);
    EXPECT_EQ(outLen, strLen);

    result = SubstrVarcharWithStart<int32_t, true, true>(contextPtr, str.c_str(), strLen, 0, false, &outLen);
    actual = std::string(result, outLen);
    EXPECT_EQ(actual, str);
    EXPECT_EQ(outLen, strLen);

    result = SubstrVarchar<int32_t, true, false>(contextPtr, str.c_str(), strLen, -15, 5, false, &outLen);
    actual = std::string(result, outLen);
    EXPECT_EQ(actual, "");
    EXPECT_EQ(outLen, 0);

    result = SubstrVarchar<int32_t, true, false>(contextPtr, str.c_str(), strLen, -15, 6, false, &outLen);
    actual = std::string(result, outLen);
    EXPECT_EQ(actual, "时");
    EXPECT_EQ(outLen, 3);

    result = SubstrVarchar<int32_t, true, false>(contextPtr, str.c_str(), strLen, -15, 14, false, &outLen);
    actual = std::string(result, outLen);
    EXPECT_EQ(actual, "时欧基乌斯侧后解 ");
    EXPECT_EQ(outLen, 25);

    result = SubstrVarchar<int32_t, true, false>(contextPtr, str.c_str(), strLen, -15, 20, false, &outLen);
    actual = std::string(result, outLen);
    EXPECT_EQ(actual, "时欧基乌斯侧后解 h");
    EXPECT_EQ(outLen, 26);

    std::string strEn = "apple";
    result = SubstrVarchar<int32_t, true, false>(contextPtr, strEn.c_str(), static_cast<int32_t>(strEn.length()), -7, 3,
        false, &outLen);
    actual = std::string(result, outLen);
    EXPECT_EQ(actual, "a");

    result = SubstrVarcharWithStart<int32_t, true, false>(contextPtr, strEn.c_str(),
        static_cast<int32_t>(strEn.length()), -7, false, &outLen);
    actual = std::string(result, outLen);
    EXPECT_EQ(actual, "apple");

    ConfigUtil::SetNegativeStartIndexOutOfBoundsRule(NegativeStartIndexOutOfBoundsRule::EMPTY_STRING);
    delete context;
}

TEST(FunctionTest, SubstrCharWithStart)
{
    auto context = new ExecutionContext();
    int64_t contextptr = reinterpret_cast<int64_t>(context);
    std::string str = "ABC efg 123 $%^        ";
    int32_t width = static_cast<int32_t>(str.length());
    int32_t outlen = 0;
    int32_t strlen = width - 8;
    const char *result;
    std::string actual;

    result = SubstrCharWithStart<int32_t, false, false>(contextptr, str.c_str(), width, strlen, 1, false, &outlen);
    actual = std::string(result, outlen);
    EXPECT_EQ(actual, "ABC efg 123 $%^");
    EXPECT_EQ(outlen, strlen);

    result = SubstrCharWithStart<int32_t, false, true>(contextptr, str.c_str(), width, strlen, 0, false, &outlen);
    actual = std::string(result, outlen);
    EXPECT_EQ(actual, "ABC efg 123 $%^");
    EXPECT_EQ(outlen, strlen);

    result = SubstrCharWithStart<int32_t, false, false>(contextptr, str.c_str(), width, strlen, 9, false, &outlen);
    actual = std::string(result, outlen);
    EXPECT_EQ(actual, "123 $%^");
    EXPECT_EQ(outlen, 7);

    result = SubstrCharWithStart<int32_t, false, false>(contextptr, str.c_str(), width, strlen, -3, false, &outlen);
    actual = std::string(result, outlen);
    EXPECT_EQ(actual, "$%^");
    EXPECT_EQ(outlen, 3);

    result = SubstrCharWithStart<int32_t, false, false>(contextptr, str.c_str(), width, strlen, 0, false, &outlen);
    actual = std::string(result, outlen);
    EXPECT_EQ(actual, "");
    EXPECT_EQ(outlen, 0);
    delete context;
}

TEST(FunctionTest, SubstrCharWithStartZh)
{
    auto context = new ExecutionContext();
    int64_t contextPtr = reinterpret_cast<int64_t>(context);
    std::string str = "时欧基乌斯侧后解 hello! 回复哦黑色的and magic粉色的圣诞袜";
    int32_t width = static_cast<int32_t>(str.length());
    int32_t outLen = 0;
    int32_t strLen = width;
    const char *result;
    std::string actual;

    result = SubstrCharWithStart<int32_t, false, false>(contextPtr, str.c_str(), width, strLen, 1, false, &outLen);
    actual = std::string(result, outLen);
    EXPECT_EQ(actual, str);
    EXPECT_EQ(outLen, strLen);

    result = SubstrCharWithStart<int32_t, false, true>(contextPtr, str.c_str(), width, strLen, 0, false, &outLen);
    actual = std::string(result, outLen);
    EXPECT_EQ(actual, str);
    EXPECT_EQ(outLen, strLen);

    result = SubstrCharWithStart<int32_t, false, false>(contextPtr, str.c_str(), width, strLen, 9, false, &outLen);
    actual = std::string(result, outLen);
    EXPECT_EQ(actual, " hello! 回复哦黑色的and magic粉色的圣诞袜");
    EXPECT_EQ(outLen, 53);

    result = SubstrCharWithStart<int32_t, false, false>(contextPtr, str.c_str(), width, strLen, -3, false, &outLen);
    actual = std::string(result, outLen);
    EXPECT_EQ(actual, "圣诞袜");
    EXPECT_EQ(outLen, 9);

    result = SubstrCharWithStart<int32_t, false, false>(contextPtr, str.c_str(), width, strLen, 0, false, &outLen);
    actual = std::string(result, outLen);
    EXPECT_EQ(actual, "");
    EXPECT_EQ(outLen, 0);

    result = SubstrCharWithStart<int32_t, false, false>(contextPtr, str.c_str(), width, strLen, 37, false, &outLen);
    actual = std::string(result, outLen);
    EXPECT_EQ(actual, "袜");
    EXPECT_EQ(outLen, 3);

    result = SubstrCharWithStart<int32_t, false, false>(contextPtr, str.c_str(), width, strLen, -38, false, &outLen);
    actual = std::string(result, outLen);
    EXPECT_EQ(actual, "");
    EXPECT_EQ(outLen, 0);

    result = SubstrCharWithStart<int32_t, false, false>(contextPtr, str.c_str(), width, strLen, -37, false, &outLen);
    actual = std::string(result, outLen);
    EXPECT_EQ(actual, str);
    EXPECT_EQ(outLen, strLen);

    delete context;
}

TEST(FunctionTest, ToUpperStr)
{
    auto context = new ExecutionContext();
    int64_t contextptr = reinterpret_cast<int64_t>(context);
    std::string test = "[\\]^_abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ{|}.";
    std::string expected = "[\\]^_ABCDEFGHIJKLMNOPQRSTUVWXYZ ABCDEFGHIJKLMNOPQRSTUVWXYZ{|}.";
    int32_t outLen = 0;
    const char *result = ToUpperStr(contextptr, test.c_str(), static_cast<int32_t>(test.length()), false, &outLen);
    std::string actual = std::string(result, outLen);
    EXPECT_EQ(actual, expected);
    EXPECT_EQ(outLen, 62);
    delete context;
}

TEST(FunctionTest, ToUpperChar)
{
    auto context = new ExecutionContext();
    int64_t contextptr = reinterpret_cast<int64_t>(context);
    std::string test = "[\\]^_abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ{|}.";
    std::string expected = "[\\]^_ABCDEFGHIJKLMNOPQRSTUVWXYZ ABCDEFGHIJKLMNOPQRSTUVWXYZ{|}.";
    int32_t width = 100;
    int32_t outLen = 0;
    const char *result =
        ToUpperChar(contextptr, test.c_str(), width, static_cast<int32_t>(test.length()), false, &outLen);
    std::string actual = std::string(result, outLen);
    EXPECT_EQ(actual, expected);
    EXPECT_EQ(outLen, 62);
    delete context;
}

TEST(FunctionTest, ToLowerStr)
{
    auto context = new ExecutionContext();
    int64_t contextPtr = reinterpret_cast<int64_t>(context);
    std::string test = "[\\]^_abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ{|}.";
    std::string expected = "[\\]^_abcdefghijklmnopqrstuvwxyz abcdefghijklmnopqrstuvwxyz{|}.";
    int32_t outLen = 0;
    const char *result = ToLowerStr(contextPtr, test.c_str(), static_cast<int32_t>(test.length()), false, &outLen);
    std::string actual = std::string(result, outLen);
    EXPECT_EQ(actual, expected);
    EXPECT_EQ(outLen, 62);
    delete context;
}

TEST(FunctionTest, ToLowerChar)
{
    auto context = new ExecutionContext();
    int64_t contextPtr = reinterpret_cast<int64_t>(context);
    std::string test = "[\\]^_abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ{|}.";
    std::string expected = "[\\]^_abcdefghijklmnopqrstuvwxyz abcdefghijklmnopqrstuvwxyz{|}.";
    int32_t width = 100;
    int32_t outLen = 0;
    const char *result =
        ToLowerChar(contextPtr, test.c_str(), width, static_cast<int32_t>(test.length()), false, &outLen);
    std::string actual = std::string(result, outLen);
    EXPECT_EQ(actual, expected);
    EXPECT_EQ(outLen, 62);
    delete context;
}

TEST(FunctionTest, StrCompare)
{
    int result = StrCompare("abcd EFGH 123 $%^", 17, "abcd EFGH 123 $%^", 17);
    EXPECT_EQ(result, std::string("abcd EFGH 123 $%^").compare(std::string("abcd EFGH 123 $%^")));

    result = StrCompare("five", 4, "four", 4);
    EXPECT_EQ(result, std::string("five").compare(std::string("four")));

    result = StrCompare("five", 4, "FIVE", 4);
    EXPECT_EQ(result, std::string("five").compare(std::string("FIVE")));

    result = StrCompare("test", 4, "testing", 7);
    EXPECT_EQ(result, std::string("test").compare(std::string("testing")));

    result = StrCompare("racecar", 7, "race", 4);
    EXPECT_EQ(result, std::string("racecar").compare(std::string("race")));
}

TEST(FunctionTest, LikeStr)
{
    bool result = LikeStr("hello", 5, "hello", 5, false);
    EXPECT_TRUE(result);

    result = LikeStr("regex", 5, "rege(x(es)?|xps?)", 17, false);
    EXPECT_TRUE(result);

    result = LikeStr("20500", 5, "\\d{5}(-\\d{4})?", 14, false);
    EXPECT_TRUE(result);
}

TEST(FunctionTest, ConcatStrStr)
{
    auto context = new ExecutionContext();
    int64_t contextptr = reinterpret_cast<int64_t>(context);
    int outlen = 0;
    const char *result;
    std::string actual;

    result = ConcatStrStr(contextptr, "abc", 3, "defghi", 6, false, &outlen);
    actual = std::string(result, outlen);
    EXPECT_EQ(actual, "abcdefghi");
    EXPECT_EQ(outlen, 9);

    result = ConcatStrStr(contextptr, "hello", 5, "", 0, false, &outlen);
    actual = std::string(result, outlen);
    EXPECT_EQ(actual, "hello");
    EXPECT_EQ(outlen, 5);

    result = ConcatStrStr(contextptr, "", 0, "", 0, false, &outlen);
    actual = std::string(result, outlen);
    EXPECT_EQ(actual, "");
    EXPECT_EQ(outlen, 0);
    delete context;
}

TEST(FunctionTest, Instr)
{
    int32_t result = InStr("", 0, "", 0, true);
    EXPECT_EQ(result, 0);
    result = InStr("", 0, "abc", 3, true);
    EXPECT_EQ(result, 0);
    result = InStr("abc", 3, "", 0, true);
    EXPECT_EQ(result, 0);
    result = InStr("abc", 3, "abcd", 4, false);
    EXPECT_EQ(result, 0);
    result = InStr("abc", 3, "bd", 2, false);
    EXPECT_EQ(result, 0);
    result = InStr("abc", 3, "bc", 2, false);
    EXPECT_EQ(result, 2);
    result = InStr("", 0, "ab", 2, false);
    EXPECT_EQ(result, 0);
    result = InStr("abc", 3, "", 0, false);
    EXPECT_EQ(result, 1);
    result = InStr("", 0, "", 0, false);
    EXPECT_EQ(result, 1);
    std::string srcStr = "一丁丂七丄丅丆万丈三上下丌不与丏";
    std::string subStr = "万丈";
    result = InStr(srcStr.c_str(), static_cast<int32_t>(srcStr.length()), subStr.c_str(),
        static_cast<int32_t>(subStr.length()), false);
    EXPECT_EQ(result, 8);
    srcStr = "壹貳叁肆伍";
    subStr = "叁肆";
    result = InStr(srcStr.c_str(), static_cast<int32_t>(srcStr.length()), subStr.c_str(),
        static_cast<int32_t>(subStr.length()), false);
    EXPECT_EQ(result, 3);
}

TEST(FunctionTest, StartsWithStr)
{
    bool result = StartsWithStr("", 0, "", 0, true);
    EXPECT_EQ(result, false);
    result = StartsWithStr("", 0, "abc", 3, true);
    EXPECT_EQ(result, false);
    result = StartsWithStr("abc", 3, "", 0, true);
    EXPECT_EQ(result, false);
    result = StartsWithStr("abc", 3, "abcd", 4, false);
    EXPECT_EQ(result, false);
    result = StartsWithStr("abc", 3, "bd", 2, false);
    EXPECT_EQ(result, false);
    result = StartsWithStr("abc", 3, "ab", 2, false);
    EXPECT_EQ(result, true);
    result = StartsWithStr("", 0, "ab", 2, false);
    EXPECT_EQ(result, false);
    result = StartsWithStr("abc", 3, "", 0, false);
    EXPECT_EQ(result, true);
    result = StartsWithStr("", 0, "", 0, false);
    EXPECT_EQ(result, true);
}

TEST(FunctionTest, EndsWithStr)
{
    bool result = EndsWithStr("", 0, "", 0, true);
    EXPECT_EQ(result, false);
    result = EndsWithStr("", 0, "abc", 3, true);
    EXPECT_EQ(result, false);
    result = EndsWithStr("abc", 3, "", 0, true);
    EXPECT_EQ(result, false);
    result = EndsWithStr("abc", 3, "abcd", 4, false);
    EXPECT_EQ(result, false);
    result = EndsWithStr("abc", 3, "bd", 2, false);
    EXPECT_EQ(result, false);
    result = EndsWithStr("abc", 3, "bc", 2, false);
    EXPECT_EQ(result, true);
    result = EndsWithStr("", 0, "ab", 2, false);
    EXPECT_EQ(result, false);
    result = EndsWithStr("abc", 3, "", 0, false);
    EXPECT_EQ(result, true);
    result = EndsWithStr("", 0, "", 0, false);
    EXPECT_EQ(result, true);
}

// Cast
TEST(FunctionTest, CastStringToDate)
{
    ConfigUtil::SetStringToDateFormatRule(StringToDateFormatRule::ALLOW_REDUCED_PRECISION);
    // year-month-day
    auto context = new ExecutionContext();
    auto contextPtr = reinterpret_cast<int64_t>(context);
    int32_t result = CastStringToDateAllowReducePrecison(contextPtr, "1970-01-03", 10, false);
    EXPECT_EQ(result, 2);
    result = CastStringToDateAllowReducePrecison(contextPtr, "1969-12-31", 10, false);
    EXPECT_EQ(result, -1);
    result = CastStringToDateAllowReducePrecison(contextPtr, "1980-01-01", 10, false);
    EXPECT_EQ(result, 3652);
    result = CastStringToDateAllowReducePrecison(contextPtr, "1980-01-01 12345", 16, false);
    EXPECT_EQ(result, 3652);
    result = CastStringToDateAllowReducePrecison(contextPtr, "1980-1-1", 8, false);
    EXPECT_EQ(result, 3652);
    result = CastStringToDateAllowReducePrecison(contextPtr, "1980-1-01", 9, false);
    EXPECT_EQ(result, 3652);
    result = CastStringToDateAllowReducePrecison(contextPtr, "1980-1-1 123", 12, false);
    EXPECT_EQ(result, 3652);
    result = CastStringToDateAllowReducePrecison(contextPtr, "1980-01-1", 9, false);
    EXPECT_EQ(result, 3652);
    result = CastStringToDateAllowReducePrecison(contextPtr, "1980-01", 7, false);
    EXPECT_EQ(result, 3652);
    result = CastStringToDateAllowReducePrecison(contextPtr, "1980", 4, false);
    EXPECT_EQ(result, 3652);
    result = CastStringToDateAllowReducePrecison(contextPtr, "1453-05-29", 10, false);
    EXPECT_EQ(result, -188682);
    result = CastStringToDateAllowReducePrecison(contextPtr, "   1453-05-29   ", 16, false);
    EXPECT_EQ(result, -188682);
    result = CastStringToDateAllowReducePrecison(contextPtr, "   1 453-05-29   ", 16, false);
    EXPECT_EQ(result, -1);
    result = CastStringToDateAllowReducePrecison(contextPtr, " 145", 4, false);
    EXPECT_EQ(result, -1);
    result = CastStringToDateAllowReducePrecison(contextPtr, "-145", 4, false);
    EXPECT_EQ(result, -1);

    result = CastStringToDateAllowReducePrecison(contextPtr, "1996-09  ", 9, false);
    EXPECT_EQ(result, 9740);
    result = CastStringToDateAllowReducePrecison(contextPtr, "1996-09-30", 10, false);
    EXPECT_EQ(result, 9769);

    bool isNull = false;
    result = CastStringToDateRetNullAllowReducePrecison(&isNull, "   1453- 05-29    ", 16);
    EXPECT_EQ(result, -1);
    result = CastStringToDateRetNullAllowReducePrecison(&isNull, "1453-05-29", 10);
    EXPECT_EQ(result, -188682);
    result = CastStringToDateRetNullAllowReducePrecison(&isNull, "   1453-05-29   ", 16);
    EXPECT_EQ(result, -188682);
    ConfigUtil::SetStringToDateFormatRule(StringToDateFormatRule::NOT_ALLOW_REDUCED_PRECISION);
    delete context;
}

TEST(FunctionTest, LengthChar)
{
    std::string test = "abcd";
    int32_t width = 10;
    auto len = LengthChar(test.c_str(), width, test.length(), false);
    EXPECT_EQ(len, 10);
}

TEST(FunctionTest, LengthStr)
{
    std::string test = "abcd";
    auto len = LengthStr(test.c_str(), test.length(), false);
    EXPECT_EQ(len, 4);
}

TEST(FunctionTest, LengthStrZh)
{
    std::string str = "时欧基乌斯侧后解 hello! 回复哦黑色的and magic粉色的圣诞袜";
    auto len = LengthStr(str.c_str(), str.length(), false);
    EXPECT_EQ(len, 37);
}

TEST(FunctionTest, CharLengthStr)
{
    std::string test = "时欧基乌斯侧后解 hello! 回复哦黑色的and magic粉色的圣诞袜";
    auto len = CharLengthStr(test.c_str(), test.length(), false);
    EXPECT_EQ(len, 37);

    std::string str = "m";
    len = CharLengthStr(str.c_str(), str.length(), false);
    EXPECT_EQ(len, 1);

    len = CharLengthStr(nullptr, 0, true);
    EXPECT_EQ(len, 0);
}

TEST(FunctionTest, CharLengthChar)
{
    std::string test = "abc       ";
    int32_t width = 10;
    auto len = CharLengthChar(test.c_str(), width, test.length(), false);
    EXPECT_EQ(len, 10);

    len = CharLengthChar(nullptr, width, 0, true);
    EXPECT_EQ(len, 0);
}

TEST(FunctionTest, ReplaceStrStrStrWithRep)
{
    auto context = new ExecutionContext();
    int64_t contextPtr = reinterpret_cast<int64_t>(context);
    int32_t outLen = 0;

    std::string str = "operator1";
    std::string searchStr = "o";
    std::string replaceStr = "**";
    auto result = ReplaceStrStrStrWithRepReplace(contextPtr, str.c_str(), str.length(), searchStr.c_str(),
        searchStr.length(), replaceStr.c_str(), replaceStr.length(), false, &outLen);
    std::string expected = "**perat**r1";
    EXPECT_EQ(outLen, 11);
    EXPECT_EQ(std::string(result, outLen), expected);

    str = "operator2";
    searchStr = "";
    replaceStr = "*";
    result = ReplaceStrStrStrWithRepReplace(contextPtr, str.c_str(), str.length(), searchStr.c_str(),
        searchStr.length(), replaceStr.c_str(), replaceStr.length(), false, &outLen);
    expected = "*o*p*e*r*a*t*o*r*2*";
    EXPECT_EQ(outLen, 19);
    EXPECT_EQ(std::string(result, outLen), expected);

    str = "operator3";
    searchStr = "era";
    replaceStr = "ER";
    result = ReplaceStrStrStrWithRepReplace(contextPtr, str.c_str(), str.length(), searchStr.c_str(),
        searchStr.length(), replaceStr.c_str(), replaceStr.length(), false, &outLen);
    expected = "opERtor3";
    EXPECT_EQ(outLen, 8);
    EXPECT_EQ(std::string(result, outLen), expected);
    delete context;
}

TEST(FunctionTest, ReplaceStrStrWithoutRep)
{
    auto context = new ExecutionContext();
    int64_t contextPtr = reinterpret_cast<int64_t>(context);
    int32_t outLen = 0;

    std::string str = "operator1";
    std::string searchStr = "o";
    auto result = ReplaceStrStrWithoutRepReplace(contextPtr, str.c_str(), str.length(), searchStr.c_str(),
        searchStr.length(), false, &outLen);
    std::string expected = "peratr1";
    EXPECT_EQ(outLen, 7);
    EXPECT_EQ(std::string(result, outLen), expected);

    str = "operator2";
    searchStr = "";
    result = ReplaceStrStrWithoutRepReplace(contextPtr, str.c_str(), str.length(), searchStr.c_str(),
        searchStr.length(), false, &outLen);
    expected = "operator2";
    EXPECT_EQ(outLen, 9);
    EXPECT_EQ(std::string(result, outLen), expected);

    str = "operator3";
    searchStr = "era";
    result = ReplaceStrStrWithoutRepReplace(contextPtr, str.c_str(), str.length(), searchStr.c_str(),
        searchStr.length(), false, &outLen);
    expected = "optor3";
    EXPECT_EQ(outLen, 6);
    EXPECT_EQ(std::string(result, outLen), expected);
    delete context;
}

TEST(FunctionTest, ReplaceStrCharStr)
{
    auto context = new ExecutionContext();
    int64_t contextPtr = reinterpret_cast<int64_t>(context);
    int32_t outLen = 0;

    std::string str[] = { "", " varchar2", "", "varchar4", "varchar5", "varchar6", "varchar7" };
    std::string searchStr[] =
                { "          ", " char200  ", "char300   ", "char400   ", "char500   ", "char600   ", "char700   " };
    std::string replaceStr[] = { "", " varchar2", "", "varchar4", "varchar5", "varchar6", "varchar7" };
    int32_t resultLen[] = { 0, 9, 0, 8, 8, 8, 8 };
    std::string expected[] = { "", " varchar2", "", "varchar4", "varchar5", "varchar6", "varchar7" };

    for (int32_t i = 0; i < 7; i++) {
        auto result = ReplaceStrStrStrWithRepReplace(contextPtr, str[i].c_str(), str[i].length(), searchStr[i].c_str(),
            searchStr[i].length(), replaceStr[i].c_str(), replaceStr[i].length(), false, &outLen);
        EXPECT_EQ(outLen, resultLen[i]);
        EXPECT_EQ(std::string(result, outLen), expected[i]);
    }
    delete context;
}

TEST(FunctionTest, ReplaceCharCharChar)
{
    auto context = new ExecutionContext();
    int64_t contextPtr = reinterpret_cast<int64_t>(context);
    int32_t outLen = 0;

    std::string str[] = { "          ", " char200  ", "          ", "char400   ", "char500   ", "char600   ",
                              "char700   " };
    std::string searchStr[] =
                { "cha1     ", " char2     ", "char3     ", "char4     ", "char5     ", "char6     ", "char7     " };
    std::string replaceStr[] =
                { "varchar100", "varchar200", "varchar300", "varchar400", "varchar500", "varchar600", "varchar700" };
    int32_t resultLen[] = { 10, 10, 10, 10, 10, 10, 10 };
    std::string expected[] =
                { "          ", " char200  ", "          ", "char400   ", "char500   ", "char600   ", "char700   " };

    for (int32_t i = 0; i < 7; i++) {
        auto result = ReplaceStrStrStrWithRepReplace(contextPtr, str[i].c_str(), str[i].length(), searchStr[i].c_str(),
            searchStr[i].length(), replaceStr[i].c_str(), replaceStr[i].length(), false, &outLen);
        EXPECT_EQ(outLen, resultLen[i]);
        EXPECT_EQ(std::string(result, outLen), expected[i]);
    }
    delete context;
}

TEST(FunctionTest, ReplaceStrStrStrZh)
{
    auto context = new ExecutionContext();
    int64_t contextPtr = reinterpret_cast<int64_t>(context);
    int32_t outLen = 0;

    std::vector<std::string> str { "", "粉色的圣诞袜", "apple", "粉色de圣诞袜" };
    std::vector<std::string> searchStr { "", "粉色", "pp", "de圣" };
    std::vector<std::string> replaceStr { "", "黑色", "*w*", "*的*" };

    auto result1 = ReplaceStrStrStrWithRepReplace(contextPtr, str[2].c_str(), str[2].length(), searchStr[0].c_str(),
        searchStr[0].length(), replaceStr[2].c_str(), replaceStr[2].length(), false, &outLen);
    std::string expected = "*w*a*w*p*w*p*w*l*w*e*w*";
    EXPECT_EQ(outLen, 23);
    EXPECT_EQ(std::string(result1, outLen), expected);

    auto result2 = ReplaceStrStrStrWithRepReplace(contextPtr, str[1].c_str(), str[1].length(), searchStr[0].c_str(),
        searchStr[0].length(), replaceStr[2].c_str(), replaceStr[2].length(), false, &outLen);
    expected = "*w*粉*w*色*w*的*w*圣*w*诞*w*袜*w*";
    EXPECT_EQ(outLen, 39);
    EXPECT_EQ(std::string(result2, outLen), expected);

    auto result3 = ReplaceStrStrStrWithRepReplace(contextPtr, str[3].c_str(), str[3].length(), searchStr[0].c_str(),
        searchStr[0].length(), replaceStr[2].c_str(), replaceStr[2].length(), false, &outLen);
    expected = "*w*粉*w*色*w*d*w*e*w*圣*w*诞*w*袜*w*";
    EXPECT_EQ(outLen, 41);
    EXPECT_EQ(std::string(result3, outLen), expected);

    auto result4 = ReplaceStrStrStrWithRepReplace(contextPtr, str[3].c_str(), str[3].length(), searchStr[0].c_str(),
        searchStr[0].length(), replaceStr[3].c_str(), replaceStr[3].length(), false, &outLen);
    expected = "*的*粉*的*色*的*d*的*e*的*圣*的*诞*的*袜*的*";
    EXPECT_EQ(outLen, 57);
    EXPECT_EQ(std::string(result4, outLen), expected);

    auto result5 = ReplaceStrStrStrWithRepReplace(contextPtr, str[3].c_str(), str[3].length(), searchStr[3].c_str(),
        searchStr[3].length(), replaceStr[3].c_str(), replaceStr[3].length(), false, &outLen);
    expected = "粉色*的*诞袜";
    EXPECT_EQ(outLen, 17);
    EXPECT_EQ(std::string(result5, outLen), expected);

    auto result6 = ReplaceStrStrStrWithRepReplace(contextPtr, str[0].c_str(), str[0].length(), searchStr[0].c_str(),
        searchStr[0].length(), replaceStr[0].c_str(), replaceStr[0].length(), false, &outLen);
    expected = "";
    EXPECT_EQ(outLen, 0);
    EXPECT_EQ(std::string(result6, outLen), expected);

    auto result7 = ReplaceStrStrStrWithRepReplace(contextPtr, str[3].c_str(), str[3].length(), searchStr[0].c_str(),
        searchStr[0].length(), replaceStr[0].c_str(), replaceStr[0].length(), false, &outLen);
    expected = "粉色de圣诞袜";
    EXPECT_EQ(outLen, 17);
    EXPECT_EQ(std::string(result7, outLen), expected);
    delete context;
}

TEST(FunctionTest, ConcatStrStrZh)
{
    auto context = new ExecutionContext();
    int64_t contextPtr = reinterpret_cast<int64_t>(context);
    int outLen = 0;
    const char *result;
    std::string actual;

    result = ConcatStrStr(contextPtr, "你是Chinese?", 14, "Yes我是", 9, false, &outLen);
    actual = std::string(result, outLen);
    EXPECT_EQ(actual, "你是Chinese?Yes我是");
    EXPECT_EQ(outLen, 23);
    delete context;
}

TEST(FunctionTest, ConcatCharCharZh)
{
    auto context = new ExecutionContext();
    int64_t contextPtr = reinterpret_cast<int64_t>(context);
    int32_t outLen = 0;
    const char *result;
    std::string actual;

    result = ConcatCharChar(contextPtr, "粉色de圣诞袜", 7, 17, "*黑色*", 4, 8, false, &outLen);
    actual = std::string(result, outLen);
    EXPECT_EQ(actual, "粉色de圣诞袜*黑色*");
    EXPECT_EQ(outLen, 25);

    result = ConcatCharChar(contextPtr, "Hei你好吗", 8, 12, "Oh我很好", 8, 11, false, &outLen);
    actual = std::string(result, outLen);
    EXPECT_EQ(actual, "Hei你好吗  Oh我很好");
    EXPECT_EQ(outLen, 25);

    result = ConcatCharChar(contextPtr, "Hei你好吗   ", 10, 15, "Oh我很好  ", 8, 13, false, &outLen);
    actual = std::string(result, outLen);
    EXPECT_EQ(actual, "Hei你好吗    Oh我很好  ");
    EXPECT_EQ(outLen, 29);

    result = ConcatCharChar(contextPtr, "   Hei你好吗", 12, 15, "   Oh我很好", 12, 14, false, &outLen);
    actual = std::string(result, outLen);
    EXPECT_EQ(actual, "   Hei你好吗      Oh我很好");
    EXPECT_EQ(outLen, 32);

    result = ConcatCharChar(contextPtr, "Hei   你好吗", 12, 15, "Oh   我很好", 8, 14, false, &outLen);
    actual = std::string(result, outLen);
    EXPECT_EQ(actual, "Hei   你好吗   Oh   我很好");
    EXPECT_EQ(outLen, 32);

    result = ConcatCharChar(contextPtr, "   ", 5, 3, "Oh我很好   ", 12, 14, false, &outLen);
    actual = std::string(result, outLen);
    EXPECT_EQ(actual, "     Oh我很好   ");
    EXPECT_EQ(outLen, 19);

    result = ConcatCharChar(contextPtr, "Hei你好吗", 8, 12, "   ", 5, 3, false, &outLen);
    actual = std::string(result, outLen);
    EXPECT_EQ(actual, "Hei你好吗     ");
    EXPECT_EQ(outLen, 17);

    result = ConcatCharChar(contextPtr, "Hei你好吗", 8, 12, "", 5, 0, false, &outLen);
    actual = std::string(result, outLen);
    EXPECT_EQ(actual, "Hei你好吗");
    EXPECT_EQ(outLen, 12);
    delete context;
}

TEST(FunctionTest, ConcatCharStrZh)
{
    auto context = new ExecutionContext();
    int64_t contextPtr = reinterpret_cast<int64_t>(context);
    int outLen = 0;
    const char *result;
    std::string actual;

    result = ConcatCharStr(contextPtr, "*你是谁呢*", 6, 14, "我很OK", 8, false, &outLen);
    actual = std::string(result, outLen);
    EXPECT_EQ(actual, "*你是谁呢*我很OK");
    EXPECT_EQ(outLen, 22);

    result = ConcatCharStr(contextPtr, "*你是谁呢*", 10, 14, "我很OK", 8, false, &outLen);
    actual = std::string(result, outLen);
    EXPECT_EQ(actual, "*你是谁呢*    我很OK");
    EXPECT_EQ(outLen, 26);
    delete context;
}

TEST(FunctionTest, ConcatStrCharZh)
{
    auto context = new ExecutionContext();
    int64_t contextPtr = reinterpret_cast<int64_t>(context);
    int outLen = 0;
    const char *result;
    std::string actual;

    result = ConcatStrChar(contextPtr, "粉色de圣诞袜", 17, "*黑色*", 4, 8, false, &outLen);
    actual = std::string(result, outLen);
    EXPECT_EQ(actual, "粉色de圣诞袜*黑色*");
    EXPECT_EQ(outLen, 25);

    result = ConcatStrChar(contextPtr, "粉色de圣诞袜", 17, "*黑色*", 6, 8, false, &outLen);
    actual = std::string(result, outLen);
    EXPECT_EQ(actual, "粉色de圣诞袜*黑色*");
    EXPECT_EQ(outLen, 25);
    delete context;
}

TEST(FunctionTest, LikeStrZh)
{
    std::string str = "时欧基乌斯侧后解 hello! 回复哦黑色的and magic粉色的圣诞袜";
    // like "xxx_"
    std::string pattern = "^时欧基乌斯侧后解 hello! 回复哦黑色的and magic粉色的圣诞.$";
    bool isMatch = LikeStr(str.c_str(), str.length(), pattern.c_str(), pattern.length(), false);
    EXPECT_TRUE(isMatch);
    pattern = "^时欧基乌斯侧后解 hello! 回复哦黑色的and magic粉色的圣诞..$";
    isMatch = LikeStr(str.c_str(), str.length(), pattern.c_str(), pattern.length(), false);
    EXPECT_FALSE(isMatch);

    // like "xxx%"
    pattern = "^时欧基乌斯侧后解 hello! 回复哦黑色的and magic粉色的圣.*$";
    isMatch = LikeStr(str.c_str(), str.length(), pattern.c_str(), pattern.length(), false);
    EXPECT_TRUE(isMatch);
    pattern = "^欧时基乌斯侧后解 hello! 回复哦黑色的and magic粉色的圣诞.*$";
    isMatch = LikeStr(str.c_str(), str.length(), pattern.c_str(), pattern.length(), false);
    EXPECT_FALSE(isMatch);
}

TEST(FunctionTest, LikeCharZh)
{
    // like "xxx_"
    std::string str = "时欧基乌斯侧后解 hello! 回复哦黑色的and magic粉色的圣诞袜";
    std::string pattern = "^时欧基乌斯侧后解 hello! 回复哦黑色的and magic粉色的圣诞.$";
    bool isMatch = LikeChar(str.c_str(), 37, str.length(), pattern.c_str(), pattern.length(), false);
    EXPECT_TRUE(isMatch);

    pattern = "^时欧基乌..$";
    str = "时欧基乌";
    isMatch = LikeChar(str.c_str(), 6, str.length(), pattern.c_str(), pattern.length(), false);
    EXPECT_TRUE(isMatch);

    pattern = "^时欧基乌.$";
    str = "时欧基乌";
    isMatch = LikeChar(str.c_str(), 6, str.length(), pattern.c_str(), pattern.length(), false);
    EXPECT_FALSE(isMatch);

    // like "xxx%"
    pattern = "^时欧基乌.*$";
    str = "时欧基乌";
    isMatch = LikeChar(str.c_str(), 6, str.length(), pattern.c_str(), pattern.length(), false);
    EXPECT_TRUE(isMatch);
}

TEST(FunctionTest, CastStringToLong)
{
    auto context = new ExecutionContext();
    auto contextPtr = reinterpret_cast<int64_t>(context);
    std::string s = "23423";
    int64_t result = CastStringToLong(contextPtr, s.c_str(), static_cast<int32_t>(s.size()), false);

    EXPECT_EQ(result, 23423);
    s = "100123";
    result = CastStringToLong(contextPtr, s.c_str(), static_cast<int32_t>(s.size()), false);
    EXPECT_EQ(result, 100123);
    s = "-10078";
    result = CastStringToLong(contextPtr, s.c_str(), static_cast<int32_t>(s.size()), false);
    EXPECT_EQ(result, -10078);
    s = "123.123";
    result = CastStringToLong(contextPtr, s.c_str(), static_cast<int32_t>(s.size()), false);
    EXPECT_EQ(result, 0);
    s = "9223372036854775807";
    result = CastStringToLong(contextPtr, s.c_str(), static_cast<int32_t>(s.size()), false);
    EXPECT_EQ(result, 922'3372'0368'5477'5807);
    s = "9223372036854775808";
    result = CastStringToLong(contextPtr, s.c_str(), static_cast<int32_t>(s.size()), false);
    EXPECT_EQ(result, 0);
    s = "-9223372036854775808";
    result = CastStringToLong(contextPtr, s.c_str(), static_cast<int32_t>(s.size()), false);
    EXPECT_EQ(result, INT64_MIN);
    delete context;
}

TEST(FunctionTest, CastStringToInt)
{
    auto context = new ExecutionContext();
    auto contextPtr = reinterpret_cast<int64_t>(context);

    std::string s = " 23423 ";
    int32_t result = CastStringToInt(contextPtr, s.c_str(), static_cast<int32_t>(s.size()), false);
    EXPECT_EQ(result, 23423);
    s = "100123";
    result = CastStringToInt(contextPtr, s.c_str(), static_cast<int32_t>(s.size()), false);
    EXPECT_EQ(result, 100123);
    s = "123.123";
    result = CastStringToInt(contextPtr, s.c_str(), static_cast<int32_t>(s.size()), false);
    EXPECT_EQ(result, 0);
    s = "2147483648";
    result = CastStringToInt(contextPtr, s.c_str(), static_cast<int32_t>(s.size()), false);
    EXPECT_EQ(result, 0);
    s = "2a147483648";
    result = CastStringToInt(contextPtr, s.c_str(), static_cast<int32_t>(s.size()), false);
    EXPECT_TRUE(context->HasError());
    context->ResetError();
    s = " -10078 ";
    result = CastStringToInt(contextPtr, s.c_str(), static_cast<int32_t>(s.size()), false);
    EXPECT_EQ(result, -10078);
    EXPECT_FALSE(context->HasError());
    s = "2123123123147483648";
    result = CastStringToInt(contextPtr, s.c_str(), static_cast<int32_t>(s.size()), false);
    EXPECT_TRUE(context->HasError());
    context->ResetError();
    s = "-2123123123147483648";
    result = CastStringToInt(contextPtr, s.c_str(), static_cast<int32_t>(s.size()), false);
    EXPECT_TRUE(context->HasError());
    context->ResetError();
    s = "-2123123123147-483648";
    result = CastStringToInt(contextPtr, s.c_str(), static_cast<int32_t>(s.size()), false);
    EXPECT_TRUE(context->HasError());
    delete context;
}

TEST(FunctionTest, CastStringToIntRetNull)
{
    bool isNull = false;
    std::string s = "23423";
    int32_t result = CastStringToIntRetNull(&isNull, s.c_str(), static_cast<int32_t>(s.size()));
    EXPECT_EQ(result, 23423);
    EXPECT_FALSE(isNull);
    s = "100123";
    result = CastStringToIntRetNull(&isNull, s.c_str(), static_cast<int32_t>(s.size()));
    EXPECT_EQ(result, 100123);
    EXPECT_FALSE(isNull);
    s = "123.123";
    result = CastStringToIntRetNull(&isNull, s.c_str(), static_cast<int32_t>(s.size()));
    EXPECT_EQ(result, 123);
    EXPECT_FALSE(isNull);
    s = "2147483648";
    result = CastStringToIntRetNull(&isNull, s.c_str(), static_cast<int32_t>(s.size()));
    EXPECT_TRUE(isNull);
    s = "2a147483648";
    result = CastStringToIntRetNull(&isNull, s.c_str(), static_cast<int32_t>(s.size()));
    EXPECT_TRUE(isNull);
    s = "-10078";
    result = CastStringToIntRetNull(&isNull, s.c_str(), static_cast<int32_t>(s.size()));
    EXPECT_EQ(result, -10078);
    EXPECT_FALSE(isNull);
    s = "2123123123147483648";
    result = CastStringToIntRetNull(&isNull, s.c_str(), static_cast<int32_t>(s.size()));
    EXPECT_TRUE(isNull);
    s = "-2123123123147483648";
    result = CastStringToIntRetNull(&isNull, s.c_str(), static_cast<int32_t>(s.size()));
    EXPECT_TRUE(isNull);
    s = "-2123123123147-483648";
    result = CastStringToIntRetNull(&isNull, s.c_str(), static_cast<int32_t>(s.size()));
    EXPECT_TRUE(isNull);
    s = "+45";
    result = CastStringToIntRetNull(&isNull, s.c_str(), static_cast<int32_t>(s.size()));
    EXPECT_EQ(result, 45);
    EXPECT_FALSE(isNull);
    s = "-45";
    result = CastStringToIntRetNull(&isNull, s.c_str(), static_cast<int32_t>(s.size()));
    EXPECT_EQ(result, -45);
    EXPECT_FALSE(isNull);
    s = "3.14159";
    result = CastStringToIntRetNull(&isNull, s.c_str(), static_cast<int32_t>(s.size()));
    EXPECT_EQ(result, 3);
    EXPECT_FALSE(isNull);
    s = "31337 with words";
    result = CastStringToIntRetNull(&isNull, s.c_str(), static_cast<int32_t>(s.size()));
    EXPECT_TRUE(isNull);
    s = "+12345678901";
    result = CastStringToIntRetNull(&isNull, s.c_str(), static_cast<int32_t>(s.size()));
    EXPECT_TRUE(isNull);
    s = "-12345678901";
    result = CastStringToIntRetNull(&isNull, s.c_str(), static_cast<int32_t>(s.size()));
    EXPECT_TRUE(isNull);
    s = "2147483647.2";
    result = CastStringToIntRetNull(&isNull, s.c_str(), static_cast<int32_t>(s.size()));
    EXPECT_EQ(result, 2147483647);
    EXPECT_FALSE(isNull);
    s = "2147483648.2";
    result = CastStringToIntRetNull(&isNull, s.c_str(), static_cast<int32_t>(s.size()));
    EXPECT_TRUE(isNull);
    s = "     2147483647.2    ";
    result = CastStringToIntRetNull(&isNull, s.c_str(), static_cast<int32_t>(s.size()));
    EXPECT_EQ(result, 2147483647);
    EXPECT_FALSE(isNull);
    s = "    a 2147483647.2    ";
    result = CastStringToIntRetNull(&isNull, s.c_str(), static_cast<int32_t>(s.size()));
    EXPECT_TRUE(isNull);
    s = "     2147483647.2   a ";
    result = CastStringToIntRetNull(&isNull, s.c_str(), static_cast<int32_t>(s.size()));
    EXPECT_TRUE(isNull);
    s = ".";
    result = CastStringToIntRetNull(&isNull, s.c_str(), static_cast<int32_t>(s.size()));
    EXPECT_EQ(result, 0);
    EXPECT_FALSE(isNull);
    s = ".2";
    result = CastStringToIntRetNull(&isNull, s.c_str(), static_cast<int32_t>(s.size()));
    EXPECT_EQ(result, 0);
    EXPECT_FALSE(isNull);
    s = "0.";
    result = CastStringToIntRetNull(&isNull, s.c_str(), static_cast<int32_t>(s.size()));
    EXPECT_EQ(result, 0);
    EXPECT_FALSE(isNull);
    s = "2.3e3";
    result = CastStringToIntRetNull(&isNull, s.c_str(), static_cast<int32_t>(s.size()));
    EXPECT_TRUE(isNull);
    s = "-1e+2";
    result = CastStringToIntRetNull(&isNull, s.c_str(), static_cast<int32_t>(s.size()));
    EXPECT_TRUE(isNull);
    s = "+.";
    result = CastStringToIntRetNull(&isNull, s.c_str(), static_cast<int32_t>(s.size()));
    EXPECT_EQ(result, 0);
    EXPECT_FALSE(isNull);
    s = "-.";
    result = CastStringToIntRetNull(&isNull, s.c_str(), static_cast<int32_t>(s.size()));
    EXPECT_EQ(result, 0);
    EXPECT_FALSE(isNull);
    s = "- .";
    result = CastStringToIntRetNull(&isNull, s.c_str(), static_cast<int32_t>(s.size()));
    EXPECT_TRUE(isNull);
    s = "";
    result = CastStringToIntRetNull(&isNull, s.c_str(), static_cast<int32_t>(s.size()));
    EXPECT_TRUE(isNull);
    s = "    ";
    result = CastStringToIntRetNull(&isNull, s.c_str(), static_cast<int32_t>(s.size()));
    EXPECT_TRUE(isNull);
    s = "  +   ";
    result = CastStringToIntRetNull(&isNull, s.c_str(), static_cast<int32_t>(s.size()));
    EXPECT_TRUE(isNull);
    s = "-";
    result = CastStringToIntRetNull(&isNull, s.c_str(), static_cast<int32_t>(s.size()));
    EXPECT_TRUE(isNull);
    s = "-123.a";
    result = CastStringToIntRetNull(&isNull, s.c_str(), static_cast<int32_t>(s.size()));
    EXPECT_TRUE(isNull);
    s = "-123.";
    result = CastStringToIntRetNull(&isNull, s.c_str(), static_cast<int32_t>(s.size()));
    EXPECT_EQ(result, -123);
}

TEST(FunctionTest, CastStringToShortRetNull)
{
    bool isNull = false;
    std::string s = "23423";
    int32_t result = CastStringToShortRetNull(&isNull, s.c_str(), static_cast<int32_t>(s.size()));
    EXPECT_EQ(result, 23423);
    EXPECT_FALSE(isNull);
    s = "123.123";
    result = CastStringToShortRetNull(&isNull, s.c_str(), static_cast<int32_t>(s.size()));
    EXPECT_EQ(result, 123);
    EXPECT_FALSE(isNull);
    s = "2a147483648";
    result = CastStringToShortRetNull(&isNull, s.c_str(), static_cast<int32_t>(s.size()));
    EXPECT_TRUE(isNull);
    s = "-10078";
    result = CastStringToShortRetNull(&isNull, s.c_str(), static_cast<int32_t>(s.size()));
    EXPECT_EQ(result, -10078);
    EXPECT_FALSE(isNull);
    s = "2123123123147483648";
    result = CastStringToShortRetNull(&isNull, s.c_str(), static_cast<int32_t>(s.size()));
    EXPECT_TRUE(isNull);
    s = "-2123123123147483648";
    result = CastStringToShortRetNull(&isNull, s.c_str(), static_cast<int32_t>(s.size()));
    EXPECT_TRUE(isNull);
    s = "-2123123123147-483648";
    result = CastStringToShortRetNull(&isNull, s.c_str(), static_cast<int32_t>(s.size()));
    EXPECT_TRUE(isNull);
    s = "+45";
    result = CastStringToShortRetNull(&isNull, s.c_str(), static_cast<int32_t>(s.size()));
    EXPECT_EQ(result, 45);
    EXPECT_FALSE(isNull);
    s = "-45";
    result = CastStringToShortRetNull(&isNull, s.c_str(), static_cast<int32_t>(s.size()));
    EXPECT_EQ(result, -45);
    EXPECT_FALSE(isNull);
    s = "3.14159";
    result = CastStringToShortRetNull(&isNull, s.c_str(), static_cast<int32_t>(s.size()));
    EXPECT_EQ(result, 3);
    EXPECT_FALSE(isNull);
}

TEST(FunctionTest, CastStringToByteRetNull)
{
    bool isNull = false;
    std::string s = "123";
    int8_t result = CastStringToByteRetNull(&isNull, s.c_str(), static_cast<int32_t>(s.size()));
    EXPECT_EQ(result, 123);
    EXPECT_FALSE(isNull);
    s = "123.123";
    result = CastStringToByteRetNull(&isNull, s.c_str(), static_cast<int32_t>(s.size()));
    EXPECT_EQ(result, 123);
    EXPECT_FALSE(isNull);
    s = "2147483648";
    result = CastStringToByteRetNull(&isNull, s.c_str(), static_cast<int32_t>(s.size()));
    EXPECT_TRUE(isNull);
    s = "2a147483648";
    result = CastStringToByteRetNull(&isNull, s.c_str(), static_cast<int32_t>(s.size()));
    EXPECT_TRUE(isNull);
    s = "2123123123147483648";
    result = CastStringToByteRetNull(&isNull, s.c_str(), static_cast<int32_t>(s.size()));
    EXPECT_TRUE(isNull);
    s = "-2123123123147483648";
    result = CastStringToIntRetNull(&isNull, s.c_str(), static_cast<int32_t>(s.size()));
    EXPECT_TRUE(isNull);
    s = "-2123123123147-483648";
    result = CastStringToByteRetNull(&isNull, s.c_str(), static_cast<int32_t>(s.size()));
    EXPECT_TRUE(isNull);
    s = "+45";
    result = CastStringToByteRetNull(&isNull, s.c_str(), static_cast<int32_t>(s.size()));
    EXPECT_EQ(result, 45);
    EXPECT_FALSE(isNull);
    s = "-45";
    result = CastStringToByteRetNull(&isNull, s.c_str(), static_cast<int32_t>(s.size()));
    EXPECT_EQ(result, -45);
    EXPECT_FALSE(isNull);
}

TEST(FunctionTest, CastStringToLongRetNull)
{
    bool isNull = false;
    std::string s = "23423";
    int64_t result = CastStringToLongRetNull(&isNull, s.c_str(), static_cast<int32_t>(s.size()));
    EXPECT_EQ(result, 23423);
    EXPECT_FALSE(isNull);
    s = "123.123";
    result = CastStringToLongRetNull(&isNull, s.c_str(), static_cast<int32_t>(s.size()));
    EXPECT_EQ(result, 123);
    EXPECT_FALSE(isNull);
    s = "2147483648";
    result = CastStringToLongRetNull(&isNull, s.c_str(), static_cast<int32_t>(s.size()));
    EXPECT_EQ(result, 2147483648);
    EXPECT_FALSE(isNull);
    s = "2a147483648";
    result = CastStringToLongRetNull(&isNull, s.c_str(), static_cast<int32_t>(s.size()));
    EXPECT_TRUE(isNull);
    s = "-10078";
    result = CastStringToLongRetNull(&isNull, s.c_str(), static_cast<int32_t>(s.size()));
    EXPECT_EQ(result, -10078);
    EXPECT_FALSE(isNull);
    s = std::to_string(std::numeric_limits<int64_t>::min());
    result = CastStringToLongRetNull(&isNull, s.c_str(), static_cast<int32_t>(s.size()));
    EXPECT_EQ(result, std::numeric_limits<int64_t>::min());
    EXPECT_FALSE(isNull);
    s = std::to_string(std::numeric_limits<int64_t>::max());
    result = CastStringToLongRetNull(&isNull, s.c_str(), static_cast<int32_t>(s.size()));
    EXPECT_EQ(result, std::numeric_limits<int64_t>::max());
    EXPECT_FALSE(isNull);
    s = std::to_string(std::numeric_limits<uint64_t>::max());
    result = CastStringToLongRetNull(&isNull, s.c_str(), static_cast<int32_t>(s.size()));
    EXPECT_TRUE(isNull);
    s = "-9223372036854775808";
    result = CastStringToLongRetNull(&isNull, s.c_str(), static_cast<int32_t>(s.size()));
    EXPECT_EQ(result, INT64_MIN);
    EXPECT_FALSE(isNull);
    s = "9223372036854775807";
    result = CastStringToLongRetNull(&isNull, s.c_str(), static_cast<int32_t>(s.size()));
    EXPECT_EQ(result, INT64_MAX);
    EXPECT_FALSE(isNull);
    s = "-9223372036854775818";
    result = CastStringToLongRetNull(&isNull, s.c_str(), static_cast<int32_t>(s.size()));
    EXPECT_TRUE(isNull);
    s = "9223372036854775817";
    result = CastStringToLongRetNull(&isNull, s.c_str(), static_cast<int32_t>(s.size()));
    EXPECT_TRUE(isNull);
    s = "-2123123123147-483648";
    result = CastStringToLongRetNull(&isNull, s.c_str(), static_cast<int32_t>(s.size()));
    EXPECT_TRUE(isNull);
    s = "     2147483647.2    ";
    result = CastStringToLongRetNull(&isNull, s.c_str(), static_cast<int32_t>(s.size()));
    EXPECT_EQ(result, 2147483647);
    EXPECT_FALSE(isNull);
    s = "    a 2147483647.2    ";
    result = CastStringToLongRetNull(&isNull, s.c_str(), static_cast<int32_t>(s.size()));
    EXPECT_TRUE(isNull);
    s = "     2147483647.2   a ";
    result = CastStringToLongRetNull(&isNull, s.c_str(), static_cast<int32_t>(s.size()));
    EXPECT_TRUE(isNull);
    s = ".";
    result = CastStringToLongRetNull(&isNull, s.c_str(), static_cast<int32_t>(s.size()));
    EXPECT_EQ(result, 0);
    EXPECT_FALSE(isNull);
    s = ".2";
    result = CastStringToLongRetNull(&isNull, s.c_str(), static_cast<int32_t>(s.size()));
    EXPECT_EQ(result, 0);
    EXPECT_FALSE(isNull);
    s = "0.";
    result = CastStringToLongRetNull(&isNull, s.c_str(), static_cast<int32_t>(s.size()));
    EXPECT_EQ(result, 0);
    EXPECT_FALSE(isNull);
    s = "2.3e3";
    result = CastStringToLongRetNull(&isNull, s.c_str(), static_cast<int32_t>(s.size()));
    EXPECT_TRUE(isNull);
    s = "-1e+2";
    result = CastStringToLongRetNull(&isNull, s.c_str(), static_cast<int32_t>(s.size()));
    EXPECT_TRUE(isNull);
}

TEST(FunctionTest, CastStringToDouble)
{
    auto context = new ExecutionContext();
    auto contextPtr = reinterpret_cast<int64_t>(context);
    std::string s = "23423";
    double result = CastStringToDouble(contextPtr, s.c_str(), static_cast<int32_t>(s.size()), false);
    EXPECT_EQ(result, 23423);
    s = "100123";
    result = CastStringToDouble(contextPtr, s.c_str(), static_cast<int32_t>(s.size()), false);
    EXPECT_EQ(result, 100123);
    s = "-10078";
    result = CastStringToDouble(contextPtr, s.c_str(), static_cast<int32_t>(s.size()), false);
    EXPECT_EQ(result, -10078);
    s = "-923.4123";
    result = CastStringToDouble(contextPtr, s.c_str(), static_cast<int32_t>(s.size()), false);
    EXPECT_EQ(result, -923.4123);
    s = "123.123";
    result = CastStringToDouble(contextPtr, s.c_str(), static_cast<int32_t>(s.size()), false);
    EXPECT_EQ(result, 123.123);
    s = "-10.11";
    result = CastStringToDouble(contextPtr, s.c_str(), static_cast<int32_t>(s.size()), false);
    EXPECT_EQ(result, -10.11);
    s = "999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999";
    result = CastStringToDouble(contextPtr, s.c_str(), static_cast<int32_t>(s.size()), false);
    EXPECT_EQ(result, 1e+108);
    s = "1.111e202";
    result = CastStringToDouble(contextPtr, s.c_str(), static_cast<int32_t>(s.size()), false);
    EXPECT_EQ(result, 1.111e202);
    s = "1.111e-202";
    result = CastStringToDouble(contextPtr, s.c_str(), static_cast<int32_t>(s.size()), false);
    EXPECT_EQ(result, 1.111e-202);
    s = "62229.33";
    bool isNull = false;
    result = CastStringToDoubleRetNull(&isNull, s.c_str(), static_cast<int32_t>(s.size()));
    EXPECT_EQ(result, 62229.33);
    isNull = false;
    s = "1234ee231";
    result = CastStringToDoubleRetNull(&isNull, s.c_str(), static_cast<int32_t>(s.size()));
    EXPECT_TRUE(isNull);
    delete context;
}

TEST(FunctionTest, EvaluateHiveUdfSingle)
{
    auto context = new ExecutionContext();
    auto contextPtr = reinterpret_cast<int64_t>(context);
    int32_t inputTypes[] = { OMNI_INT, OMNI_INT };
    int32_t retType = OMNI_INT;
    int32_t vecCount = 2;

    int32_t inputValue[2] = { 3, 5 };
    uint8_t inputNull[2] = { 0, 0 };
    int64_t inputLength = 0;
    int32_t outputValue;
    int8_t outputNull;
    int32_t outputLength;

    using namespace omniruntime::mock;
    using namespace testing::internal;
    using testing::_;
    using testing::Assign;
    using testing::DoAll;
    using testing::Return;
    JNIEnvMock *env = CreateJNIEnvMock();
    JniUtil::SetEnv(env);

    // for InitHiveUdf
    EXPECT_CALL(*env, FindClass(_)).WillRepeatedly(Return(nullptr));
    EXPECT_CALL(*env, ExceptionCheck()).WillRepeatedly(Return(false));
    EXPECT_CALL(*env, NewGlobalRef(_)).WillRepeatedly(Return(nullptr));
    EXPECT_CALL(*env, DeleteLocalRef(_)).WillRepeatedly(Return());
    EXPECT_CALL(*env, GetStaticMethodID(_, _, _)).WillRepeatedly(Return(nullptr));
    EXPECT_CALL(*env, GetStaticFieldID(_, _, _)).WillRepeatedly(Return(nullptr));

    // for EvaluateHiveUdfSingle
    EXPECT_CALL(*env, NewStringUTF(_)).WillOnce(Return(jstring("AddIntUDF")));
    EXPECT_CALL(*env, NewObjectArray(vecCount, _, _)).WillOnce(Return(nullptr));
    EXPECT_CALL(*env, GetStaticObjectField(_, _)).WillRepeatedly(Return(nullptr));
    EXPECT_CALL(*env, SetObjectArrayElement(_, _, _)).WillRepeatedly(Return());

    InAndOutputInfos infos {};
    EXPECT_CALL(*env, CallStaticVoidMethodV(_, _, infos))
        .WillOnce(DoAll(Assign((int32_t *)(&outputValue), 8), Assign((int8_t *)(&outputNull), 0)))
        .WillRepeatedly(Return());

    EvaluateHiveUdfSingle(contextPtr, "omniruntime.udf.AddIntUDF", inputTypes, retType, vecCount,
        reinterpret_cast<int64_t>(inputValue), reinterpret_cast<int64_t>(inputNull), inputLength,
        reinterpret_cast<int64_t>(&outputValue), reinterpret_cast<int64_t>(&outputNull),
        reinterpret_cast<int64_t>(&outputLength));

    ASSERT_EQ(outputValue, 8);
    ASSERT_EQ(outputNull, 0);

    delete context;
    DestroyJNIEnvMock(env);
}

// date time functions
TEST(FunctionTest, UnixTimestampFromStr)
{
    const int32_t rowCnt = 6;
    std::string timeStrs[] = {"2024-10-12", "1948-01-12", "2023-12-09", "",
                              "1989-07-10 11:10:09", "1985-06-29 00:04:49"};
    std::string fmtStrs[] = {"%Y-%m-%d", "%Y-%m-%d", "%Y-%m-%d", "", "%Y-%m-%d %H:%M:%S", "%Y-%m-%d %H:%M:%S"};
    bool isNullTimeStr[] = {false, false, false, true, false, false};
    bool isNullFmtStr[] = {false, false, false, true, false, false};
    bool* retIsNull[rowCnt];
    for (int i = 0; i < rowCnt; ++i) {
        retIsNull[i] = new bool(false);
    }
    int64_t output[rowCnt];
    for (int32_t i = 0; i < rowCnt; i++) {
        output[i] = UnixTimestampFromStr(timeStrs[i].c_str(), timeStrs[i].length(), isNullTimeStr[i],
                                         fmtStrs[i].c_str(), fmtStrs[i].length(), isNullFmtStr[i],
                                         "Asia/Shanghai", 13, false, "CORRECTED", 9, false, retIsNull[i]);
    }
    std::vector<bool> expectIsNull = {false, false, false, true, false, false};
    bool resultIsNull[rowCnt];
    for (int32_t i = 0; i < rowCnt; i++) {
        resultIsNull[i] = *retIsNull[i];
    }
    TestUtil::AssertBoolEquals(expectIsNull, resultIsNull);
    std::vector<int64_t> result(output, output + rowCnt);
    std::vector<int64_t> expect = { 1728662400, -693388800, 1702051200, 0, 616039809, 488822689 };
    TestUtil::AssertLongEquals(expect, result);
    for (int i = 0; i < rowCnt; ++i) {
    delete retIsNull[i];
    }
}

TEST(FunctionTest, UnixTimestampFromDate)
{
    const int32_t rowCnt = 3;
    int32_t dates[] = {7130, 5658, 0};
    std::string fmtStrs[] = {"%Y-%m-%d", "%Y-%m-%d", "%Y-%m-%d"};
    bool isNull[] = {false, false, false};
    int64_t output[rowCnt];
    for (int32_t i = 0; i < rowCnt; i++) {
        output[i] = UnixTimestampFromDate(dates[i], fmtStrs[i].c_str(), fmtStrs[i].length(),
                                          "Asia/Shanghai", 13, "CORRECTED", 9, isNull[i]);
    }
    std::vector<int64_t> result(output, output + rowCnt);
    std::vector<int64_t> expect = { 615999600, 488822400, -28800 };
    TestUtil::AssertLongEquals(expect, result);
}

TEST(FunctionTest, FromUnixTimeRetNull)
{
    auto context = new ExecutionContext();
    int64_t contextPtr = reinterpret_cast<int64_t>(context);
    bool isNull = false;
    std::string fmtStr = "%Y-%m-%d %H:%M:%S";
    std::string tzStr = "Asia/Shanghai";
    int32_t outlen = 0;
    char *result = nullptr;
    std::string actual;

    result = FromUnixTimeRetNull(contextPtr, &isNull, 615999600, fmtStr.c_str(), fmtStr.length(),
                                 tzStr.c_str(), tzStr.length(), &outlen);
    actual = std::string(result, outlen);
    EXPECT_EQ(actual, "1989-07-10 00:00:00");
    EXPECT_EQ(outlen, 19);

    result = FromUnixTimeRetNull(contextPtr, &isNull, 488822400, fmtStr.c_str(), fmtStr.length(),
                                 tzStr.c_str(), tzStr.length(), &outlen);
    actual = std::string(result, outlen);
    EXPECT_EQ(actual, "1985-06-29 00:00:00");
    EXPECT_EQ(outlen, 19);

    result = FromUnixTimeRetNull(contextPtr, &isNull, 0, fmtStr.c_str(), fmtStr.length(),
                                 tzStr.c_str(), tzStr.length(), &outlen);
    actual = std::string(result, outlen);
    EXPECT_EQ(actual, "1970-01-01 08:00:00");
    EXPECT_EQ(outlen, 19);

    result = FromUnixTimeRetNull(contextPtr, &isNull, -100, fmtStr.c_str(), fmtStr.length(),
                                 tzStr.c_str(), tzStr.length(), &outlen);
    actual = std::string(result, outlen);
    EXPECT_EQ(actual, "1970-01-01 07:58:20");
    EXPECT_EQ(outlen, 19);
    delete context;
}

TEST(FunctionTest, FromUnixTimeWithoutTz)
{
    auto context = new ExecutionContext();
    int64_t contextPtr = reinterpret_cast<int64_t>(context);
    int32_t outlen = 0;
    std::string actual;
    std::string format;
    char *result = nullptr;

    int64_t timestamp = 1740484215000;

    format = "%y-%m-%d %H:%M:%S";
    result = FromUnixTimeWithoutTz(contextPtr, timestamp, format.c_str(), format.length(), false, &outlen);
    actual = std::string(result, outlen);
    EXPECT_EQ(actual, "25-02-25 11:50:15");
    EXPECT_EQ(outlen, 17);

    format = "%Y-%m";
    result = FromUnixTimeWithoutTz(contextPtr, timestamp, format.c_str(), format.length(), false, &outlen);
    actual = std::string(result, outlen);
    EXPECT_EQ(actual, "2025-02");
    EXPECT_EQ(outlen, 7);

    format = "%H:%M";
    result = FromUnixTimeWithoutTz(contextPtr, timestamp, format.c_str(), format.length(), false, &outlen);
    actual = std::string(result, outlen);
    EXPECT_EQ(actual, "11:50");
    EXPECT_EQ(outlen, 5);

    format = "%m-%H";
    result = FromUnixTimeWithoutTz(contextPtr, timestamp, format.c_str(), format.length(), false, &outlen);
    actual = std::string(result, outlen);
    EXPECT_EQ(actual, "02-11");
    EXPECT_EQ(outlen, 5);

    delete context;
}

TEST(FunctionTest, RegexMatch)
{
    std::string input("");
    std::string pattern(R"(^\d+$)");
    auto result = RegexMatch(input.c_str(), input.length(), pattern.c_str(), pattern.length(), false);
    EXPECT_FALSE(result);

    input = std::string("");
    pattern = std::string("");
    result = RegexMatch(input.c_str(), input.length(), pattern.c_str(), pattern.length(), false);
    EXPECT_TRUE(result);

    input = std::string("123");
    pattern = std::string("");
    result = RegexMatch(input.c_str(), input.length(), pattern.c_str(), pattern.length(), false);
    EXPECT_TRUE(result);

    input = std::string("123");
    pattern = std::string(R"(^\d+$)");
    result = RegexMatch(input.c_str(), input.length(), pattern.c_str(), pattern.length(), false);
    EXPECT_TRUE(result);

    input = std::string("abc123d");
    pattern = std::string(R"(^\d+$)");
    result = RegexMatch(input.c_str(), input.length(), pattern.c_str(), pattern.length(), false);
    EXPECT_FALSE(result);

    input = std::string("abc123");
    pattern = std::string(R"(^\d+$)");
    result = RegexMatch(input.c_str(), input.length(), pattern.c_str(), pattern.length(), false);
    EXPECT_FALSE(result);

    input = std::string("123d");
    pattern = std::string(R"(^\d+$)");
    result = RegexMatch(input.c_str(), input.length(), pattern.c_str(), pattern.length(), false);
    EXPECT_FALSE(result);
}

TEST(FunctionTest, Date32Trunc)
{
    Date32TruncTest("0086-03-14", "YEAR", "0086-01-01", false);
    Date32TruncTest("0987-12-27", "YEAR", "0987-01-01", false);

    Date32TruncTest("0086-03-14", "MONTH", "0086-03-01", false);
    Date32TruncTest("0987-12-27", "MONTH", "0987-12-01", false);

    Date32TruncTest("0086-03-14", "QUARTER", "0086-01-01", false);
    Date32TruncTest("0987-12-27", "QUARTER", "0987-10-01", false);

    Date32TruncTest("0086-03-14", "WEeK", "0086-03-11", false);
    Date32TruncTest("0987-12-27", "WEeK", "0987-12-24", false);

    Date32TruncTest("0086-03-14", "ww", "0086-03-11", true);
    Date32TruncTest("0987-12-27", "weeek", "0987-12-24", true);
}

TEST(FunctionTest, ContainsStr)
{
    std::string src = std::string("abc");
    std::string match = std::string("abc");
    bool result = ContainsStr(src.c_str(), src.length(), match.c_str(), match.length(), true);
    EXPECT_EQ(result, false);

    src = std::string("");
    match = std::string("abc");
    result = ContainsStr(src.c_str(), src.length(), match.c_str(), match.length(), false);
    EXPECT_EQ(result, false);

    src = std::string("abc");
    match = std::string("abd");
    result = ContainsStr(src.c_str(), src.length(), match.c_str(), match.length(), false);
    EXPECT_EQ(result, false);

    src = std::string("abcd");
    match = std::string("abd");
    result = ContainsStr(src.c_str(), src.length(), match.c_str(), match.length(), false);
    EXPECT_EQ(result, false);

    src = std::string("abcd");
    match = std::string("acd");
    result = ContainsStr(src.c_str(), src.length(), match.c_str(), match.length(), false);
    EXPECT_EQ(result, false);

    src = std::string("");
    match = std::string("");
    result = ContainsStr(src.c_str(), src.length(), match.c_str(), match.length(), false);
    EXPECT_EQ(result, true);

    src = std::string("abc");
    match = std::string("");
    result = ContainsStr(src.c_str(), src.length(), match.c_str(), match.length(), false);
    EXPECT_EQ(result, true);

    src = std::string("abc");
    match = std::string("abc");
    result = ContainsStr(src.c_str(), src.length(), match.c_str(), match.length(), false);
    EXPECT_EQ(result, true);

    src = std::string("abcd");
    match = std::string("abc");
    result = ContainsStr(src.c_str(), src.length(), match.c_str(), match.length(), false);
    EXPECT_EQ(result, true);

    src = std::string("abcd");
    match = std::string("bcd");
    result = ContainsStr(src.c_str(), src.length(), match.c_str(), match.length(), false);
    EXPECT_EQ(result, true);

    src = std::string("abcde");
    match = std::string("bcd");
    result = ContainsStr(src.c_str(), src.length(), match.c_str(), match.length(), false);
    EXPECT_EQ(result, true);
}

TEST(FunctionTest, GreatestStr)
{
    const char* lValue = "abc";
    const char* rValue = "abcd";
    bool retIsNull = false;
    int32_t outLen = 0;
    const char* result = GreatestStr(lValue, strlen(lValue), false, rValue, strlen(rValue), false, &retIsNull, &outLen);
    EXPECT_EQ(result, rValue);
    EXPECT_EQ(outLen, strlen(rValue));
    EXPECT_FALSE(retIsNull);

    lValue = "abcd";
    rValue = "abc";
    retIsNull = false;
    outLen = 0;
    result = GreatestStr(lValue, strlen(lValue), false, rValue, strlen(rValue), false, &retIsNull, &outLen);
    EXPECT_EQ(result, lValue);
    EXPECT_EQ(outLen, strlen(lValue));
    EXPECT_FALSE(retIsNull);

    lValue = "abc";
    rValue = "";
    retIsNull = false;
    outLen = 0;
    result = GreatestStr(lValue, strlen(lValue), false, rValue, strlen(rValue), false, &retIsNull, &outLen);
    EXPECT_EQ(result, lValue);
    EXPECT_EQ(outLen, strlen(lValue));
    EXPECT_FALSE(retIsNull);

    lValue = "";
    rValue = "abc";
    retIsNull = false;
    outLen = 0;
    result = GreatestStr(lValue, strlen(lValue), false, rValue, strlen(rValue), false, &retIsNull, &outLen);
    EXPECT_EQ(result, rValue);
    EXPECT_EQ(outLen, strlen(rValue));
    EXPECT_FALSE(retIsNull);

    lValue = "";
    rValue = "";
    retIsNull = false;
    outLen = 0;
    result = GreatestStr(lValue, strlen(lValue), false, rValue, strlen(rValue), false, &retIsNull, &outLen);
    EXPECT_EQ(result, lValue);
    EXPECT_EQ(outLen, strlen(lValue));
    EXPECT_FALSE(retIsNull);

    lValue = "abc";
    rValue = nullptr;
    retIsNull = false;
    outLen = 0;
    result = GreatestStr(lValue, strlen(lValue), false, rValue, 0, true, &retIsNull, &outLen);
    EXPECT_EQ(result, lValue);
    EXPECT_EQ(outLen, strlen(lValue));
    EXPECT_FALSE(retIsNull);

    lValue = nullptr;
    rValue = "abc";
    retIsNull = false;
    outLen = 0;
    result = GreatestStr(lValue, 0, true, rValue, strlen(rValue), false, &retIsNull, &outLen);
    EXPECT_EQ(result, rValue);
    EXPECT_EQ(outLen, strlen(rValue));
    EXPECT_FALSE(retIsNull);

    lValue = nullptr;
    rValue = nullptr;
    retIsNull = false;
    outLen = 0;
    result = GreatestStr(lValue, 0, true, rValue, 0, true, &retIsNull, &outLen);
    EXPECT_EQ(result, nullptr);
    EXPECT_EQ(outLen, 0);
    EXPECT_TRUE(retIsNull);

    lValue = "1234";
    rValue = "2";
    retIsNull = false;
    outLen = 0;
    result = GreatestStr(lValue, strlen(lValue), false, rValue, strlen(rValue), false, &retIsNull, &outLen);
    EXPECT_EQ(result, rValue);
    EXPECT_EQ(outLen, strlen(rValue));
    EXPECT_FALSE(retIsNull);
}

TEST(FunctionTest, Greatest)
{
    int32_t lInt32 = 10;
    int32_t rInt32 = 5;
    bool retIsNull = false;
    auto resultInt32 = Greatest<int32_t>(lInt32, false, rInt32, false, &retIsNull);
    EXPECT_EQ(resultInt32, lInt32);
    EXPECT_FALSE(retIsNull);

    lInt32 = 5;
    rInt32 = 10;
    retIsNull = false;
    resultInt32 = Greatest<int32_t>(lInt32, false, rInt32, false, &retIsNull);
    EXPECT_EQ(resultInt32, rInt32);
    EXPECT_FALSE(retIsNull);

    lInt32 = 0;
    rInt32 = 10;
    retIsNull = false;
    resultInt32 = Greatest<int32_t>(lInt32, true, rInt32, false, &retIsNull);
    EXPECT_EQ(resultInt32, rInt32);
    EXPECT_FALSE(retIsNull);

    lInt32 = 10;
    rInt32 = 0;
    retIsNull = false;
    resultInt32 = Greatest<int32_t>(lInt32, false, rInt32, true, &retIsNull);
    EXPECT_EQ(resultInt32, lInt32);
    EXPECT_FALSE(retIsNull);

    lInt32 = 0;
    rInt32 = 0;
    retIsNull = false;
    resultInt32 = Greatest<int32_t>(lInt32, true, rInt32, true, &retIsNull);
    EXPECT_EQ(resultInt32, 0);
    EXPECT_TRUE(retIsNull);

    int64_t lInt64 = 10;
    int64_t rInt64 = 5;
    retIsNull = false;
    auto resultInt64 = Greatest<int64_t>(lInt64, false, rInt64, false, &retIsNull);
    EXPECT_EQ(resultInt64, lInt64);
    EXPECT_FALSE(retIsNull);

    bool lBool = true;
    bool rBool = false;
    retIsNull = false;
    auto resultBool = Greatest<bool>(lBool, false, rBool, false, &retIsNull);
    EXPECT_EQ(resultBool, lBool);
    EXPECT_FALSE(retIsNull);

    double lDouble = 10.00;
    double rDouble = 5.00;
    retIsNull = false;
    auto resultDouble = Greatest<double>(lDouble, false, rDouble, false, &retIsNull);
    EXPECT_EQ(resultDouble, lDouble);
    EXPECT_FALSE(retIsNull);
}

TEST(FunctionTest, StaticInvokeVarcharTypeWriteSideCheck)
{
    auto context = new ExecutionContext();
    int64_t contextPtr = reinterpret_cast<int64_t>(context);
    std::string src = "abc";
    int outLen;
    const char* cs1 = StaticInvokeVarcharTypeWriteSideCheck(contextPtr, src.c_str(), src.size(), 4, false, &outLen);
    std::string ss1(cs1, outLen);
    EXPECT_EQ(ss1, src);

    const char* cs2 = StaticInvokeVarcharTypeWriteSideCheck(contextPtr, src.c_str(), src.size(), 2, false, &outLen);
    EXPECT_TRUE(cs2 == nullptr);

    src = "abc   ";
    const char* cs3 = StaticInvokeVarcharTypeWriteSideCheck(contextPtr, src.c_str(), src.size(), 4, false, &outLen);
    std::string ss3(cs3, outLen);
    EXPECT_EQ(ss3, "abc ");

    const char* cs4 = StaticInvokeVarcharTypeWriteSideCheck(contextPtr, src.c_str(), src.size(), 2, false, &outLen);
    EXPECT_TRUE(cs4 == nullptr);

    src = "你好";
    const char* cs5 = StaticInvokeVarcharTypeWriteSideCheck(contextPtr, src.c_str(), src.size(), 2, false, &outLen);
    std::string ss5(cs5, outLen);
    EXPECT_EQ(ss5, src);

    const char* cs6 = StaticInvokeVarcharTypeWriteSideCheck(contextPtr, src.c_str(), src.size(), 1, false, &outLen);
    EXPECT_TRUE(cs6 == nullptr);

    const char* cs7 = StaticInvokeVarcharTypeWriteSideCheck(contextPtr, nullptr, 0, 1, true, &outLen);
    EXPECT_TRUE(cs7 == nullptr);
    delete context;
}

TEST(FunctionTest, StaticInvokeCharReadPadding)
{
    auto context = new ExecutionContext();
    int64_t contextPtr = reinterpret_cast<int64_t>(context);
    std::string src = "abc";
    int outLen;
    const char* cs1 = StaticInvokeCharReadPadding(contextPtr, src.c_str(), src.size(), 2, false, &outLen);
    std::string ss1(cs1, outLen);
    EXPECT_EQ(ss1, src);

    const char* cs2 = StaticInvokeCharReadPadding(contextPtr, src.c_str(), src.size(), src.size(), false, &outLen);
    std::string ss2(cs2, outLen);
    EXPECT_EQ(ss2, src);

    const char* cs3 = StaticInvokeCharReadPadding(contextPtr, src.c_str(), src.size(), 6, false, &outLen);
    std::string ss3(cs3, outLen);
    EXPECT_EQ(ss3, "abc   ");

    src = "你好";
    const char* cs4 = StaticInvokeCharReadPadding(contextPtr, src.c_str(), src.size(), 1, false, &outLen);
    std::string ss4(cs4, outLen);
    EXPECT_EQ(ss4, src);

    const char* cs5 = StaticInvokeCharReadPadding(contextPtr, src.c_str(), src.size(), 2, false, &outLen);
    std::string ss5(cs5, outLen);
    EXPECT_EQ(ss5, src);

    const char* cs6 = StaticInvokeCharReadPadding(contextPtr, src.c_str(), src.size(), 4, false, &outLen);
    std::string ss6(cs6, outLen);
    EXPECT_EQ(ss6, "你好  ");

    const char* cs7 = StaticInvokeCharReadPadding(contextPtr, nullptr, 0, 4, true, &outLen);
    std::string ss7(cs7, outLen);
    EXPECT_TRUE(cs7 == nullptr);
    delete context;
}

TEST(FunctionTest, GetJsonObject)
{
    auto context = new ExecutionContext();
    int64_t contextPtr = reinterpret_cast<int64_t>(context);

    auto expectNull = [&](const char *jsonStr, int32_t jsonLen, bool jsonIsNull, const char *pathStr, int32_t pathLen,
                          bool pathIsNull) {
        bool retIsNull = false;
        int32_t outLen = -1;
        const char *ret = GetJsonObject(contextPtr, jsonStr, jsonLen, jsonIsNull, pathStr, pathLen, pathIsNull,
            &retIsNull, &outLen);
        EXPECT_TRUE(retIsNull);
        EXPECT_EQ(ret, nullptr);
        EXPECT_EQ(outLen, 0);
    };

    auto expectValue = [&](const char *jsonStr, int32_t jsonLen, const char *pathStr, int32_t pathLen,
                           const std::string &expect) {
        bool retIsNull = true;
        int32_t outLen = 0;
        const char *ret = GetJsonObject(contextPtr, jsonStr, jsonLen, false, pathStr, pathLen, false, &retIsNull, &outLen);
        EXPECT_FALSE(retIsNull);
        ASSERT_NE(ret, nullptr);
        EXPECT_EQ(outLen, static_cast<int32_t>(expect.size()));
        EXPECT_EQ(std::string(ret, outLen), expect);
    };

    expectNull(nullptr, 0, true, "$.a", 3, false);
    expectNull("{\"a\":1}", 7, false, nullptr, 0, true);
    expectNull(nullptr, 0, false, "$.a", 3, false);
    expectNull("{\"a\":1}", 0, false, "$.a", 3, false);
    expectNull("{\"a\":1}", 7, false, "$.a", 0, false);

    expectNull("{\"a\":1}", 7, false, "a", 1, false);
    expectNull("{\"a\":1}", 7, false, "$.", 2, false);
    expectNull("{\"a\":1}", 7, false, "$[", 2, false);

    expectNull("{", 1, false, "$.a", 3, false);

    expectNull("{\"a\":1}", 7, false, "$.b", 3, false);
    expectNull("{\"a\":1}", 7, false, "$.a.b", 5, false);

    expectValue("{\"a\":\"x\"}", 9, "$.a", 3, "x");
    expectValue("{\"a\":20}", 8, "$.a", 3, "20");
    expectValue("{\"a\":1}", 7, "$.a", 3, "1");
    expectValue("{\"a\":{\"b\":1}}", 13, "$.a", 3, "{\"b\":1}");
    expectValue("{\"a\":[1,2]}", 11, "$.a", 3, "[1,2]");
    expectValue("{\"a\":[10,20]}", 13, "$.a[1]", 6, "20");
    expectNull("{\"a\":[1]}", 9, false, "$.a[2]", 6, false);
    expectValue("{\"a\":[{\"b\":\"c\"}]}", 17, "$.a[0].b", 8, "c");

    expectValue("{\"a\":true}", 10, "$.a", 3, "true");

    expectValue("{\"a\":1}", 7, "$", 1, "{\"a\":1}");

    expectNull("{\"a\":null}", 10, false, "$.a", 3, false);

    expectValue("{\"a\":1}", 7, "$['a']", 6, "1");

    expectValue("{\"a\":{\"b\":{\"c\":1}}}", 19, "$.a.b", 5, "{\"c\":1}");
    expectValue("{\"a\":[[1,2],[3,4]]}", 19, "$.a[1][0]", 9, "3");
    expectValue("{\"a\":{\"b\":[{\"c\":null},{\"c\":\"d\"}]}}", 35, "$.a.b[1].c", 10, "d");
    expectNull("{\"a\":{\"b\":[{\"c\":null},{\"c\":\"d\"}]}}", 35, false, "$.a.b[0].c", 10, false);
    expectValue("{\"a\":{\"b\":\"c\"}}", 16, "$['a']['b']", 11, "c");
    expectValue("[{\"a\":1},{\"a\":2}]", 17, "$[0].a", 6, "1");
    expectValue("[{\"a\":1},{\"a\":2}]", 17, "$[1].a", 6, "2");
    expectValue("[{\"a\":1},{\"a\":2}]", 17, "$[0]", 4, "{\"a\":1}");
    expectNull("[{\"a\":1},{\"a\":2}]", 17, false, "$[2].a", 6, false);

    delete context;
}

TEST(FunctionTest, CurrentTimestamp)
{
    int64_t timestamp1 = CurrentTimestamp();
    EXPECT_GT(timestamp1, 0);
    
    std::this_thread::sleep_for(std::chrono::milliseconds(10));
    int64_t timestamp2 = CurrentTimestamp();
    EXPECT_GT(timestamp2, timestamp1);
    
    auto now = std::chrono::system_clock::now();
    auto duration = now.time_since_epoch();
    int64_t expectedMillis = std::chrono::duration_cast<std::chrono::milliseconds>(duration).count();
    int64_t diff = std::abs(timestamp1 - expectedMillis);
    EXPECT_LT(diff, 100);
}

TEST(FunctionTest, DateAddDays)
{
    bool retIsNull = false;
    
    constexpr int64_t MILLIS_PER_DAY = 86400000LL;
    constexpr int64_t MIN_EPOCH_MILLS = -62167219200000LL;
    constexpr int64_t MAX_EPOCH_MILLS = 253402300799999LL;
    
    int64_t timestamp = 1625097600000L;
    
    int64_t result = DateAddDays(timestamp, false, 1, false, &retIsNull);
    EXPECT_FALSE(retIsNull);
    EXPECT_EQ(result, timestamp + MILLIS_PER_DAY);
    
    result = DateAddDays(timestamp, false, 7, false, &retIsNull);
    EXPECT_FALSE(retIsNull);
    EXPECT_EQ(result, timestamp + 7 * MILLIS_PER_DAY);
    
    result = DateAddDays(timestamp, false, -1, false, &retIsNull);
    EXPECT_FALSE(retIsNull);
    EXPECT_EQ(result, timestamp - MILLIS_PER_DAY);
    
    result = DateAddDays(timestamp, false, -30, false, &retIsNull);
    EXPECT_FALSE(retIsNull);
    EXPECT_EQ(result, timestamp - 30 * MILLIS_PER_DAY);
    
    result = DateAddDays(timestamp, false, 0, false, &retIsNull);
    EXPECT_FALSE(retIsNull);
    EXPECT_EQ(result, timestamp);
    
    result = DateAddDays(timestamp, true, 1, false, &retIsNull);
    EXPECT_TRUE(retIsNull);
    EXPECT_EQ(result, 0);
    
    result = DateAddDays(timestamp, false, 1, true, &retIsNull);
    EXPECT_TRUE(retIsNull);
    EXPECT_EQ(result, 0);
    
    int64_t nearMax = MAX_EPOCH_MILLS - MILLIS_PER_DAY;
    result = DateAddDays(nearMax, false, 1, false, &retIsNull);
    EXPECT_FALSE(retIsNull);
    EXPECT_EQ(result, MAX_EPOCH_MILLS);
    
    result = DateAddDays(MAX_EPOCH_MILLS, false, 1, false, &retIsNull);
    EXPECT_TRUE(retIsNull);
    EXPECT_EQ(result, 0);
    
    int64_t nearMin = MIN_EPOCH_MILLS + MILLIS_PER_DAY;
    result = DateAddDays(nearMin, false, -1, false, &retIsNull);
    EXPECT_FALSE(retIsNull);
    EXPECT_EQ(result, MIN_EPOCH_MILLS);
    
    result = DateAddDays(MIN_EPOCH_MILLS, false, -1, false, &retIsNull);
    EXPECT_TRUE(retIsNull);
    EXPECT_EQ(result, 0);
    
    result = DateAddDays(0L, false, 365, false, &retIsNull);
    EXPECT_FALSE(retIsNull);
    EXPECT_EQ(result, 365 * MILLIS_PER_DAY);
    
    result = DateAddDays(365 * MILLIS_PER_DAY, false, -365, false, &retIsNull);
    EXPECT_FALSE(retIsNull);
    EXPECT_EQ(result, 0L);
    
    int64_t epochTimestamp = 0L;
    result = DateAddDays(epochTimestamp, false, 1000, false, &retIsNull);
    EXPECT_FALSE(retIsNull);
    EXPECT_EQ(result, 1000 * MILLIS_PER_DAY);
    
    result = DateAddDays(epochTimestamp, false, -1000, false, &retIsNull);
    EXPECT_FALSE(retIsNull);
    EXPECT_EQ(result, -1000 * MILLIS_PER_DAY);
}

}