text: //
  // Copyright 2019 Google LLC
  //
  // Licensed under the Apache License, Version 2.0 (the "License");
  // you may not use this file except in compliance with the License.
  // You may obtain a copy of the License at
  //
  //      http://www.apache.org/licenses/LICENSE-2.0
  //
  // Unless required by applicable law or agreed to in writing, software
  // distributed under the License is distributed on an "AS IS" BASIS,
  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  // See the License for the specific language governing permissions and
  // limitations under the License.
  //
  
  #include <math.h>
  
  #include <array>
  #include <cstdint>
  #include <limits>
  #include <memory>
  #include <numeric>
  #include <string>
  #include <utility>
  #include <vector>
  
  #include "zetasql/base/logging.h"
  #include "google/protobuf/wrappers.pb.h"
  #include "zetasql/compliance/functions_testlib_common.h"
  #include "zetasql/public/functions/date_time_util.h"
  #include "zetasql/public/numeric_value.h"
  #include "zetasql/public/options.pb.h"
  #include "zetasql/public/type.h"
  #include "zetasql/public/types/type_factory.h"
  #include "zetasql/public/value.h"
  #include "zetasql/testing/test_function.h"
  #include "zetasql/testing/test_value.h"
  #include "zetasql/testing/using_test_value.cc"
  #include <cstdint>
  #include "absl/strings/cord.h"
  #include "absl/strings/string_view.h"
  #include "zetasql/base/status.h"
  
  namespace zetasql {
  namespace {
  constexpr absl::StatusCode INVALID_ARGUMENT =
      absl::StatusCode::kInvalidArgument;
  constexpr absl::StatusCode OUT_OF_RANGE = absl::StatusCode::kOutOfRange;
  }  // namespace
  
  std::vector<QueryParamsWithResult> GetFunctionTestsAnd() {
    return {
      // Binary.
      {{False(), False()}, False()},
      {{False(), True()}, False()},
      {{True(), False()}, False()},
      {{True(), True()}, True()},
      {{True(), NullBool()}, NullBool()},
      {{NullBool(), True()}, NullBool()},
      {{False(), NullBool()}, False()},
      {{NullBool(), False()}, False()},
      {{NullBool(), NullBool()}, NullBool()},
      // Ternary. The third argument affects the result.
      {{True(), True(), NullBool()}, NullBool()},
      {{True(), True(), False()}, False()},
      {{True(), NullBool(), False()}, False()}
    };
  }
  
  std::vector<QueryParamsWithResult> GetFunctionTestsOr() {
    return {
      // Binary.
      {{False(), False()}, False()},
      {{False(), True()}, True()},
      {{True(), False()}, True()},
      {{True(), True()}, True()},
      {{True(), NullBool()}, True()},
      {{NullBool(), True()}, True()},
      {{False(), NullBool()}, NullBool()},
      {{NullBool(), False()}, NullBool()},
      {{NullBool(), NullBool()}, NullBool()},
      // Ternary. The third argument affects the result.
      {{False(), False(), True()}, True()},
      {{False(), False(), NullBool()}, NullBool()},
      {{False(), NullBool(), True()}, True()}
    };
  }
  
  std::vector<QueryParamsWithResult> GetFunctionTestsNot() {
    return {
      {{False()}, True()},
      {{True()}, False()},
      {{NullBool()}, NullBool()}
    };
  }
  
  // Note that many array tests are generated by taking non-array tests
  // and wrapping the values in arrays for the comparison.  This function
  // returns test cases that aren't covered by those tests, such as
  // NULL array values, arrays with different lengths, arrays with elements
  // that are NULLs and NaNs, etc.  So for instance, these tests use
  // ARRAY<DOUBLE> in order to test NaN behavior, and arrays with other
  // element types are not covered here.
  //
  // The test result can be UNEQUAL, which in this case indicates that the
  // two arrays compares as NOT EQUAL, but it cannot be determined if one
  // array is LESS than the other.  For example, consider the comparison between:
  //
  // [NULL]
  // [1, 2]
  //
  // We know these arrays are NOT EQUAL since they have different lengths.  But
  // LESS comparison returns NULL because the comparison between the first
  // element in the two arrays results in NULL.
  static std::vector<ComparisonTest> GetArrayComparisonTests() {
    const Value null_array = Value::Null(DoubleArrayType());
    const Value empty_array = Value::EmptyArray(DoubleArrayType());
  
    const Value array0 = values::Array(DoubleArrayType(), {Value::NullDouble()});
    const Value array1 = values::DoubleArray({0});
    const Value array2 = values::DoubleArray({1});
    const Value array3 = values::Array(DoubleArrayType(),
                                       {Value::Double(1), Value::NullDouble()});
    const Value array4 = values::DoubleArray({1, 0});
    const Value array5 = values::DoubleArray({1, 1});
    const Value array6 = values::DoubleArray({2});
  
    const Value array7 = values::Array(DoubleArrayType(),
                                       {Value::Double(1), Value::NullDouble(),
                                        Value::Double(0)});
    const Value array8 = values::Array(DoubleArrayType(),
                                       {Value::Double(1), Value::NullDouble(),
                                        Value::Double(1)});
    const Value array9 = values::DoubleArray({1, 1, 1});
  
    const Value array_nan1 = values::DoubleArray({double_nan});
    const Value array_nan2 = values::DoubleArray({0, double_nan});
    const Value array_nan3 = values::DoubleArray({1, double_nan});
    const Value array_nan4 = values::DoubleArray({1, double_nan, 0});
    const Value array_nan5 = values::DoubleArray({1, double_nan, 1});
  
    std::vector<ComparisonTest> v = {
      // same null array, compare as NULL for both equality and non-equality.
      {null_array, null_array, NULL_VALUE},
  
      // same non-null array
      {empty_array, empty_array, EQUAL},
      {array1, array1, EQUAL},
      {array4, array4, EQUAL},
  
      // same array with null elements
      {array0, array0, NULL_VALUE},
      {array3, array3, NULL_VALUE},
  
      // null array and non-null array
      {null_array, empty_array, NULL_VALUE},
      {null_array, array0, NULL_VALUE},
      {null_array, array1, NULL_VALUE},
      {null_array, array3, NULL_VALUE},
  
      // empty array an non-empty array
      {empty_array, array0, LESS},
      {empty_array, array1, LESS},
      {empty_array, array2, LESS},
      {empty_array, array3, LESS},
      {empty_array, array4, LESS},
      {empty_array, array5, LESS},
      {empty_array, array6, LESS},
  
      // An array with the first NULL element compares as NULL with all
      // other arrays with at least one element.
      {array0, array1, NULL_VALUE},
      {array0, array2, NULL_VALUE},
      {array0, array3, UNEQUAL},  // We do know these are not equal because
      {array0, array4, UNEQUAL},  // array lengths are not equal, but for
      {array0, array5, UNEQUAL},  // LESS/GREATER the result is NULL.
      {array0, array6, NULL_VALUE},
  
      {array1, array2, LESS},
      {array1, array3, LESS},
      {array1, array4, LESS},
      {array1, array5, LESS},
      {array1, array6, LESS},
  
      {array2, array3, LESS},
      {array2, array4, LESS},
      {array2, array5, LESS},
      {array2, array6, LESS},
  
      {array3, array4, NULL_VALUE},
      {array3, array5, NULL_VALUE},
      {array3, array6, LESS},
      {array3, array7, UNEQUAL},
      {array3, array8, UNEQUAL},
      {array3, array9, UNEQUAL},
  
      {array4, array5, LESS},
      {array4, array6, LESS},
  
      {array5, array6, LESS},
  
      {array7, array8, UNEQUAL},
      {array7, array9, UNEQUAL},
  
      {array8, array9, NULL_VALUE},
  
      // Comparing NaN to a NULL returns NULL, comparing NaN to non-NULL
      // returns FALSE (including comparing NaN to NaN).
      {array_nan1, array0, NULL_VALUE},
      {array_nan1, array3, UNORDERED},
      {array_nan1, array6, UNORDERED},
      {array_nan1, array_nan1, UNORDERED},
      {array_nan1, array_nan2, UNORDERED},
      {array_nan1, array_nan3, UNORDERED},
      {array_nan1, array_nan4, UNORDERED},
      {array_nan1, array_nan5, UNORDERED},
  
      {array_nan2, array0, UNEQUAL},
      {array_nan2, array3, LESS},
      {array_nan2, array6, LESS},
      {array_nan2, array_nan2, UNORDERED},
      {array_nan2, array_nan3, LESS},
      {array_nan2, array_nan4, LESS},
      {array_nan2, array_nan5, LESS},
  
      {array_nan3, array0, UNEQUAL},
      {array_nan3, array3, NULL_VALUE},
      {array_nan3, array6, LESS},
      {array_nan3, array_nan3, UNORDERED},
      {array_nan3, array_nan4, UNORDERED},
      {array_nan3, array_nan5, UNORDERED},
  
      {array_nan4, array0, UNEQUAL},
      {array_nan4, array3, UNEQUAL},
      {array_nan4, array6, LESS},
      {array_nan4, array_nan4, UNORDERED},
      {array_nan4, array_nan5, UNORDERED},
    };
  
    return v;
  }
  
  // Only struct equality/inequality is defined for ZetaSQL, not other
  // comparisons (less than, etc.).  Therefore all tests should be defined
  // as EQUAL, UNORDERED (not equal), or NULL_VALUE.
  static std::vector<ComparisonTest> GetStructComparisonTests() {
    const StructType* struct_type = SimpleStructType();  // a: string, b: int32_t
    const Value struct0 = Value::Struct(struct_type, {String("foo"), Int32(0)});
    const Value struct1 = Value::Struct(struct_type, {String("bar"), Int32(1)});
    const Value struct_with_null2 =
        Value::Struct(struct_type, {NullString(), Int32(1)});
    const Value struct_with_null3 =
        Value::Struct(struct_type, {String("bar"), NullInt32()});
    const Value struct_with_null4 =
        Value::Struct(struct_type, {NullString(), NullInt32()});
    const Value null_struct = Value::Null(struct_type);
  
    // a: string, b: {a: string b: int32_t}
    const StructType* nested_struct_type;
    ZETASQL_CHECK_OK(type_factory()->MakeStructType(
        {{"a", StringType()}, {"b", struct_type}}, &nested_struct_type));
    const Value null_nested_struct = Value::Null(nested_struct_type);
    const Value nested_struct1 =
        Value::Struct(nested_struct_type, {String("x"), struct1});
    const Value nested_struct1b =
        Value::Struct(nested_struct_type, {String("x"), struct1});
    const Value nested_struct_null1 =
        Value::Struct(nested_struct_type, {NullString(), struct1});
    const Value nested_struct_null2 =
        Value::Struct(nested_struct_type, {String("x"), struct_with_null2});
    const Value nested_struct_null3 =
        Value::Struct(nested_struct_type, {String("x"), struct_with_null3});
    const Value nested_struct_null4 =
        Value::Struct(nested_struct_type,
          {String("x"), Value::Null(struct_type)});
  
    // These DCHECKs are only here to more clearly show the contents of
    // all the struct values.
    ZETASQL_DCHECK_EQ("(\"foo\", 0)",    struct0.GetSQLLiteral());
    ZETASQL_DCHECK_EQ("(\"bar\", 1)",    struct1.GetSQLLiteral());
    ZETASQL_DCHECK_EQ("(NULL, 1)",       struct_with_null2.GetSQLLiteral());
    ZETASQL_DCHECK_EQ("(\"bar\", NULL)", struct_with_null3.GetSQLLiteral());
    ZETASQL_DCHECK_EQ("(NULL, NULL)",    struct_with_null4.GetSQLLiteral());
    ZETASQL_DCHECK_EQ("NULL",            null_struct.GetSQLLiteral());
  
    ZETASQL_DCHECK_EQ("NULL",                     null_nested_struct.GetSQLLiteral());
    ZETASQL_DCHECK_EQ("(\"x\", (\"bar\", 1))",    nested_struct1.GetSQLLiteral());
    ZETASQL_DCHECK_EQ("(\"x\", (\"bar\", 1))",    nested_struct1b.GetSQLLiteral());
    ZETASQL_DCHECK_EQ("(NULL, (\"bar\", 1))",     nested_struct_null1.GetSQLLiteral());
    ZETASQL_DCHECK_EQ("(\"x\", (NULL, 1))",       nested_struct_null2.GetSQLLiteral());
    ZETASQL_DCHECK_EQ("(\"x\", (\"bar\", NULL))", nested_struct_null3.GetSQLLiteral());
    ZETASQL_DCHECK_EQ("(\"x\", NULL)",            nested_struct_null4.GetSQLLiteral());
  
    std::vector<ComparisonTest> v = {
      // same non-null struct
      {struct0, struct0, EQUAL},                 // (foo, 0) vs. (foo, 0)
      {struct1, struct1, EQUAL},                 // (bar, 1) vs. (bar, 1)
  
      // different non-null struct
      {struct0, struct1, UNORDERED},             // (foo, 0) vs. (bar, 1)
  
      // null struct and non-null struct
      {null_struct, struct1, NULL_VALUE},        // NULL vs. (bar, 1)
  
      // non-null struct vs. struct with a null field
      {struct0, struct_with_null2, UNORDERED},   // (foo, 0) vs. (NULL, 1)
      {struct1, struct_with_null2, NULL_VALUE},  // (bar, 1) vs. (NULL, 1)
      {struct0, struct_with_null3, UNORDERED},   // (foo, 0) vs. (bar, NULL)
      {struct1, struct_with_null3, NULL_VALUE},  // (bar, 1) vs. (bar, NULL)
      {struct0, struct_with_null4, NULL_VALUE},  // (foo, 0) vs. (NULL, NULL)
      {struct1, struct_with_null4, NULL_VALUE},  // (bar, 1) vs. (NULL, NULL)
  
      // null struct vs. struct with null field
      {null_struct, struct_with_null2, NULL_VALUE},  // NULL vs. (NULL, 1)
      {null_struct, struct_with_null3, NULL_VALUE},  // NULL vs. (bar, NULL)
      {null_struct, struct_with_null4, NULL_VALUE},  // NULL vs. (NULL, NULL)
  
      // null struct vs. same null struct
      {null_struct, null_struct, NULL_VALUE},        // NULL vs. NULL
  
      // Nested structs
      {nested_struct1, nested_struct1, EQUAL},   // (x, (bar, 1)) v. (x, (bar, 1))
      {nested_struct1, nested_struct1b, EQUAL},  // (x, (bar, 1)) v. (x, (bar, 1))
  
      // (x, (bar, 1)) vs. NULL
      {nested_struct1, null_nested_struct, NULL_VALUE},
  
      // (x, (bar, 1)) vs. struct with null
      {nested_struct1, nested_struct_null1, NULL_VALUE},  // (NULL, (bar, 1))
      {nested_struct1, nested_struct_null2, NULL_VALUE},  // (x, (NULL, 1))
      {nested_struct1, nested_struct_null3, NULL_VALUE},  // (x, (bar, NULL))
      {nested_struct1, nested_struct_null4, NULL_VALUE},  // (x, NULL)
  
      // struct with null vs. same struct with null
      {null_nested_struct, null_nested_struct, NULL_VALUE},
      {nested_struct_null1, nested_struct_null1, NULL_VALUE},
      {nested_struct_null2, nested_struct_null2, NULL_VALUE},
      {nested_struct_null3, nested_struct_null3, NULL_VALUE},
      {nested_struct_null4, nested_struct_null4, NULL_VALUE},
  
      // struct with null vs. different struct with null
      {null_nested_struct, nested_struct_null1, NULL_VALUE},
      {nested_struct_null1, nested_struct_null2, NULL_VALUE},
      {nested_struct_null2, nested_struct_null3, NULL_VALUE},
      {nested_struct_null3, nested_struct_null4, NULL_VALUE},
      {nested_struct_null4, null_nested_struct, NULL_VALUE},
    };
    return v;
  }
  
  static std::vector<ComparisonTest> GetComparisonTests(
      bool include_struct_comparisons, bool include_array_comparisons,
      bool include_nano_timestamp) {
    const Value enum0 = Value::Enum(TestEnumType(), 0);
    const Value enum1 = Value::Enum(TestEnumType(), 1);
    std::vector<ComparisonTest> v = {
        // bool
        {True(), True(), EQUAL},
        {False(), False(), EQUAL},
        {False(), True(), LESS},
        {True(), NullBool(), NULL_VALUE},
  
        // double
        {3.14, 3.14, EQUAL},
        {2.72, 3.14, LESS},
        {-3.14, -2.72, LESS},
        {-2.72, 3.14, LESS},
        {3.14, NullDouble(), NULL_VALUE},
        {NullDouble(), 3.14, NULL_VALUE},
        {0.0, 0.0, EQUAL},
        {0.0, double_pos_inf, LESS},
        {double_neg_inf, 0.0, LESS},
        {double_neg_inf, double_pos_inf, LESS},
        {double_pos_inf, double_pos_inf, EQUAL},
        {0.0, double_nan, UNORDERED},
        {double_nan, 0.0, UNORDERED},
        {double_pos_inf, double_nan, UNORDERED},
        {double_neg_inf, double_nan, UNORDERED},
        {double_nan, double_pos_inf, UNORDERED},
        {double_nan, double_neg_inf, UNORDERED},
        {double_nan, double_nan, UNORDERED},
        {double_nan, NullDouble(), NULL_VALUE},
        {NullDouble(), double_nan, NULL_VALUE},
        {double_neg_inf, NullDouble(), NULL_VALUE},
        {NullDouble(), double_neg_inf, NULL_VALUE},
        {double_pos_inf, NullDouble(), NULL_VALUE},
        {NullDouble(), double_pos_inf, NULL_VALUE},
  
        // float
        {3.14f, 3.14f, EQUAL},
        {2.72f, 3.14f, LESS},
        {-3.14f, -2.72f, LESS},
        {-2.72f, 3.14f, LESS},
        {3.14f, NullFloat(), NULL_VALUE},
        {NullFloat(), 3.14f, NULL_VALUE},
        {0.0f, 0.0f, EQUAL},
        {0.0f, float_pos_inf, LESS},
        {float_neg_inf, 0.0f, LESS},
        {float_neg_inf, float_pos_inf, LESS},
        {float_pos_inf, float_pos_inf, EQUAL},
        {0.0f, float_nan, UNORDERED},
        {float_nan, 0.0f, UNORDERED},
        {float_pos_inf, float_nan, UNORDERED},
        {float_neg_inf, float_nan, UNORDERED},
        {float_nan, float_pos_inf, UNORDERED},
        {float_nan, float_neg_inf, UNORDERED},
        {float_nan, float_nan, UNORDERED},
        {float_nan, NullFloat(), NULL_VALUE},
        {NullFloat(), float_nan, NULL_VALUE},
        {float_neg_inf, NullDouble(), NULL_VALUE},
        {NullDouble(), float_neg_inf, NULL_VALUE},
        {float_pos_inf, NullDouble(), NULL_VALUE},
        {NullDouble(), float_pos_inf, NULL_VALUE},
  
        // int32_t
        {0, int32max, LESS},
        {int32min, int32max, LESS},
        {1, 1, EQUAL},
        {1, 2, LESS},
        {-2, -1, LESS},
        {-1, 1, LESS},
        {1, NullInt32(), NULL_VALUE},
  
        // int64_t
        {0ll, int64max, LESS},
        {int64min, int64max, LESS},
        {1ll, 1ll, EQUAL},
        {1ll, 2ll, LESS},
        {-2ll, -1ll, LESS},
        {-1ll, 1ll, LESS},
        {1ll, NullInt64(), NULL_VALUE},
  
        // uint32_t
        {0u, uint32max, LESS},
        {0u, 1u, LESS},
        {0u, uint32max, LESS},
        {1u, 1u, EQUAL},
        {0u, 2u, LESS},
        {1u, NullUint32(), NULL_VALUE},
  
        // uint64_t
        {0ull, uint64max, LESS},
        {0ull, 1ull, LESS},
        {0ull, uint64max, LESS},
        {1ull, 1ull, EQUAL},
        {0ull, 2ull, LESS},
        {1ull, NullUint64(), NULL_VALUE},
  
        // int64_t vs. uint64_t
        {0ll, 0ull, EQUAL},
        {int64max, Uint64(int64max), EQUAL},
        {0ll, Uint64(int64max), LESS},
        {-1ll, 0ull, LESS},
        {0ll, 1ull, LESS},
        {0ull, 1ll, LESS},
        {int64max, int64max_plus_one, LESS},
        {-1ll, int64max_plus_one, LESS},
        {-1ll, NullUint64(), NULL_VALUE},
        {1ull, NullInt64(), NULL_VALUE},
  
        // numeric
        {Numeric(0), NumericValue::MaxValue(), LESS},
        {NumericValue::MinValue(), NumericValue::MaxValue(), LESS},
        {Numeric(1), Numeric(1), EQUAL},
        {NumericFromDouble(123.456), NumericFromDouble(123.654), LESS},
        {NumericFromDouble(-123.654), NumericFromDouble(-123.456), LESS},
        {Numeric(-1), Numeric(-1), EQUAL},
        {Numeric(1), NullNumeric(), NULL_VALUE},
  
        // numeric vs. int64_t
        {Int64(0), NumericValue::MaxValue(), LESS},
        {NumericValue::MinValue(), int64min, LESS},
        {Int64(1), Numeric(1), EQUAL},
        {Int64(123), NumericFromDouble(123.654), LESS},
        {NumericFromDouble(-123.456), Int64(-123), LESS},
        {Int64(-1), Numeric(-1), EQUAL},
        {Int64(1), NullNumeric(), NULL_VALUE},
  
        // numeric vs. uint64_t
        {Uint64(0), NumericValue::MaxValue(), LESS},
        {NumericValue::MinValue(), uint64max, LESS},
        {Uint64(1), Numeric(1), EQUAL},
        {Uint64(123), NumericFromDouble(123.654), LESS},
        {NumericFromDouble(-123.456), Uint64(123), LESS},
        {Numeric(-1), Uint64(1), LESS},
        {Uint64(1), NullNumeric(), NULL_VALUE},
  
        // numeric vs. double
        {Double(0), NumericValue::MaxValue(), LESS},
        {doublemin, NumericValue::MinValue(), LESS},
        {double_neg_inf, NumericValue::MinValue(), LESS},
        {NumericValue::MaxValue(), double_pos_inf, LESS},
        {NumericValue::MaxValue(), double_nan, UNORDERED},
        {Double(1.0), Numeric(1), EQUAL},
        {Double(0.0), Numeric(0), EQUAL},
        {Double(-0.0), Numeric(0), EQUAL},
        {Double(123), NumericFromDouble(123.654), LESS},
        {NumericFromDouble(-123.456), Double(-123), LESS},
        {Double(-123.456), NumericFromDouble(-123.456), EQUAL},
        {Double(-1), Numeric(-1), EQUAL},
        {Double(1), NullNumeric(), NULL_VALUE},
  
        // bignumeric
        {BigNumeric(0), BigNumeric(BigNumericValue::MaxValue()), LESS},
        {BigNumeric(BigNumericValue::MinValue()), BigNumeric(0), LESS},
        {BigNumeric(1), BigNumeric(1), EQUAL},
        {BigNumeric(BigNumericValue::FromStringStrict("123.456").value()),
         BigNumeric(BigNumericValue::FromStringStrict("123.654").value()), LESS},
        {BigNumeric(BigNumericValue::FromStringStrict("-123.654").value()),
         BigNumeric(BigNumericValue::FromStringStrict("-123.456").value()), LESS},
        {BigNumeric(-1), BigNumeric(-1), EQUAL},
        {BigNumeric(1), NullBigNumeric(), NULL_VALUE},
  
        // bignumeric vs. int64_t
        {Int64(0), BigNumeric(BigNumericValue::MaxValue()), LESS},
        {BigNumeric(BigNumericValue::MinValue()), int64min, LESS},
        {Int64(1), BigNumeric(1), EQUAL},
        {Int64(123),
         BigNumeric(BigNumericValue::FromStringStrict("123.654").value()), LESS},
        {BigNumeric(BigNumericValue::FromStringStrict("-123.456").value()),
         Int64(-123), LESS},
        {Int64(-1), BigNumeric(-1), EQUAL},
        {Int64(1), NullBigNumeric(), NULL_VALUE},
  
        // bignumeric vs. uint64_t
        {Uint64(0), BigNumeric(BigNumericValue::MaxValue()), LESS},
        {BigNumeric(BigNumericValue::MinValue()), uint64max, LESS},
        {Uint64(1), BigNumeric(1), EQUAL},
        {Uint64(123),
         BigNumeric(BigNumericValue::FromStringStrict("123.654").value()), LESS},
        {BigNumeric(BigNumericValue::FromStringStrict("-123.456").value()),
         Uint64(123), LESS},
        {BigNumeric(-1), Uint64(1), LESS},
        {Uint64(1), NullBigNumeric(), NULL_VALUE},
  
        // bignumeric vs. floating point
        {Double(0), BigNumeric(BigNumericValue::MaxValue()), LESS},
        {doublemin, BigNumeric(BigNumericValue::MinValue()), LESS},
        {double_neg_inf, BigNumeric(BigNumericValue::MinValue()), LESS},
        {BigNumeric(BigNumericValue::MaxValue()), double_pos_inf, LESS},
        {BigNumeric(BigNumericValue::MaxValue()), float_pos_inf, LESS},
        {BigNumeric(BigNumericValue::MaxValue()), double_nan, UNORDERED},
        {Double(1.0), BigNumeric(1), EQUAL},
        {Double(0.0), BigNumeric(0), EQUAL},
        {Double(-0.0), BigNumeric(0), EQUAL},
        {Double(123),
         BigNumeric(BigNumericValue::FromStringStrict("123.654").value()), LESS},
        {BigNumeric(BigNumericValue::FromStringStrict("-123.456").value()),
         Double(-123), LESS},
        {Double(-123.456),
         BigNumeric(BigNumericValue::FromStringStrict("-123.456").value()),
         EQUAL},
        {Double(-1), BigNumeric(-1), EQUAL},
        {Double(1), NullBigNumeric(), NULL_VALUE},
  
        // bignumeric vs numeric
        {Numeric(0), BigNumeric(BigNumericValue::MaxValue()), LESS},
        {BigNumeric(BigNumericValue::MinValue()), Numeric(0), LESS},
        {Numeric(1), BigNumeric(1), EQUAL},
        {Numeric(NumericValue::FromStringStrict("123.456").value()),
         BigNumeric(BigNumericValue::FromStringStrict("123.654").value()), LESS},
        {Numeric(NumericValue::FromStringStrict("-123.654").value()),
         BigNumeric(BigNumericValue::FromStringStrict("-123.456").value()), LESS},
        {Numeric(-1), BigNumeric(-1), EQUAL},
        {Numeric(1), NullBigNumeric(), NULL_VALUE},
        {BigNumeric(1), NullNumeric(), NULL_VALUE},
  
        // string
        {"hello", "hello", EQUAL},
        {"bye", "hello", LESS},
        {"@", "A", LESS},
        {"a", "aa", LESS},
        {"Case sensitive", "case sensitive", LESS},
        {"hello world", NullString(), NULL_VALUE},
        // Cyrillic UTF-8 characters
        {"ъ", "ь", LESS},
        {"", NullString(), NULL_VALUE},
  
        // bytes
        {Bytes("hello"), Bytes("hello"), EQUAL},
        {Bytes("bye"), Bytes("hello"), LESS},
        {Bytes("@"), Bytes("A"), LESS},
        {Bytes("a"), Bytes("aa"), LESS},
        {Bytes("Case sensitive"), Bytes("case sensitive"), LESS},
        {Bytes("hello world"), NullBytes(), NULL_VALUE},
        // Cyrillic UTF-8 characters
        {Bytes("ъ"), Bytes("ь"), LESS},
        {Bytes(""), NullBytes(), NULL_VALUE},
  
        // date
        {Date(1), Date(1), EQUAL},
        {Date(-1), Date(0), LESS},
        {Date(-10), Date(-1), LESS},
        {Date(1), Date(10), LESS},
        {Date(1), NullDate(), NULL_VALUE},
  
        // timestamp
        {Timestamp(1), Timestamp(1), EQUAL},
        {Timestamp(-1), Timestamp(0), LESS},
        {Timestamp(-10), Timestamp(-1), LESS},
        {Timestamp(1), Timestamp(10), LESS},
        {Timestamp(1), NullTimestamp(), NULL_VALUE},
  
        // enum
        {enum0, enum0, EQUAL},
        {enum1, enum1, EQUAL},
        {enum0, enum1, LESS},
        {enum0, Null(TestEnumType()), NULL_VALUE},
  
        // time
        // micros
        {TimeMicros(1, 2, 3, 4), TimeMicros(1, 2, 3, 4), EQUAL},
        {TimeMicros(1, 2, 3, 4), TimeMicros(1, 2, 3, 5), LESS},
        {TimeMicros(1, 2, 3, 4), TimeMicros(1, 2, 5, 4), LESS},
        {TimeMicros(1, 2, 3, 4), TimeMicros(1, 5, 3, 4), LESS},
        {TimeMicros(1, 2, 3, 4), TimeMicros(5, 2, 3, 4), LESS},
        {TimeMicros(1, 2, 3, 4), NullTime(), NULL_VALUE},
  
        // datetime
        // micros
        {DatetimeMicros(2006, 1, 2, 3, 4, 5, 654321),
         DatetimeMicros(2006, 1, 2, 3, 4, 5, 654321), EQUAL},
        {DatetimeMicros(2006, 1, 2, 3, 4, 5, 654321),
         DatetimeMicros(2006, 1, 2, 3, 4, 5, 765432), LESS},
        {DatetimeMicros(2006, 1, 2, 3, 4, 5, 654321),
         DatetimeMicros(2006, 1, 2, 3, 4, 7, 654321), LESS},
        {DatetimeMicros(2006, 1, 2, 3, 4, 5, 654321),
         DatetimeMicros(2006, 1, 2, 3, 7, 5, 654321), LESS},
        {DatetimeMicros(2006, 1, 2, 3, 4, 5, 654321),
         DatetimeMicros(2006, 1, 2, 7, 4, 5, 654321), LESS},
        {DatetimeMicros(2006, 1, 2, 3, 4, 5, 654321),
         DatetimeMicros(2006, 1, 7, 3, 4, 5, 654321), LESS},
        {DatetimeMicros(2006, 1, 2, 3, 4, 5, 654321),
         DatetimeMicros(2006, 7, 2, 3, 4, 5, 654321), LESS},
        {DatetimeMicros(2006, 1, 2, 3, 4, 5, 654321),
         DatetimeMicros(2007, 1, 2, 3, 4, 5, 654321), LESS},
        {DatetimeMicros(2006, 1, 2, 3, 4, 5, 654321), NullDatetime(), NULL_VALUE},
    };
    if (include_nano_timestamp) {
      std::vector<ComparisonTest> nano_tests = {
          // time nanos
          {TimeNanos(1, 2, 3, 1234567), TimeNanos(1, 2, 3, 1234567), EQUAL},
          {TimeNanos(1, 2, 3, 1234567), TimeNanos(1, 2, 3, 1234568), LESS},
          {TimeNanos(1, 2, 3, 1234567), TimeNanos(1, 2, 5, 1234567), LESS},
          {TimeNanos(1, 2, 3, 1234567), TimeNanos(1, 5, 3, 1234567), LESS},
          {TimeNanos(1, 2, 3, 1234567), TimeNanos(5, 2, 3, 1234567), LESS},
          {TimeNanos(1, 2, 3, 1234567), NullTime(), NULL_VALUE},
  
          // datetime nanos
          {DatetimeNanos(2006, 1, 2, 3, 4, 5, 987654321),
           DatetimeNanos(2006, 1, 2, 3, 4, 5, 987654321), EQUAL},
          {DatetimeNanos(2006, 1, 2, 3, 4, 5, 987654321),
           DatetimeNanos(2006, 1, 2, 3, 4, 5, 987654322), LESS},
          {DatetimeNanos(2006, 1, 2, 3, 4, 5, 987654321),
           DatetimeNanos(2006, 1, 2, 3, 4, 7, 987654321), LESS},
          {DatetimeNanos(2006, 1, 2, 3, 4, 5, 987654321),
           DatetimeNanos(2006, 1, 2, 3, 7, 5, 987654321), LESS},
          {DatetimeNanos(2006, 1, 2, 3, 4, 5, 987654321),
           DatetimeNanos(2006, 1, 2, 7, 4, 5, 987654321), LESS},
          {DatetimeNanos(2006, 1, 2, 3, 4, 5, 987654321),
           DatetimeNanos(2006, 1, 7, 3, 4, 5, 987654321), LESS},
          {DatetimeNanos(2006, 1, 2, 3, 4, 5, 987654321),
           DatetimeNanos(2006, 7, 2, 3, 4, 5, 987654321), LESS},
          {DatetimeNanos(2006, 1, 2, 3, 4, 5, 987654321),
           DatetimeNanos(2007, 1, 2, 3, 4, 5, 987654321), LESS},
          {DatetimeNanos(2006, 1, 2, 3, 4, 5, 987654321), NullDatetime(),
           NULL_VALUE},
      };
      v.insert(v.end(), nano_tests.begin(), nano_tests.end());
    }
    if (include_struct_comparisons) {
      std::vector<ComparisonTest> struct_equality_tests =
          GetStructComparisonTests();
      v.insert(v.end(), struct_equality_tests.begin(),
               struct_equality_tests.end());
    }
    if (include_array_comparisons) {
      // Add a few more tests for array-specific comparison behaviors.
      std::vector<ComparisonTest> array_comparison_tests =
          GetArrayComparisonTests();
  
      // Duplicate tests by nesting the values into arrays, and do the same
      // comparison on the arrays.
      for (const ComparisonTest& test : v) {
        const ArrayType* left_array_type;
        ZETASQL_CHECK_OK(type_factory()->MakeArrayType(test.left.type(),
                                               &left_array_type));
        const Value left_array = values::Array(left_array_type, {test.left});
  
        const ArrayType* right_array_type;
        ZETASQL_CHECK_OK(type_factory()->MakeArrayType(test.right.type(),
                                               &right_array_type));
        const Value right_array = values::Array(right_array_type, {test.right});
  
        // We can only compare arrays if they are the same type.  We do not
        // do implicit coercion of arrays.  So if the types of the arguments
        // are not the same then skip this test.
        if (!left_array_type->Equals(right_array_type)) {
          continue;
        }
  
        array_comparison_tests.push_back(
            ComparisonTest(left_array, right_array, test.result));
      }
      v.insert(v.end(), array_comparison_tests.begin(),
               array_comparison_tests.end());
    }
    return v;
  }
  
  // Builds a QueryParamsWithResult from <input> and <out>, and appends it
  // to <result>.  Wraps <out> with a feature set-result map if needed, in
  // the following cases:
  //
  // 1) If there is any TIME/DATETIME typed value in the input, then
  //    FEATURE_V_1_2_CIVIL_TIME is added to the feature set.
  // 2) If <array_language_feature> is present then it is added.
  // 3) If the <input> includes the NUMERIC type, then FEATURE_NUMERIC_TYPE
  //    is added.
  //
  // If none of these are true, then constructs the QueryParamsWithResult
  // directly from  <input>/<out>.
  static void AddTestWithPossiblyWrappedResultWithRequiredFeatures(
      const std::vector<ValueConstructor>& input, const Value& out,
      const absl::optional<LanguageFeature>& array_language_feature,
      std::vector<QueryParamsWithResult>* result) {
    bool has_any_civil_time = false;
    bool has_any_numeric = false;
    bool has_any_bignumeric = false;
    bool has_any_array = false;
    // Check the inputs for civil time, numeric, and arrays.
    for (const auto& each : input) {
      if (each.type()->UsingFeatureV12CivilTimeType()) {
        has_any_civil_time = true;
      }
      if (each.type()->IsNumericType()) {
        has_any_numeric = true;
      }
      if (each.type()->IsBigNumericType()) {
        has_any_bignumeric = true;
      }
      if (each.type()->IsArray()) {
        has_any_array = true;
        if (each.type()->AsArray()->element_type()->IsNumericType()) {
          has_any_numeric = true;
        }
        if (each.type()->AsArray()->element_type()->IsBigNumericType()) {
          has_any_bignumeric = true;
        }
      }
    }
    // Check the output as well.
    if (out.type()->UsingFeatureV12CivilTimeType()) {
      has_any_civil_time = true;
    }
    if (out.type()->IsNumericType()) {
      has_any_numeric = true;
    }
    if (out.type()->IsBigNumericType()) {
      has_any_bignumeric = true;
    }
    if (out.type()->IsArray()) {
      has_any_array = true;
      if (out.type()->AsArray()->element_type()->IsNumericType()) {
        has_any_numeric = true;
      }
      if (out.type()->AsArray()->element_type()->IsBigNumericType()) {
        has_any_bignumeric = true;
      }
    }
  
    // Build the feature set.
    QueryParamsWithResult::FeatureSet feature_set;
    if (has_any_civil_time) {
      feature_set.insert(FEATURE_V_1_2_CIVIL_TIME);
    }
    if (has_any_numeric) {
      feature_set.insert(FEATURE_NUMERIC_TYPE);
    }
    if (has_any_array && array_language_feature) {
      feature_set.insert(*array_language_feature);
    }
    if (has_any_bignumeric) {
      feature_set.insert(FEATURE_BIGNUMERIC_TYPE);
    }
  
    // If the feature set is not empty then wrap the output result in
    // a feature set map.
    if (!feature_set.empty()) {
      result->push_back(QueryParamsWithResult(
          input, {{feature_set, QueryParamsWithResult::Result(out)}}));
    } else {
      result->push_back(QueryParamsWithResult(input, out));
    }
  }
  
  // Wraps any test cases that use NUMERIC with FEATURE_NUMERIC_TYPE.
  static void WrapNumericTestCases(std::vector<QueryParamsWithResult>* tests) {
    for (auto& test_case : *tests) {
      if (test_case.HasEmptyFeatureSetAndNothingElse() &&
          test_case.result().type()->IsNumericType()) {
        test_case = test_case.WrapWithFeature(FEATURE_NUMERIC_TYPE);
      }
    }
  }
  
  // Wraps any test cases that use BIGNUMERIC with FEATURE_BIGNUMERIC_TYPE.
  static void WrapBigNumericTestCases(std::vector<QueryParamsWithResult>* tests) {
    for (auto& test_case : *tests) {
      if (test_case.HasEmptyFeatureSetAndNothingElse() &&
          test_case.result().type()->IsBigNumericType()) {
        test_case = test_case.WrapWithFeature(FEATURE_BIGNUMERIC_TYPE);
      }
    }
  }
  
  std::vector<QueryParamsWithResult> GetFunctionTestsEqual(
      bool include_nano_timestamp) {
    std::vector<QueryParamsWithResult> result;
    for (const ComparisonTest& test : GetComparisonTests(
             /*include_struct_comparisons=*/true,
             /*include_array_comparisons=*/true, include_nano_timestamp)) {
      Value out;
      switch (test.result) {
        case NULL_VALUE:
          out = NullBool();
          break;
        case EQUAL:
          out = True();
          break;
        case LESS:
        case UNEQUAL:
        case UNORDERED:
          out = False();
          break;
      }
      AddTestWithPossiblyWrappedResultWithRequiredFeatures(
          {test.left, test.right}, out,
          /*array_language_feature=*/FEATURE_V_1_1_ARRAY_EQUALITY, &result);
      AddTestWithPossiblyWrappedResultWithRequiredFeatures(
          {test.right, test.left}, out,
          /*array_language_feature=*/FEATURE_V_1_1_ARRAY_EQUALITY, &result);
    }
    return result;
  }
  
  std::vector<QueryParamsWithResult> GetFunctionTestsNotEqual(
      bool include_nano_timestamp) {
    std::vector<QueryParamsWithResult> result;
    for (const ComparisonTest& test : GetComparisonTests(
             /*include_struct_comparisons=*/true,
             /*include_array_comparisons=*/true, include_nano_timestamp)) {
      Value out;
      switch (test.result) {
        case NULL_VALUE:
          out = NullBool();
          break;
        case LESS:
        case UNEQUAL:
        case UNORDERED:
          out = True();
          break;
        case EQUAL:
          out = False();
          break;
      }
      AddTestWithPossiblyWrappedResultWithRequiredFeatures(
          {test.left, test.right}, out,
          /*array_language_feature=*/FEATURE_V_1_1_ARRAY_EQUALITY, &result);
      AddTestWithPossiblyWrappedResultWithRequiredFeatures(
          {test.right, test.left}, out,
          /*array_language_feature=*/FEATURE_V_1_1_ARRAY_EQUALITY, &result);
    }
    return result;
  }
  
  std::vector<QueryParamsWithResult> GetFunctionTestsGreater(
      bool include_nano_timestamp) {
    std::vector<QueryParamsWithResult> result;
    for (const ComparisonTest& test : GetComparisonTests(
             /*include_struct_comparisons=*/false,
             /*include_array_comparisons=*/true, include_nano_timestamp)) {
      Value out;
      switch (test.result) {
        case NULL_VALUE:
          out = NullBool();
          break;
        case LESS:
        case EQUAL:
        case UNORDERED:
          out = False();
          break;
        case UNEQUAL:
          out = NullBool();
          break;
      }
      AddTestWithPossiblyWrappedResultWithRequiredFeatures(
          {test.left, test.right}, out,
          /*array_language_feature=*/FEATURE_V_1_3_ARRAY_ORDERING, &result);
      AddTestWithPossiblyWrappedResultWithRequiredFeatures(
          {test.right, test.left}, (test.result == LESS) ? True() : out,
          /*array_language_feature=*/FEATURE_V_1_3_ARRAY_ORDERING, &result);
    }
    return result;
  }
  
  std::vector<QueryParamsWithResult> GetFunctionTestsGreaterOrEqual(
      bool include_nano_timestamp) {
    std::vector<QueryParamsWithResult> result;
    for (const ComparisonTest& test : GetComparisonTests(
             /*include_struct_comparisons=*/false,
             /*include_array_comparisons=*/true, include_nano_timestamp)) {
      Value out;
      switch (test.result) {
        case NULL_VALUE:
          out = NullBool();
          break;
        case EQUAL:
          out = True();
          break;
        case LESS:
        case UNORDERED:
          out = False();
          break;
        case UNEQUAL:
          out = NullBool();
          break;
      }
      AddTestWithPossiblyWrappedResultWithRequiredFeatures(
          {test.left, test.right}, out,
          /*array_language_feature=*/FEATURE_V_1_3_ARRAY_ORDERING, &result);
      AddTestWithPossiblyWrappedResultWithRequiredFeatures(
          {test.right, test.left}, (test.result == LESS) ? True() : out,
          /*array_language_feature=*/FEATURE_V_1_3_ARRAY_ORDERING, &result);
    }
    return result;
  }
  
  std::vector<QueryParamsWithResult> GetFunctionTestsLess(
      bool include_nano_timestamp) {
    std::vector<QueryParamsWithResult> result;
    for (const ComparisonTest& test : GetComparisonTests(
             /*include_struct_comparisons=*/false,
             /*include_array_comparisons=*/true, include_nano_timestamp)) {
      Value out;
      switch (test.result) {
        case NULL_VALUE:
          out = NullBool();
          break;
        case LESS:
          out = True();
          break;
        case EQUAL:
        case UNORDERED:
          out = False();
          break;
        case UNEQUAL:
          out = NullBool();
          break;
      }
      AddTestWithPossiblyWrappedResultWithRequiredFeatures(
          {test.left, test.right}, out,
          /*array_language_feature=*/FEATURE_V_1_3_ARRAY_ORDERING, &result);
      AddTestWithPossiblyWrappedResultWithRequiredFeatures(
          {test.right, test.left}, (test.result == LESS) ? False() : out,
          /*array_language_feature=*/FEATURE_V_1_3_ARRAY_ORDERING, &result);
    }
    return result;
  }
  
  std::vector<QueryParamsWithResult> GetFunctionTestsLessOrEqual(
      bool include_nano_timestamp) {
    std::vector<QueryParamsWithResult> result;
    for (const ComparisonTest& test : GetComparisonTests(
             /*include_struct_comparisons=*/false,
             /*include_array_comparisons=*/true, include_nano_timestamp)) {
      Value out;
      switch (test.result) {
        case NULL_VALUE:
          out = NullBool();
          break;
        case EQUAL:
        case LESS:
          out = True();
          break;
        case UNORDERED:
          out = False();
          break;
        case UNEQUAL:
          out = NullBool();
          break;
      }
      AddTestWithPossiblyWrappedResultWithRequiredFeatures(
          {test.left, test.right}, out,
          /*array_language_feature=*/FEATURE_V_1_3_ARRAY_ORDERING, &result);
      AddTestWithPossiblyWrappedResultWithRequiredFeatures(
          {test.right, test.left}, (test.result == LESS) ? False() : out,
          /*array_language_feature=*/FEATURE_V_1_3_ARRAY_ORDERING, &result);
    }
    return result;
  }
  
  std::vector<QueryParamsWithResult> GetFunctionTestsInWithoutNulls() {
    std::vector<std::array<Value, 3>> type_sets = {
        {{String("a"), String("foo"), String("3523523zz5")}},
        {{Int32(4), Int32(-1), Int32(6)}},
        {{Int64(std::numeric_limits<int64_t>::lowest()), Int64(-1),
          Int64(std::numeric_limits<int64_t>::max())}},
        {{Float(std::numeric_limits<float>::lowest()),
          Float(std::numeric_limits<float>::max()),
          Float(std::numeric_limits<float>::min())}},
        {{Float(0.0f), Float(INFINITY), Float(-INFINITY)}},
        {{Double(0.0f), Double(INFINITY), Double(-INFINITY)}},
        {{Float(4.0f), Float(2.0), Float(8.0)}},
        {{Double(4.0f), Double(2.0), Double(8.0)}},
        {{Double(std::numeric_limits<double>::lowest()),
          Double(std::numeric_limits<double>::max()),
          Double(std::numeric_limits<double>::min())}},
    };
    std::vector<QueryParamsWithResult> ret;
    Value null_bool = NullBool();
    for (const auto& type_set : type_sets) {
      const Value& a = type_set[0];
      const Value& b = type_set[1];
      const Value& c = type_set[2];
      Value null = Value::Null(a.type());
      ret.insert(
          ret.end(),
          {
              // True.
              {{a, a}, true},
              {{a, a, b}, true},
              {{a, b, a}, true},
              {{b, a, b, c}, true},
              {{c, a, c}, true},
              {{b, b, c, a}, true},
              {{b, b, b, a, a}, true},
              {{b, b, b, b}, true},
              // False.
              {{a, b}, false},
              {{b, a, c}, false},
              {{b, a, a, c, c}, false},
              {{c, a, b, b}, false},
              // NULL first.
              {{null, a}, null_bool},
              {{null, a, b}, null_bool},
              {{null, a, b, c}, null_bool},
              {{null, b, b, a, a}, null_bool},
              {{null, b, b, b}, null_bool},
          });
    }
  
    auto nanf = Float(std::nanf(""));
    auto nan = Double(std::nan(""));
    ret.insert(ret.end(),
               {
                   // 0.0 == -0.0
                   {{Float(0.0f), Float(-0.0f)}, true},
                   {{Float(0.0f), Float(-0.0f), Float(3.14f)}, true},
                   {{Float(0.0f), Float(1.0f), Float(-0.0f), Float(3.14f)}, true},
                   {{Float(-0.0f), Float(0.0f)}, true},
                   {{Float(-0.0f), Float(0.0f), Float(3.14f)}, true},
                   {{Float(-0.0f), Float(1.0f), Float(0.0f), Float(3.14f)}, true},
                   {{Double(0.0), Double(-0.0)}, true},
                   {{Double(0.0), Double(-0.0), Double(3.14)}, true},
                   {{Double(0.0), Double(1), Double(-0.0), Double(3.14)}, true},
                   {{Double(-0.0), Double(0.0)}, true},
                   {{Double(-0.0), Double(0.0), Double(3.14)}, true},
                   {{Double(-0.0), Double(1), Double(0.0), Double(3.14)}, true},
                   // NaN != NaN
                   {{nanf, nanf}, false},
                   {{nanf, nanf, Float(3.14f)}, false},
                   {{nanf, Float(2.0f), nanf, Float(3.14f)}, false},
                   {{nan, nan}, false},
                   {{nan, nan, Double(3.14)}, false},
                   {{nan, Double(2), nan, Double(3.14)}, false},
                   // Bools.
                   {{true, true}, true},
                   {{false, false}, true},
                   {{true, false}, false},
                   {{false, true}, false},
                   {{true, true, false}, true},
                   {{false, true, false}, true},
                   {{null_bool, true}, null_bool},
               });
    return ret;
  }
  
  std::vector<QueryParamsWithResult> GetFunctionTestsInWithNulls() {
    std::vector<std::array<Value, 3>> type_sets = {
        {{String("a"), String("foo"), String("3523523zz5")}},
        {{Int32(4), Int32(-1), Int32(6)}},
        {{Int64(std::numeric_limits<int64_t>::lowest()), Int64(-1),
          Int64(std::numeric_limits<int64_t>::max())}},
        {{Float(std::numeric_limits<float>::lowest()),
          Float(std::numeric_limits<float>::max()),
          Float(std::numeric_limits<float>::min())}},
        {{Float(0.0f), Float(INFINITY), Float(-INFINITY)}},
        {{Double(0.0f), Double(INFINITY), Double(-INFINITY)}},
        {{Float(4.0f), Float(2.0), Float(8.0)}},
        {{Double(4.0f), Double(2.0), Double(8.0)}},
        {{Double(std::numeric_limits<double>::lowest()),
          Double(std::numeric_limits<double>::max()),
          Double(std::numeric_limits<double>::min())}},
    };
    std::vector<QueryParamsWithResult> ret;
    Value null_bool = NullBool();
    for (const auto& type_set : type_sets) {
      const Value& a = type_set[0];
      const Value& b = type_set[1];
      const Value& c = type_set[2];
      Value null = Value::Null(a.type());
      ret.insert(
          ret.end(),
          {
              // True with NULLs.
              {{a, a, null}, true},
              {{a, null, a}, true},
              {{a, a, null, null}, true},
              {{a, null, a}, true},
              {{a, null, null, a}, true},
              {{a, null, a, null}, true},
              {{a, null, null, a, null, null, a}, true},
              {{b, null, null, a, null, null, b}, true},
              {{b, null, null, a, null, null, b, null, b, null, a, null, null},
               true},
              // Not-True with NULLs.
              {{b, a, null}, null_bool},
              {{b, null, c}, null_bool},
              {{b, a, null, null}, null_bool},
              {{b, null, c}, null_bool},
              {{b, null, null, a}, null_bool},
              {{b, null, c, null}, null_bool},
              {{b, null, null, a, null, null, a}, null_bool},
              {{b, null, null, a, null, null, c}, null_bool},
              {{b, null, null, a, null, null, c, null, c, null, a, null, null},
               null_bool},
              // NULL first.
              {{null, b, null}, null_bool},
              {{null, null, c, null}, null_bool},
          });
    }
  
    ret.insert(ret.end(),
               {
                   {{true, true, null_bool}, true},
                   {{false, false, null_bool}, true},
                   {{true, false, null_bool}, null_bool},
                   {{false, true, null_bool}, null_bool},
                   {{true, true, false, null_bool}, true},
                   {{false, true, false, null_bool}, true},
               });
    return ret;
  }
  
  std::vector<QueryParamsWithResult> GetFunctionTestsIn() {
    std::vector<QueryParamsWithResult> ret = GetFunctionTestsInWithNulls();
    std::vector<QueryParamsWithResult> tests_without_nulls =
        GetFunctionTestsInWithoutNulls();
    ret.insert(ret.end(), tests_without_nulls.begin(), tests_without_nulls.end());
    return ret;
  }
  
  std::vector<QueryParamsWithResult> GetFunctionTestsStructIn() {
    const StructType* struct_type = SimpleStructType();  // a: string, b: int32_t
    const Value struct0 = Value::Struct(struct_type, {String("foo"), Int32(0)});
    const Value struct1 = Value::Struct(struct_type, {String("bar"), Int32(1)});
    const Value struct2 = Value::Struct(struct_type, {String("baz"), Int32(2)});
    const Value struct1_with_null1 =
        Value::Struct(struct_type, {NullString(), Int32(1)});
    const Value struct1_with_null2 =
        Value::Struct(struct_type, {String("bar"), NullInt32()});
    const Value struct_with_all_nulls =
        Value::Struct(struct_type, {NullString(), NullInt32()});
    const Value null_struct = Value::Null(struct_type);
    // These DCHECKs are only here to more clearly show the contents of
    // all the struct values.
    ZETASQL_DCHECK_EQ("(\"foo\", 0)",    struct0.GetSQLLiteral());
    ZETASQL_DCHECK_EQ("(\"bar\", 1)",    struct1.GetSQLLiteral());
    ZETASQL_DCHECK_EQ("(\"baz\", 2)",    struct2.GetSQLLiteral());
    ZETASQL_DCHECK_EQ("(NULL, 1)",       struct1_with_null1.GetSQLLiteral());
    ZETASQL_DCHECK_EQ("(\"bar\", NULL)", struct1_with_null2.GetSQLLiteral());
    ZETASQL_DCHECK_EQ("(NULL, NULL)",    struct_with_all_nulls.GetSQLLiteral());
    ZETASQL_DCHECK_EQ("NULL",            null_struct.GetSQLLiteral());
  
    return {
      {{struct0, struct0}, True()},
      {{struct0, struct1}, False()},
      {{struct0, struct0, struct1, struct2}, True()},
      {{struct1, struct0, struct1, struct2}, True()},
      {{struct2, struct0, struct1, struct2}, True()},
  
      {{struct0, struct1, struct2}, False()},
      {{struct0, struct1_with_null1, struct0}, True()},
      {{struct0, struct1_with_null2, struct0}, True()},
      {{struct0, struct_with_all_nulls, struct0}, True()},
      {{struct0, null_struct, struct0}, True()},
      {{struct0, null_struct, struct0}, True()},
      {{struct0, struct1_with_null1}, False()},
      {{struct0, struct1_with_null2}, False()},
      {{struct0, struct_with_all_nulls}, NullBool()},
      {{struct0, null_struct}, NullBool()},
  
      {{struct1, struct1_with_null1, struct0}, NullBool()},
      {{struct1, struct1_with_null2, struct0}, NullBool()},
      {{struct0, struct_with_all_nulls}, NullBool()},
      {{struct1, struct_with_all_nulls}, NullBool()},
      {{struct2, struct_with_all_nulls}, NullBool()},
  
      {{struct1_with_null1, struct1_with_null1}, NullBool()},
      {{struct1_with_null1, struct0, struct1}, NullBool()},
      {{struct1_with_null2, struct1_with_null2}, NullBool()},
      {{struct1_with_null2, struct0, struct1}, NullBool()},
      {{struct1_with_null2, struct0}, False()},
      {{struct1_with_null2, struct0}, False()},
  
      {{struct_with_all_nulls, struct0}, NullBool()},
      {{struct_with_all_nulls, struct1}, NullBool()},
      {{struct_with_all_nulls, struct2}, NullBool()},
      {{struct_with_all_nulls, struct1_with_null1}, NullBool()},
      {{struct_with_all_nulls, struct1_with_null2}, NullBool()},
      {{struct_with_all_nulls, struct_with_all_nulls}, NullBool()},
      {{struct_with_all_nulls, null_struct}, NullBool()},
  
      {{null_struct, struct0}, NullBool()},
      {{null_struct, struct1}, NullBool()},
      {{null_struct, struct2}, NullBool()},
      {{null_struct, struct1_with_null1}, NullBool()},
      {{null_struct, struct1_with_null2}, NullBool()},
      {{null_struct, struct_with_all_nulls}, NullBool()},
      {{null_struct, null_struct}, NullBool()},
    };
  }
  
  std::vector<QueryParamsWithResult> GetFunctionTestsIsNull() {
    const ArrayType* struct_array_type = MakeArrayType(SimpleStructType());
    const ArrayType* nullable_int_array_type =
        MakeArrayType(NullableIntProtoType());
    std::vector<QueryParamsWithResult> v = {
        // Simple types.
        {{NullInt32()},                                           True()},
        {{NullInt64()},                                           True()},
        {{NullUint32()},                                          True()},
        {{NullUint64()},                                          True()},
        {{NullBool()},                                            True()},
        {{NullFloat()},                                           True()},
        {{NullDouble()},                                          True()},
        {{NullString()},                                          True()},
        {{NullBytes()},                                           True()},
  
        {{Int32(1)},                                              False()},
        {{Int64(1)},                                              False()},
        {{Uint32(1)},                                             False()},
        {{Uint64(1)},                                             False()},
        {{True()},                                                False()},
        {{False()},                                               False()},
        {{Float(1.1)},                                            False()},
        {{Double(1.1)},                                           False()},
        {{String("a")},                                           False()},
        {{Bytes("b")},                                            False()},
  
        // Date and timestamp types.
        {{NullDate()},                                            True()},
        {{NullTimestamp()},                                       True()},
  
        {{Date(0)},                                               False()},
        {{Timestamp(0)},                                          False()},
  
        // Enum types.
        {{Value::Null(TestEnumType())},                           True()},
        {{Value::Enum(TestEnumType(), 0)},                        False()},
  
        // Proto types.
        {{Value::Null(KitchenSinkProtoType())},                   True()},
        {{Value::Null(NullableIntProtoType())},                   True()},
  
        {{KitchenSink("int64_key_1: 1 int64_key_2: 2")},          False()},
        {{NullableInt("")},                                       False()},
        {{NullableInt("value: 1")},                               False()},
  
        // Struct types.
        {{Value::Null(SimpleStructType())},                       True()},
        {{Value::Null(AnotherStructType())},                      True()},
  
        {{Value::Struct(SimpleStructType(),
                        {String("a"), Int32(1)})},                False()},
        {{Value::Struct(SimpleStructType(),
                        {NullString(), NullInt32()})},            False()},
  
        // Array types.
        {{Value::Null(Int32ArrayType())},                         True()},
        {{Value::Null(Uint32ArrayType())},                        True()},
        {{Value::Null(BoolArrayType())},                          True()},
        {{Value::Null(DoubleArrayType())},                        True()},
        {{Value::Null(StringArrayType())},                        True()},
        {{Value::Null(BytesArrayType())},                         True()},
        {{Value::Null(struct_array_type)},                        True()},
        {{Value::Null(nullable_int_array_type)},                  True()},
  
        {{Value::Array(Int64ArrayType(), {}/* empty_array */)},   False()},
        {{Value::Array(Int64ArrayType(), {Int64(0), Int64(1)})},  False()},
        {{Value::Array(Int64ArrayType(),
                       {NullInt64(), NullInt64()})},              False()},
        {{Value::Array(StringArrayType(),
                       {String("a"), String("b")})},              False()},
        {{Value::Array(struct_array_type,
                       {Value::Struct(SimpleStructType(),
                                      {NullString(),
                                       NullInt32()})})},          False()},
        {{Value::Array(nullable_int_array_type,
                       {NullableInt("")})},                       False()},
    };
    return v;
  }
  
  std::vector<QueryParamsWithResult> GetFunctionTestsGreatest(
      bool include_nano_timestamp) {
    std::vector<QueryParamsWithResult> result;
    for (const ComparisonTest& test : GetComparisonTests(
             /*include_struct_comparisons=*/false,
             /*include_array_comparisons=*/false, include_nano_timestamp)) {
      // TODO: This should be 'Equivalent()', not 'Equals()'.  Need
      // to add tests that illustrate the difference.
      if (!test.left.type()->Equals(test.right.type())) {
        continue;  // Inputs to Greatest must all be of the same type.
      }
      Value out;
      switch (test.result) {
        case NULL_VALUE:
          out = Value::Null(test.left.type()); break;
        case LESS:
        case EQUAL:
          out = test.right; break;
        case UNORDERED:  // NaN
          out = test.GetNaN(); break;
        case UNEQUAL:
          // The UNEQUAL test result type is currently only used for ARRAY
          // comparisons, but GREATEST/LEAST do not support ARRAYS so this
          // is an unexpected condition.
          ZETASQL_CHECK_NE(test.result, UNEQUAL)
              << "Unexpected comparison test result type:" << test.result;
      }
      // Binary
      AddTestWithPossiblyWrappedResultWithRequiredFeatures(
          {test.left, test.right}, out,
          /*array_language_feature=*/absl::optional<LanguageFeature>(), &result);
      // Ternary
      AddTestWithPossiblyWrappedResultWithRequiredFeatures(
          {test.right, test.left, test.right}, out,
          /*array_language_feature=*/absl::optional<LanguageFeature>(), &result);
    }
    return result;
  }
  
  std::vector<QueryParamsWithResult> GetFunctionTestsLeast(
      bool include_nano_timestamp) {
    std::vector<QueryParamsWithResult> result;
    for (const ComparisonTest& test : GetComparisonTests(
             /*include_struct_comparisons=*/false,
             /*include_array_comparisons=*/false, include_nano_timestamp)) {
      // TODO: This should be 'Equivalent()', not 'Equals()'.  Need
      // to add tests that illustrate the difference.
      if (!test.left.type()->Equals(test.right.type())) {
        continue;  // Inputs to Least must all be of the same type.
      }
      Value out;
      switch (test.result) {
        case NULL_VALUE:
          out = Value::Null(test.left.type()); break;
        case LESS:
        case EQUAL:
          out = test.left; break;
        case UNORDERED:  // NaN
          out = test.GetNaN(); break;
        case UNEQUAL:
          // The UNEQUAL test result type is currently only used for ARRAY
          // comparisons, but GREATEST/LEAST do not support ARRAYS so this
          // is an unexpected condition.
          ZETASQL_CHECK_NE(test.result, UNEQUAL)
              << "Unexpected comparison test result type:" << test.result;
      }
      // Binary
      AddTestWithPossiblyWrappedResultWithRequiredFeatures(
          {test.left, test.right}, out,
          /*array_language_feature=*/absl::optional<LanguageFeature>(), &result);
      // Ternary
      AddTestWithPossiblyWrappedResultWithRequiredFeatures(
          {test.right, test.left, test.right}, out,
          /*array_language_feature=*/absl::optional<LanguageFeature>(), &result);
    }
    return result;
  }
  
  // FromType is in {float, double}. ToType is in {int32_t, uint32_t, int64_t, uint64_t}.
  template <typename FromType, typename ToType>
  static std::vector<QueryParamsWithResult> TestCastPositiveRounding() {
    return {
      {{Value::Make<FromType>(1.1)}, Value::Make<ToType>(1)},
      {{Value::Make<FromType>(1.5)}, Value::Make<ToType>(2)},
      {{Value::Make<FromType>(1.9)}, Value::Make<ToType>(2)},
      {{Value::Make<FromType>(2.5)}, Value::Make<ToType>(3)},
    };
  }
  
  // FromType = {float, double}. ToType = {int32_t, int64_t}.
  template <typename FromType, typename ToType>
  static std::vector<QueryParamsWithResult> TestCastNegativeRounding() {
    return {
      {{Value::Make<FromType>(-1.1)}, Value::Make<ToType>(-1)},
      {{Value::Make<FromType>(-1.5)}, Value::Make<ToType>(-2)},
      {{Value::Make<FromType>(-1.9)}, Value::Make<ToType>(-2)},
      {{Value::Make<FromType>(-2.5)}, Value::Make<ToType>(-3)},
    };
  }
  
  // FromType is in {float, double}. ToType is in {int32_t, uint32_t, int64_t, uint64_t,
  // bool}.
  template <typename FromType, typename ToType>
  static std::vector<QueryParamsWithResult> TestCastInfinityError() {
    return {
        {{Value::Make<FromType>(std::numeric_limits<FromType>::quiet_NaN())},
         Value::MakeNull<ToType>(),
         OUT_OF_RANGE},
        {{Value::Make<FromType>(std::numeric_limits<FromType>::infinity())},
         Value::MakeNull<ToType>(),
         OUT_OF_RANGE},
        {{Value::Make<FromType>(-std::numeric_limits<FromType>::infinity())},
         Value::MakeNull<ToType>(),
         OUT_OF_RANGE},
    };
  }
  
  // FromType = {int32_t, int64_t, uint32_t, uint64_t, float, double}.
  template <typename FromType>
  static std::vector<QueryParamsWithResult> TestCastNumericNull() {
    const Value& from_null = Value::MakeNull<FromType>();
    return {
      {{from_null}, NullInt32()},
      {{from_null}, NullInt64()},
      {{from_null}, NullUint32()},
      {{from_null}, NullUint64()},
      {{from_null}, NullFloat()},
      {{from_null}, NullDouble()},
    };
  }
  
  std::vector<QueryParamsWithResult> GetFunctionTestsBitwiseNot() {
    return {
      {{NullInt32()}, NullInt32()},
      {{NullInt64()}, NullInt64()},
      {{NullUint32()}, NullUint32()},
      {{NullUint64()}, NullUint64()},
      {{NullBytes()}, NullBytes()},
  
      {{Int32(-1)}, Int32(0) },
      {{Int32(0)}, Int32(-1) },
      {{Int32(-2)}, Int32(1) },
      {{Int32(1)}, Int32(-2) },
      {{Int32(0xAAAAAAAA)}, Int32(0x55555555) },
      {{Int32(0x55555555)}, Int32(0xAAAAAAAA) },
  
      {{Int64(-1)}, Int64(0) },
      {{Int64(0)}, Int64(-1) },
      {{Int64(-2)}, Int64(1) },
      {{Int64(1)}, Int64(-2) },
      {{Int64(0xAAAAAAAAAAAAAAAA)}, Int64(0x5555555555555555) },
      {{Int64(0x5555555555555555)}, Int64(0xAAAAAAAAAAAAAAAA) },
  
      {{Uint32(0xFFFFFFFF)}, Uint32(0) },
      {{Uint32(0)}, Uint32(0xFFFFFFFF) },
      {{Uint32(0xAAAAAAAA)}, Uint32(0x55555555) },
      {{Uint32(0x55555555)}, Uint32(0xAAAAAAAA) },
  
      {{Uint64(0xFFFFFFFFFFFFFFFF)}, Uint64(0) },
      {{Uint64(0)}, Uint64(0xFFFFFFFFFFFFFFFF) },
      {{Uint64(0xAAAAAAAAAAAAAAAA)}, Uint64(0x5555555555555555) },
      {{Uint64(0x5555555555555555)}, Uint64(0xAAAAAAAAAAAAAAAA) },
  
      {{Bytes("")}, Bytes("") },
      {{Bytes("\0")}, Bytes("\xFF") },
      {{Bytes("\xFF")}, Bytes("\0") },
      {{Bytes("\x01\x23\x45\x67\x89\xAB\xCD\xEF\x55\xAA")},
          Bytes("\xFE\xDC\xBA\x98\x76\x54\x32\x10\xAA\x55") },
      {{Bytes("\xFE\xDC\xBA\x98\x76\x54\x32\x10\xAA\x55")},
          Bytes("\x01\x23\x45\x67\x89\xAB\xCD\xEF\x55\xAA") },
    };
  }
  
  std::vector<QueryParamsWithResult> GetFunctionTestsBitwiseOr() {
    return {
      {{NullInt32(), Int32(0)}, NullInt32()},
      {{Int32(1), NullInt32()}, NullInt32()},
      {{NullInt64(), Int64(2)}, NullInt64()},
      {{Int64(3), NullInt64()}, NullInt64()},
      {{NullUint32(), Uint32(4)}, NullUint32()},
      {{Uint32(5), NullUint32()}, NullUint32()},
      {{NullUint64(), Uint64(6)}, NullUint64()},
      {{Uint64(7), NullUint64()}, NullUint64()},
      {{NullBytes(), Bytes("foo")}, NullBytes()},
      {{Bytes("foo"), NullBytes()}, NullBytes()},
  
      {{Int32(0), Int32(0)}, Int32(0)},
      {{Int32(-1), Int32(0)}, Int32(-1)},
      {{Int32(0xAAAAAAAA), Int32(0x55555555)}, Int32(-1)},
      {{Int32(0), Int32(1)}, Int32(1)},
      {{Int32(2), Int32(1)}, Int32(3)},
      {{Int32(0xFF), Int32(1)}, Int32(0xFF)},
  
      {{Int64(0), Int64(0)}, Int64(0)},
      {{Int64(-1), Int64(0)}, Int64(-1)},
      {{Int64(0xAAAAAAAAAAAAAAAA), Int64(0x5555555555555555)}, Int64(-1)},
      {{Int64(0), Int64(1)}, Int64(1)},
      {{Int64(2), Int64(1)}, Int64(3)},
      {{Int64(0xFF), Int64(1)}, Int64(0xFF)},
  
      {{Uint32(0), Uint32(0)}, Uint32(0)},
      {{Uint32(0xFFFFFFFFU), Uint32(0)}, Uint32(0xFFFFFFFFU)},
      {{Uint32(0xAAAAAAAA), Uint32(0x55555555)}, Uint32(0xFFFFFFFFU)},
      {{Uint32(0), Uint32(1)}, Uint32(1)},
      {{Uint32(2), Uint32(1)}, Uint32(3)},
      {{Uint32(0xFF), Uint32(1)}, Uint32(0xFF)},
  
      {{Uint64(0), Uint64(0)}, Uint64(0)},
      {{Uint64(0xFFFFFFFFFFFFFFFFU), Uint64(0)}, Uint64(0xFFFFFFFFFFFFFFFFU)},
      {{Uint64(0xAAAAAAAAAAAAAAAA), Uint64(0x5555555555555555)},
          Uint64(0xFFFFFFFFFFFFFFFFU)},
      {{Uint64(0), Uint64(1)}, Uint64(1)},
      {{Uint64(2), Uint64(1)}, Uint64(3)},
      {{Uint64(0xFF), Uint64(1)}, Uint64(0xFF)},
  
      {{Bytes(""), Bytes("")}, Bytes("") },
      {{Bytes("\0"), Bytes("\xFF")}, Bytes("\xFF") },
      {{Bytes("\0\xFF"), Bytes("\xFF\0")}, Bytes("\xFF\xFF") },
      {{Bytes("\xAA\xAA\xAA\xAA\xAA"), Bytes("\x55\x55\x55\x55\x55")},
          Bytes("\xFF\xFF\xFF\xFF\xFF") },
      {{Bytes("\x01\x23\x45\x67\x89\xAB\xCD\xEF\xFE\xDC\xBA"),
        Bytes("\x12\x34\x56\x78\x9A\xBC\xDE\xF0\x0F\xED\xCB")},
          Bytes("\x13\x37\x57\x7F\x9B\xBF\xDF\xFF\xFF\xFD\xFB") },
      {{Bytes(""), Bytes("\xFF")}, NullBytes(), OUT_OF_RANGE },
    };
  }
  
  std::vector<QueryParamsWithResult> GetFunctionTestsBitwiseXor() {
    return {
      {{NullInt32(), Int32(0)}, NullInt32()},
      {{Int32(1), NullInt32()}, NullInt32()},
      {{NullInt64(), Int64(2)}, NullInt64()},
      {{Int64(3), NullInt64()}, NullInt64()},
      {{NullUint32(), Uint32(4)}, NullUint32()},
      {{Uint32(5), NullUint32()}, NullUint32()},
      {{NullUint64(), Uint64(6)}, NullUint64()},
      {{Uint64(7), NullUint64()}, NullUint64()},
      {{NullBytes(), Bytes("foo")}, NullBytes()},
      {{Bytes("foo"), NullBytes()}, NullBytes()},
  
      {{Int32(0), Int32(0)}, Int32(0)},
      {{Int32(-1), Int32(0)}, Int32(-1)},
      {{Int32(-1), Int32(-1)}, Int32(0)},
      {{Int32(0xAAAAAAAA), Int32(0x55555555)}, Int32(-1)},
      {{Int32(0xAAAAAAAA), Int32(0xFFFFFFFF)}, Int32(0x55555555)},
      {{Int32(2), Int32(1)}, Int32(3)},
  
      {{Int64(0), Int64(0)}, Int64(0)},
      {{Int64(-1), Int64(0)}, Int64(-1)},
      {{Int64(-1), Int64(-1)}, Int64(0)},
      {{Int64(0xAAAAAAAAAAAAAAAA), Int64(0x5555555555555555)}, Int64(-1)},
      {{Int64(0xAAAAAAAAAAAAAAAA), Int64(0xFFFFFFFFFFFFFFFF)},
          Int64(0x5555555555555555)},
      {{Int64(2), Int64(1)}, Int64(3)},
  
      {{Uint32(0), Uint32(0)}, Uint32(0)},
      {{Uint32(0xFFFFFFFFU), Uint32(0)}, Uint32(0xFFFFFFFFU)},
      {{Uint32(0xFFFFFFFFU), Uint32(0xFFFFFFFFU)}, Uint32(0)},
      {{Uint32(0xAAAAAAAAU), Uint32(0x55555555U)}, Uint32(0xFFFFFFFFU)},
      {{Uint32(0xAAAAAAAAU), Uint32(0xFFFFFFFFU)}, Uint32(0x55555555U)},
      {{Uint32(2), Uint32(1)}, Uint32(3)},
  
      {{Uint64(0), Uint64(0)}, Uint64(0)},
      {{Uint64(0xFFFFFFFFFFFFFFFFU), Uint64(0)}, Uint64(0xFFFFFFFFFFFFFFFFU)},
      {{Uint64(0xFFFFFFFFFFFFFFFFU), Uint64(0xFFFFFFFFFFFFFFFFU)}, Uint64(0)},
      {{Uint64(0xAAAAAAAAAAAAAAAAU), Uint64(0x5555555555555555U)},
          Uint64(0xFFFFFFFFFFFFFFFFU)},
      {{Uint64(0xAAAAAAAAAAAAAAAAU), Uint64(0xFFFFFFFFFFFFFFFFU)},
          Uint64(0x5555555555555555U)},
      {{Uint64(2), Uint64(1)}, Uint64(3)},
  
      {{Bytes(""), Bytes("")}, Bytes("") },
      {{Bytes("\0"), Bytes("\xFF")}, Bytes("\xFF") },
      {{Bytes("\0\xFF"), Bytes("\xFF\0")}, Bytes("\xFF\xFF") },
      {{Bytes("\xAA\xAA\xAA\xAA\xAA"), Bytes("\x55\x55\x55\x55\x55")},
          Bytes("\xFF\xFF\xFF\xFF\xFF") },
      {{Bytes("\x01\x23\x45\x67\x89\xAB\xCD\xEF\xFE\xDC\xBA"),
        Bytes("\x12\x34\x56\x78\x9A\xBC\xDE\xF0\x0F\xED\xCB")},
          Bytes("\x13\x17\x13\x1F\x13\x17\x13\x1F\xF1\x31\x71") },
      {{Bytes(""), Bytes("\xFF")}, NullBytes(), OUT_OF_RANGE },
    };
  }
  
  std::vector<QueryParamsWithResult> GetFunctionTestsBitwiseAnd() {
    return {
      {{NullInt32(), Int32(0)}, NullInt32()},
      {{Int32(1), NullInt32()}, NullInt32()},
      {{NullInt64(), Int64(2)}, NullInt64()},
      {{Int64(3), NullInt64()}, NullInt64()},
      {{NullUint32(), Uint32(4)}, NullUint32()},
      {{Uint32(5), NullUint32()}, NullUint32()},
      {{NullUint64(), Uint64(6)}, NullUint64()},
      {{Uint64(7), NullUint64()}, NullUint64()},
      {{NullBytes(), Bytes("foo")}, NullBytes()},
      {{Bytes("foo"), NullBytes()}, NullBytes()},
  
      {{Int32(0), Int32(0)}, Int32(0)},
      {{Int32(-1), Int32(0)}, Int32(0)},
      {{Int32(0xAAAAAAAA), Int32(0x55555555)}, Int32(0)},
      {{Int32(0xAAAAAAAA), Int32(0xFFFFFFFF)}, Int32(0xAAAAAAAA)},
      {{Int32(0xAAAAAAAA), Int32(0xF0F0F0F0)}, Int32(0xA0A0A0A0)},
  
      {{Int64(0), Int64(0)}, Int64(0)},
      {{Int64(-1), Int64(0)}, Int64(0)},
      {{Int64(0xAAAAAAAAAAAAAAAA), Int64(0x5555555555555555)}, Int64(0)},
      {{Int64(0xAAAAAAAAAAAAAAAA), Int64(0xFFFFFFFFFFFFFFFF)},
          Int64(0xAAAAAAAAAAAAAAAA)},
      {{Int64(0xAAAAAAAAAAAAAAAA), Int64(0xF0F0F0F0F0F0F0F0)},
          Int64(0xA0A0A0A0A0A0A0A0)},
  
      {{Uint32(0), Uint32(0)}, Uint32(0)},
      {{Uint32(0xFFFFFFFFU), Uint32(0)}, Uint32(0)},
      {{Uint32(0xAAAAAAAAU), Uint32(0x55555555U)}, Uint32(0)},
      {{Uint32(0xAAAAAAAAU), Uint32(0xFFFFFFFFU)}, Uint32(0xAAAAAAAAU)},
      {{Uint32(0xAAAAAAAAU), Uint32(0xF0F0F0F0U)}, Uint32(0xA0A0A0A0U)},
  
      {{Uint64(0), Uint64(0)}, Uint64(0)},
      {{Uint64(0xFFFFFFFFFFFFFFFFU), Uint64(0)}, Uint64(0)},
      {{Uint64(0xAAAAAAAAAAAAAAAAU), Uint64(0x5555555555555555U)}, Uint64(0)},
      {{Uint64(0xAAAAAAAAAAAAAAAAU), Uint64(0xFFFFFFFFFFFFFFFFU)},
          Uint64(0xAAAAAAAAAAAAAAAAU)},
      {{Uint64(0xAAAAAAAAAAAAAAAAU), Uint64(0xF0F0F0F0F0F0F0F0U)},
          Uint64(0xA0A0A0A0A0A0A0A0U)},
  
      {{Bytes(""), Bytes("")}, Bytes("") },
      {{Bytes("\0"), Bytes("\xFF")}, Bytes("\0")},
      {{Bytes("\0\xFF"), Bytes("\xFF\0")}, Bytes("\0\0") },
      {{Bytes("\xAA\xAA\xAA\xAA\xAA"), Bytes("\x55\x55\x55\x55\x55")},
          Bytes("\0\0\0\0\0") },
      {{Bytes("\x01\x23\x45\x67\x89\xAB\xCD\xEF\xFE\xDC\xBA"),
        Bytes("\x12\x34\x56\x78\x9A\xBC\xDE\xF0\x0F\xED\xCB")},
          Bytes("\x00\x20\x44\x60\x88\xA8\xCC\xE0\x0E\xCC\x8A") },
      {{Bytes(""), Bytes("\xFF")}, NullBytes(), OUT_OF_RANGE },
    };
  }
  
  std::vector<QueryParamsWithResult> GetFunctionTestsBitwiseLeftShift() {
    return {
        {{NullInt32(), Int64(0)}, NullInt32()},
        {{NullInt64(), Int64(0)}, NullInt64()},
        {{NullUint32(), Int64(0)}, NullUint32()},
        {{NullUint64(), Int64(0)}, NullUint64()},
        {{NullBytes(), Int64(0)}, NullBytes()},
        {{Int32(0), NullInt64()}, NullInt32()},
        {{Int64(0), NullInt64()}, NullInt64()},
        {{Uint32(0), NullInt64()}, NullUint32()},
        {{Uint64(0), NullInt64()}, NullUint64()},
        {{Bytes("foo"), NullInt64()}, NullBytes()},
  
        {{Int32(-1), Int64(0)}, Int32(-1)},
        {{Int32(-1), Int64(32)}, Int32(0)},
        {{Int32(-1), Int64(1)}, Int32(-2)},
        {{Int32(0x5555), Int64(16)}, Int32(0x55550000)},
        {{Int32(0x5555), Int64(-1)}, NullInt32(), OUT_OF_RANGE},
  
        {{Int64(-1), Int64(0)}, Int64(-1)},
        {{Int64(-1), Int64(64)}, Int64(0)},
        {{Int64(-1), Int64(1)}, Int64(-2)},
        {{Int64(0x5555), Int64(48)}, Int64(0x5555000000000000)},
        {{Int64(0x5555), Int64(-1)}, NullInt64(), OUT_OF_RANGE},
  
        {{Uint32(0xFFFFFFFFU), Int64(0)}, Uint32(0xFFFFFFFFU)},
        {{Uint32(0xFFFFFFFFU), Int64(32)}, Uint32(0)},
        {{Uint32(0xFFFFFFFFU), Int64(1)}, Uint32(0xFFFFFFFEU)},
        {{Uint32(0x5555), Int64(16)}, Uint32(0x55550000U)},
        {{Uint32(0x5555), Int64(-1)}, NullUint32(), OUT_OF_RANGE},
  
        {{Uint64(0xFFFFFFFFFFFFFFFFU), Int64(0)}, Uint64(0xFFFFFFFFFFFFFFFFU)},
        {{Uint64(0xFFFFFFFFFFFFFFFFU), Int64(64)}, Uint64(0)},
        {{Uint64(0xFFFFFFFFFFFFFFFFU), Int64(1)}, Uint64(0xFFFFFFFFFFFFFFFEU)},
        {{Uint64(0x5555), Int64(48)}, Uint64(0x5555000000000000U)},
        {{Uint64(0x5555), Int64(-1)}, NullUint64(), OUT_OF_RANGE},
  
        {{Bytes("\xFE\xDC\xBA\x98\x76"), Int64(0)},
         Bytes("\xFE\xDC\xBA\x98\x76")},
        {{Bytes("\xFE\xDC\xBA\x98\x76"), Int64(40)},
         Bytes("\x00\x00\x00\x00\x00")},
        {{Bytes("\xFE\xDC\xBA\x98\x76"), Int64(41)},
         Bytes("\x00\x00\x00\x00\x00")},
        {{Bytes("\xFE\xDC\xBA\x98\x76"), Int64(1)},
         Bytes("\xFD\xB9\x75\x30\xEC")},
        {{Bytes("\xFE\xDC\xBA\x98\x76"), Int64(4)},
         Bytes("\xED\xCB\xA9\x87\x60")},
        {{Bytes("\xFE\xDC\xBA\x98\x76"), Int64(17)},
         Bytes("\x75\x30\xEC\x00\x00")},
        {{Bytes("\xFE\xDC\xBA\x98\x76"), Int64(24)},
         Bytes("\x98\x76\x00\x00\x00")},
        {{Bytes("\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"), Int64(64)},
         Bytes("\xFF\xFF\xFF\xFF\0\0\0\0\0\0\0\0")},
        {{Bytes("\xFE\xDC\xBA\x98\x76"), Int64(-1)}, NullBytes(), OUT_OF_RANGE},
        // Empty input.
        {{Bytes(""), Int64(0)}, Bytes("")},
        {{Bytes(""), Int64(10)}, Bytes("")},
    };
  }
  
  std::vector<QueryParamsWithResult> GetFunctionTestsBitwiseRightShift() {
    return {
        {{NullInt32(), Int64(0)}, NullInt32()},
        {{NullInt64(), Int64(2)}, NullInt64()},
        {{NullUint32(), Int64(4)}, NullUint32()},
        {{NullUint64(), Int64(6)}, NullUint64()},
        {{NullBytes(), Int64(0)}, NullBytes()},
        {{Int32(0), NullInt64()}, NullInt32()},
        {{Int64(0), NullInt64()}, NullInt64()},
        {{Uint32(0), NullInt64()}, NullUint32()},
        {{Uint64(0), NullInt64()}, NullUint64()},
        {{Bytes("foo"), NullInt64()}, NullBytes()},
  
        {{Int32(-1), Int64(0)}, Int32(-1)},
        {{Int32(-1), Int64(32)}, Int32(0)},
        {{Int32(-1), Int64(1)}, Int32(0x7FFFFFFF)},
        {{Int32(0x55550000), Int64(16)}, Int32(0x5555)},
        {{Int32(0x5555), Int64(-1)}, NullInt32(), OUT_OF_RANGE},
  
        {{Int64(-1), Int64(0)}, Int64(-1)},
        {{Int64(-1), Int64(64)}, Int64(0)},
        {{Int64(-1), Int64(1)}, Int64(0x7FFFFFFFFFFFFFFF)},
        {{Int64(0x5555000000000000), Int64(48)}, Int64(0x5555)},
        {{Int64(0x5555), Int64(-1)}, NullInt64(), OUT_OF_RANGE},
  
        {{Uint32(0xFFFFFFFFU), Int64(0)}, Uint32(0xFFFFFFFFU)},
        {{Uint32(0xFFFFFFFFU), Int64(32)}, Uint32(0)},
        {{Uint32(0xFFFFFFFFU), Int64(1)}, Uint32(0x7FFFFFFFU)},
        {{Uint32(0x55550000U), Int64(16)}, Uint32(0x5555)},
        {{Uint32(0x5555), Int64(-1)}, NullUint32(), OUT_OF_RANGE},
  
        {{Uint64(0xFFFFFFFFFFFFFFFFU), Int64(0)}, Uint64(0xFFFFFFFFFFFFFFFFU)},
        {{Uint64(0xFFFFFFFFFFFFFFFFU), Int64(64)}, Uint64(0)},
        {{Uint64(0xFFFFFFFFFFFFFFFFU), Int64(1)}, Uint64(0x7FFFFFFFFFFFFFFFU)},
        {{Uint64(0x5555000000000000U), Int64(48)}, Uint64(0x5555)},
        {{Uint64(0x5555), Int64(-1)}, NullUint64(), OUT_OF_RANGE},
  
        {{Bytes("\xFE\xDC\xBA\x98\x76"), Int64(0)},
         Bytes("\xFE\xDC\xBA\x98\x76")},
        {{Bytes("\xFE\xDC\xBA\x98\x76"), Int64(40)},
         Bytes("\x00\x00\x00\x00\x00")},
        {{Bytes("\xFE\xDC\xBA\x98\x76"), Int64(41)},
         Bytes("\x00\x00\x00\x00\x00")},
        {{Bytes("\xFE\xDC\xBA\x98\x76"), Int64(1)},
         Bytes("\x7F\x6E\x5D\x4C\x3B")},
        {{Bytes("\xFE\xDC\xBA\x98\x76"), Int64(4)},
         Bytes("\x0F\xED\xCB\xA9\x87")},
        {{Bytes("\xFE\xDC\xBA\x98\x76"), Int64(17)},
         Bytes("\x00\x00\x7F\x6E\x5D")},
        {{Bytes("\xFE\xDC\xBA\x98\x76"), Int64(24)},
         Bytes("\x00\x00\x00\xFE\xDC")},
        {{Bytes("\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"), Int64(64)},
         Bytes("\0\0\0\0\0\0\0\0\xFF\xFF\xFF\xFF")},
        {{Bytes("\xFE\xDC\xBA\x98\x76"), Int64(-1)}, NullBytes(), OUT_OF_RANGE},
        // Empty input.
        {{Bytes(""), Int64(0)}, Bytes("")},
        {{Bytes(""), Int64(10)}, Bytes("")},
    };
  }
  
  std::vector<QueryParamsWithResult> GetFunctionTestsBitCount() {
    return {
        {{NullInt32()}, NullInt64()},
        {{NullInt64()}, NullInt64()},
        {{NullUint64()}, NullInt64()},
        {{NullBytes()}, NullInt64()},
  
        {{Int32(0)}, Int64(0)},
        {{Int32(-1)}, Int64(32)},
        {{Int32(-2)}, Int64(31)},
        {{Int32(0xFFFF)}, Int64(16)},
        {{Int32(0xFFFFFF)}, Int64(24)},
        {{Int32(0xFFFFFFF)}, Int64(28)},
        {{Int32(0x7FFFFFFF)}, Int64(31)},
        {{Int32(0x7F0F0F0F)}, Int64(19)},
        {{Int32(0x88888888)}, Int64(8)},
  
        {{Uint32(0)}, Int64(0)},
        {{Uint32(0xFFFF)}, Int64(16)},
        {{Uint32(0xFFFFFF)}, Int64(24)},
        {{Uint32(0xFFFFFFF)}, Int64(28)},
        {{Uint32(0x7FFFFFFF)}, Int64(31)},
        {{Uint32(0xFFFFFFFFU)}, Int64(32)},
        {{Uint32(0x7F0F0F0F)}, Int64(19)},
        {{Uint32(0x88888888)}, Int64(8)},
  
        {{Int64(0)}, Int64(0)},
        {{Int64(-1)}, Int64(64)},
        {{Int64(-2)}, Int64(63)},
        {{Int64(0xFFFF)}, Int64(16)},
        {{Int64(0xFFFFFF)}, Int64(24)},
        {{Int64(0xFFFFFFF)}, Int64(28)},
        {{Int64(0x7FFFFFFF)}, Int64(31)},
        {{Int64(0xFFFFFFFFL)}, Int64(32)},
        {{Int64(0xFFFFFFFFFFL)}, Int64(40)},
        {{Int64(0xFFFFFFFFFFFFFFL)}, Int64(56)},
        {{Int64(0xFFFFFFFFFFFFFFFL)}, Int64(60)},
        {{Int64(0x7FFFFFFFFFFFFFFFL)}, Int64(63)},
  
        {{Uint64(0)}, Int64(0)},
        {{Uint64(-1)}, Int64(64)},
        {{Uint64(-2)}, Int64(63)},
        {{Uint64(0xFFFF)}, Int64(16)},
        {{Uint64(0xFFFFFF)}, Int64(24)},
        {{Uint64(0xFFFFFFF)}, Int64(28)},
        {{Uint64(0x7FFFFFFF)}, Int64(31)},
        {{Uint64(0xFFFFFFFFUL)}, Int64(32)},
        {{Uint64(0xFFFFFFFFFFUL)}, Int64(40)},
        {{Uint64(0xFFFFFFFFFFFFFFUL)}, Int64(56)},
        {{Uint64(0xFFFFFFFFFFFFFFFUL)}, Int64(60)},
        {{Uint64(0x7FFFFFFFFFFFFFFFUL)}, Int64(63)},
        {{Uint64(0xFFFFFFFFFFFFFFFFUL)}, Int64(64)},
  
        {{Bytes("")}, Int64(0)},
        {{Bytes("\x00")}, Int64(0)},
        {{Bytes("\xFF")}, Int64(8)},
        {{Bytes("\x78")}, Int64(4)},
        {{Bytes("\x00\x00")}, Int64(0)},
        {{Bytes("\xFF\xFF")}, Int64(16)},
        {{Bytes("\xFF\x00")}, Int64(8)},
        {{Bytes("\x00\xFF")}, Int64(8)},
        {{Bytes("\x12\x34")}, Int64(5)},
        {{Bytes("\x01\x02\x03\x04\x05\x06\x07\x08")}, Int64(13)},
        {{Bytes("\x01\x02\x03\x04\x05\x06\x07\x08\x09")}, Int64(15)},
        {{Bytes("\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a")}, Int64(17)},
        {{Bytes("\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b")}, Int64(20)},
        {{Bytes("\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF")}, Int64(96)},
    };
  }
  
  std::vector<QueryParamsWithResult> GetFunctionTestsAtOffset() {
    const Value int64_array =
        Value::Array(Int64ArrayType(), {Int64(10), Int64(11)});
    const Value string_array =
        Value::Array(StringArrayType(), {String("foo"), String("bar")});
    const StructType* struct_type = SimpleStructType();  // a: string, b: int32_t
    const ArrayType* array_struct_type;
    ZETASQL_CHECK_OK(type_factory()->MakeArrayType(struct_type, &array_struct_type));
    const Value struct0 = Value::Struct(struct_type, {String("foo"), Int32(0)});
    const Value struct1 = Value::Struct(struct_type, {String("bar"), Int32(1)});
    const Value struct_array =
        Value::Array(array_struct_type, {struct0, struct1});
    return {
      {{int64_array, Int64(-1)}, NullInt64(), OUT_OF_RANGE},
      {{int64_array, Int64(0)}, Int64(10)},
      {{int64_array, Int64(1)}, Int64(11)},
      {{int64_array, Int64(2)}, NullInt64(), OUT_OF_RANGE},
      {{string_array, Int64(-1)}, NullString(), OUT_OF_RANGE},
      {{string_array, Int64(0)}, String("foo")},
      {{string_array, Int64(1)}, String("bar")},
      {{string_array, Int64(2)}, NullString(), OUT_OF_RANGE},
      {{struct_array, Int64(-1)}, Null(struct_type), OUT_OF_RANGE},
      {{struct_array, Int64(0)}, struct0},
      {{struct_array, Int64(1)}, struct1},
      {{struct_array, Int64(2)}, Null(struct_type), OUT_OF_RANGE},
    };
  }
  
  std::vector<QueryParamsWithResult> GetFunctionTestsSafeAtOffset() {
    // Use the same tests as above, but return null rather than an error when the
    // position is out of bounds.
    std::vector<QueryParamsWithResult> offset_tests = GetFunctionTestsAtOffset();
    for (auto& offset_test : offset_tests) {
      QueryParamsWithResult::ResultMap new_result_map = offset_test.results();
      for (auto& result : new_result_map) {
        result.second.status = absl::OkStatus();
      }
      offset_test.set_results(new_result_map);
    }
    return offset_tests;
  }
  
  std::vector<QueryParamsWithResult> GetFunctionTestsIf() {
    std::vector<QueryParamsWithResult> result;
    for (const auto& v : GetRowsOfValues()) {
      result.push_back({{NullBool(), v[0], v[1]}, v[1]});
      result.push_back({{False(), v[0], v[1]}, v[1]});
      result.push_back({{True(), v[0], v[1]}, v[0]});
      result.push_back({{NullBool(), v[1], v[0]}, v[0]});
      result.push_back({{False(), v[1], v[0]}, v[0]});
      result.push_back({{True(), v[1], v[0]}, v[1]});
    }
    WrapNumericTestCases(&result);
    WrapBigNumericTestCases(&result);
    return result;
  }
  
  std::vector<QueryParamsWithResult> GetFunctionTestsIfNull() {
    std::vector<QueryParamsWithResult> result;
    for (const auto& v : GetRowsOfValues()) {
      result.push_back({{Null(v[0].type()), v[0]}, v[0]});
      result.push_back({{v[0], v[1]}, v[0]});
      result.push_back({{v[1], v[0]}, v[1]});
    }
    WrapNumericTestCases(&result);
    WrapBigNumericTestCases(&result);
    return result;
  }
  
  // Builds test cases with FEATURE_V_1_1_ARRAY_EQUALITY option turned on/off.
  static QueryParamsWithResult BuildArrayEqualityQueryParamsWithResult(
      const std::vector<ValueConstructor>& arguments,
      const ValueConstructor& result,
      const Value& null_value) {
    return QueryParamsWithResult(
        arguments,
        {{QueryParamsWithResult::kEmptyFeatureSet,
          QueryParamsWithResult::Result(null_value, OUT_OF_RANGE)},
         {{FEATURE_V_1_1_ARRAY_EQUALITY},
             QueryParamsWithResult::Result(result)}});
  }
  
  std::vector<QueryParamsWithResult> GetFunctionTestsNullIf() {
    std::vector<QueryParamsWithResult> result;
    for (const auto& v : GetRowsOfValues()) {
      const Type* type = v[0].type();
      Value null_value = Null(type);
      if (type->IsProto()) {
        // SQL equality is not defined for protos.
        result.push_back({{v[0], v[0]}, null_value, OUT_OF_RANGE});
        continue;
      }
      if (type->IsArray()) {
        result.push_back(BuildArrayEqualityQueryParamsWithResult(
            {null_value, v[0]}, null_value, null_value));
        result.push_back(BuildArrayEqualityQueryParamsWithResult(
            {v[0], null_value}, v[0], null_value));
        result.push_back(BuildArrayEqualityQueryParamsWithResult(
            {v[0], v[1]}, v[0], null_value));
        result.push_back(BuildArrayEqualityQueryParamsWithResult(
            {v[1], v[0]}, v[1], null_value));
        result.push_back(BuildArrayEqualityQueryParamsWithResult(
            {v[0], v[0]}, null_value, null_value));
        result.push_back(BuildArrayEqualityQueryParamsWithResult(
            {v[1], v[1]}, null_value, null_value));
        continue;
      }
      result.push_back({{null_value, v[0]}, null_value});
      result.push_back({{v[0], null_value}, v[0]});
      result.push_back({{v[0], v[1]}, v[0]});
      result.push_back({{v[1], v[0]}, v[1]});
      result.push_back({{v[0], v[0]}, null_value});
      result.push_back({{v[1], v[1]}, null_value});
    }
    WrapNumericTestCases(&result);
    WrapBigNumericTestCases(&result);
    return result;
  }
  
  std::vector<QueryParamsWithResult> GetFunctionTestsCoalesce() {
    std::vector<QueryParamsWithResult> result;
    for (const auto& v : GetRowsOfValues()) {
      Value null_value = Null(v[0].type());
      result.push_back({{null_value}, null_value});
      result.push_back({{v[0], null_value}, v[0]});
      result.push_back({{null_value, v[0]}, v[0]});
      result.push_back({{null_value, v[0], v[1]}, v[0]});
      result.push_back({{null_value, v[1], v[0]}, v[1]});
      result.push_back({{null_value, v[0], null_value, v[1]}, v[0]});
      result.push_back({{null_value, v[1], null_value, v[0]}, v[1]});
      result.push_back({{v[0], v[1]}, v[0]});
      result.push_back({{v[1], v[0]}, v[1]});
    }
    WrapNumericTestCases(&result);
    WrapBigNumericTestCases(&result);
    return result;
  }
  
  
  std::vector<FunctionTestCall> GetArrayConcatTests() {
    const Value empty_array = Value::EmptyArray(Int32ArrayType());
    const Value null_array = Value::Null(Int32ArrayType());
    const Value array_12 = Value::Array(Int32ArrayType(), {Int32(1), Int32(2)});
    const Value array_23 = Value::Array(Int32ArrayType(), {Int32(2), Int32(3)});
    const Value array_3 = Value::Array(Int32ArrayType(), {Int32(3)});
    const Value array_1223 = Value::Array(
        Int32ArrayType(), {Int32(1), Int32(2), Int32(2), Int32(3)});
    const Value array_2312 = Value::Array(
        Int32ArrayType(), {Int32(2), Int32(3), Int32(1), Int32(2)});
    const Value array_23123 = Value::Array(
        Int32ArrayType(), {Int32(2), Int32(3), Int32(1), Int32(2), Int32(3)});
    const Value array_ab = Value::Array(StringArrayType(),
                                        {String("a"), String("b")});
    const Value array_c = Value::Array(StringArrayType(), {String("c")});
    const Value array_abc = Value::Array(StringArrayType(),
                                        {String("a"), String("b"), String("c")});
    return {
        // array_concat(array...) -> array
        {"array_concat", {empty_array}, empty_array},
        {"array_concat", {empty_array, empty_array}, empty_array},
        {"array_concat", {empty_array, null_array}, null_array},
        {"array_concat", {null_array}, null_array},
        {"array_concat", {array_12}, array_12},
        {"array_concat", {empty_array, array_12}, array_12},
        {"array_concat", {array_12, empty_array}, array_12},
        {"array_concat", {null_array, array_12}, null_array},
        {"array_concat", {array_12, array_23}, array_1223},
        {"array_concat", {array_23, array_12}, array_2312},
        {"array_concat", {array_23, array_12, array_3}, array_23123},
        {"array_concat", {array_ab}, array_ab},
        {"array_concat", {array_ab, array_c}, array_abc},
    };
  }
  
  std::vector<FunctionTestCall> GetFunctionTestsArray() {
    const Value array_ab = Value::Array(StringArrayType(),
                                        {String("a"), String("b")});
    const Value array_c = Value::Array(StringArrayType(), {String("c")});
    const Value array_abc = Value::Array(StringArrayType(),
                                        {String("a"), String("b"), String("c")});
    const Value array_ab_nulls =
        Value::Array(StringArrayType(),
                     {NullString(), String("a"), NullString(), String("b")});
    const Value array_empty_string = Value::Array(StringArrayType(),
                                                  {String("")});
    const Value array_empty_string_2 = Value::Array(StringArrayType(),
                                                    {String(""), String("")});
    const Value array_empty_string_3 = Value::Array(StringArrayType(),
                                                    {String("a"), String("")});
    const Value array_empty_string_4 = Value::Array(StringArrayType(),
                                                    {String(""), String("b")});
    const Value array_empty_string_5 =
        Value::Array(StringArrayType(), {String(""), String("b"), String("")});
    const Value array_empty_string_6 =
        Value::Array(StringArrayType(),
                     {String("a"), String(""), String(""), String("b")});
  
    const Value array_ab_bytes = Value::Array(
        BytesArrayType(), {Bytes("a"), Bytes("b")});
    const Value array_c_bytes = Value::Array(BytesArrayType(), {Bytes("c")});
    const Value array_abc_bytes = Value::Array(
        BytesArrayType(), {Bytes("a"), Bytes("b"), Bytes("c")});
    const Value array_ab_nulls_bytes =
        Value::Array(BytesArrayType(),
                     {NullBytes(), Bytes("a"), NullBytes(), Bytes("b")});
    const Value array_empty_bytes = Value::Array(BytesArrayType(), {Bytes("")});
  
    const StructType* struct_type = SimpleStructType();  // a: string, b: int32_t
    const Value struct0 = Value::Struct(struct_type, {String("foo"), Int32(0)});
    const Value struct1 = Value::Struct(struct_type, {String("bar"), Int32(1)});
    const Value struct2 = Value::Struct(struct_type, {String("baz"), Int32(2)});
    const ArrayType* array_struct_type = MakeArrayType(struct_type);
  
    std::vector<FunctionTestCall> results = {
        // array_to_string -> string
        {"array_to_string", {Null(StringArrayType()), String(",")}, NullString()},
        {"array_to_string", {array_ab, NullString()}, NullString()},
        {"array_to_string", {array_ab, String(","), NullString()}, NullString()},
        {"array_to_string",
         {EmptyArray(StringArrayType()), String(",")},
         String("")},
        {"array_to_string", {array_empty_string, String(",")}, String("")},
        {"array_to_string", {array_empty_string_2, String(",")}, String(",")},
        {"array_to_string", {array_empty_string_3, String(",")}, String("a,")},
        {"array_to_string", {array_empty_string_4, String(",")}, String(",b")},
        {"array_to_string", {array_empty_string_5, String(",")}, String(",b,")},
        {"array_to_string", {array_empty_string_6, String(",")}, String("a,,,b")},
  
        {"array_to_string", {array_c, String(",")}, String("c")},
        {"array_to_string", {array_abc, String(",")}, String("a,b,c")},
        {"array_to_string", {array_abc, String("+!+")}, String("a+!+b+!+c")},
        {"array_to_string", {array_abc, String("")}, String("abc")},
        {"array_to_string", {array_ab_nulls, String(",")}, String("a,b")},
        {"array_to_string",
         {array_ab_nulls, String(","), String("")},
         String(",a,,b")},
        {"array_to_string",
         {array_ab_nulls, String(","), String("*")},
         String("*,a,*,b")},
        {"array_to_string",
         {array_ab_nulls, String(","), String("<null>")},
         String("<null>,a,<null>,b")},
  
        // array_to_string -> bytes
        {"array_to_string", {Null(BytesArrayType()), Bytes(",")}, NullBytes()},
        {"array_to_string", {array_ab_bytes, NullBytes()}, NullBytes()},
        {"array_to_string",
         {array_ab_bytes, Bytes(","), NullBytes()},
         NullBytes()},
        {"array_to_string",
         {EmptyArray(BytesArrayType()), Bytes(",")},
         Bytes("")},
        {"array_to_string", {array_empty_bytes, Bytes(",")}, Bytes("")},
        {"array_to_string", {array_c_bytes, Bytes(",")}, Bytes("c")},
        {"array_to_string", {array_abc_bytes, Bytes(",")}, Bytes("a,b,c")},
        {"array_to_string", {array_abc_bytes, Bytes("\1")}, Bytes("a\1b\1c")},
        {"array_to_string", {array_abc_bytes, Bytes("")}, Bytes("abc")},
        {"array_to_string", {array_ab_nulls_bytes, Bytes(",")}, Bytes("a,b")},
        {"array_to_string",
         {array_ab_nulls_bytes, Bytes(","), Bytes("\2")},
         Bytes("\2,a,\2,b")},
  
        {"array_reverse", {Null(Int64ArrayType())}, Null(Int64ArrayType())},
        {"array_reverse", {Int64Array({})}, Int64Array({})},
        {"array_reverse", {Int64Array({1})}, Int64Array({1})},
        {"array_reverse",
         {Int64Array({1, 2, 3, 4, 5, 6, 7, 8, 9, 10})},
         Int64Array({10, 9, 8, 7, 6, 5, 4, 3, 2, 1})},
        {"array_reverse",
         {StringArray({"", "foo", "bar", "baz", "foobar"})},
         StringArray({"foobar", "baz", "bar", "foo", ""})},
        {"array_reverse",
         {DoubleArray({3.14, 1.59, -0.0, double_pos_inf, double_neg_inf})},
         DoubleArray({double_neg_inf, double_pos_inf, -0.0, 1.59, 3.14})},
        {"array_reverse",
         {Value::Array(array_struct_type, {struct0, struct1, struct2})},
         Value::Array(array_struct_type, {struct2, struct1, struct0})},
  
        {"array_is_distinct", {Null(Int64ArrayType())}, NullBool()},
        {"array_is_distinct", {Int64Array({1, 2, 3})}, True()},
        {"array_is_distinct", {Int64Array({1, 1, 1})}, False()},
        {"array_is_distinct", {Array({Int64(1), Int64(2), NullInt64()})}, True()},
        {"array_is_distinct",
         {Array({Int64(1), Int64(1), NullInt64()})},
         False()},
        {"array_is_distinct",
         {Array({Int64(1), NullInt64(), NullInt64()})},
         False()},
        {"array_is_distinct", {StringArray({"foo", "foo"})}, False()},
        {"array_is_distinct",
         {Array({String(""), String("foo"), NullString()})},
         True()},
        {"array_is_distinct", {DoubleArray({0.0, 1.0})}, True()},
        {"array_is_distinct", {DoubleArray({0.0, 0.0})}, False()},
        {"array_is_distinct", {DoubleArray({0.0, double_nan})}, True()},
        {"array_is_distinct", {DoubleArray({double_nan, double_nan})}, False()},
    };
    std::vector<FunctionTestCall> tests_array_concat = GetArrayConcatTests();
    results.insert(results.end(),
                   std::make_move_iterator(tests_array_concat.begin()),
                   std::make_move_iterator(tests_array_concat.end())
    );
    return results;
  }
  
  std::vector<QueryParamsWithResult> GetFunctionTestsArrayConcatOperator() {
    std::vector<QueryParamsWithResult> results;
    // array || array -> array
    // Test the test cases of array_concat function.
    for (const FunctionTestCall& function_call : GetArrayConcatTests()) {
      if (function_call.params.params().size() == 2) {
        results.push_back(function_call.params);
      }
    }
    return results;
  }
  
  std::vector<FunctionTestCall> GetFunctionTestsBase32() {
    const std::vector<std::pair<Value, Value>> unencoded_and_encoded = {
        {NullBytes(), NullString()},
        {Bytes(""), String("")},
        {Bytes("1"), String("GE======")},
        {Bytes("1a"), String("GFQQ====")},
        {Bytes("12345"), String("GEZDGNBV")},
        {Bytes("123456"), String("GEZDGNBVGY======")},
        {Bytes("1234567890123456"),
         String("GEZDGNBVGY3TQOJQGEZDGNBVGY======")},
    };
    std::vector<FunctionTestCall> tests;
    for (const auto& entry : unencoded_and_encoded) {
      tests.push_back({"to_base32", {entry.first}, entry.second});
      tests.push_back({"from_base32", {entry.second}, entry.first});
    }
    tests.push_back({"from_base32", {String("GE0")}, NullBytes(), OUT_OF_RANGE});
    tests.push_back({"from_base32", {String("12")}, NullBytes(), OUT_OF_RANGE});
    return tests;
  }
  
  std::vector<FunctionTestCall> GetFunctionTestsBase64() {
    const std::vector<std::pair<Value, Value>> unencoded_and_encoded = {
        {NullBytes(), NullString()},
        {Bytes(""), String("")},
        {Bytes(" "), String("IA==")},
        {Bytes("abcABC"), String("YWJjQUJD")},
        {Bytes("abcABCжщфЖЩФ"), String("YWJjQUJD0LbRidGE0JbQqdCk")},
        {Bytes("Ḋ"), String("4biK")},
        {Bytes("abca\0b\0c\0"), String("YWJjYQBiAGMA")},
    };
    std::vector<FunctionTestCall> tests;
    for (const auto& entry : unencoded_and_encoded) {
      tests.push_back({"to_base64", {entry.first}, entry.second});
      tests.push_back({"from_base64", {entry.second}, entry.first});
    }
    tests.push_back({"from_base64", {String("====")}, NullBytes(), OUT_OF_RANGE});
    return tests;
  }
  
  std::vector<FunctionTestCall> GetFunctionTestsHex() {
    const std::vector<std::pair<Value, Value>> unencoded_and_encoded = {
        {NullBytes(), NullString()},
        {Bytes(""), String("")},
        {Bytes(" "), String("20")},
        {Bytes("abcABC"), String("616263414243")},
        {Bytes("abcABCжщфЖЩФ"), String("616263414243d0b6d189d184d096d0a9d0a4")},
        {Bytes("\0\0a\ff\xee"), String("0000610c66ee")},
        {Bytes("\x01\x23\x45\x67\x89\xAB\xCD\xEF\x55\xAA"),
         String("0123456789abcdef55aa")},
        {Bytes("\xFE\xDC\xBA\x98\x76\x54\x32\x10\xAA\x55"),
         String("fedcba9876543210aa55")},
    };
    std::vector<FunctionTestCall> tests;
    for (const auto& entry : unencoded_and_encoded) {
      tests.push_back({"to_hex", {entry.first}, entry.second});
      tests.push_back({"from_hex", {entry.second}, entry.first});
    }
    tests.push_back({"from_hex", {String("G")}, NullBytes(), OUT_OF_RANGE});
    tests.push_back({"from_hex", {String("123g321")}, NullBytes(), OUT_OF_RANGE});
    tests.push_back(
        {"from_hex", {String("abcde00011-")}, NullBytes(), OUT_OF_RANGE});
    tests.push_back(
        {"from_hex", {String("abcABCжщфЖЩФ")}, NullBytes(), OUT_OF_RANGE});
    return tests;
  }
  
  std::vector<FunctionTestCall> GetFunctionTestsCodePoints() {
    const Value null_array = Null(types::Int64ArrayType());
  
    // Contains all ASCII characters with values in the range [0, 255].
    Value all_ascii_characters;
    // Elements are numbers from 0 to 255.
    Value all_ascii_characters_array;
    {
      std::string all_ascii_characters_string(255, 'a');
      std::iota(all_ascii_characters_string.begin(),
                all_ascii_characters_string.end(),
                std::numeric_limits<uint8_t>::lowest());
      all_ascii_characters = Bytes(all_ascii_characters_string);
  
      std::vector<int64_t> all_ascii_characters_vector(255);
      std::iota(all_ascii_characters_vector.begin(),
                all_ascii_characters_vector.end(), 0);
      all_ascii_characters_array =
          values::Int64Array(all_ascii_characters_vector);
    }
  
    const std::vector<std::pair<Value, Value>> value_and_codepoints = {
        {NullBytes(), null_array},
        {NullString(), null_array},
        {Bytes(""), values::Int64Array({})},
        {String(""), values::Int64Array({})},
        {Bytes(" "), values::Int64Array({32})},
        {String(" "), values::Int64Array({32})},
        {Bytes("abcABC"), values::Int64Array({97, 98, 99, 65, 66, 67})},
        {String("abcABC"), values::Int64Array({97, 98, 99, 65, 66, 67})},
        {String("abcABCжщфЖЩФ"),
         values::Int64Array(
             {97, 98, 99, 65, 66, 67, 1078, 1097, 1092, 1046, 1065, 1060})},
        {String("Ḋ"), values::Int64Array({7690})},
        {Bytes("abca\0\1cde"),
         values::Int64Array({97, 98, 99, 97, 0, 1, 99, 100, 101})},
        // Note that the null character is not interchange valid, but can be part
        // of structurally valid UTF8 strings.
        {String("abca\0\1cde"),
         values::Int64Array({97, 98, 99, 97, 0, 1, 99, 100, 101})},
        {String("абвгд"), values::Int64Array({1072, 1073, 1074, 1075, 1076})},
        // Borders of valid codepoint ranges, which are [0, 0xD800) and
        // [0xE000, 0x10FFFF]. 0 is tested above.
        {String("\uD7FE"
                "\uD7FF"),
         values::Int64Array({0xD7FE, 0xD7FF})},
        {String("\uE000"
                "\uE001"
                "\U0010FFFE"
                "\U0010FFFF"),
         values::Int64Array({0xE000, 0xE001, 0x10FFFE, 0x10FFFF})},
        {all_ascii_characters, all_ascii_characters_array},
    };
    std::vector<FunctionTestCall> tests;
    for (const auto& entry : value_and_codepoints) {
      tests.push_back({"to_code_points", {entry.first}, entry.second});
      if (entry.first.type()->IsBytes()) {
        tests.push_back({"code_points_to_bytes", {entry.second}, entry.first});
      } else {
        tests.push_back({"code_points_to_string", {entry.second}, entry.first});
      }
    }
  
    // Error cases.
    // The C++ compiler rejects Unicode literals in strings that aren't valid
    // codepoints, so we have to construct them "manually".
    {
      std::string invalid_codepoint_string;
      // The first character is a valid codepoint.
      invalid_codepoint_string.push_back(0xD7);
      invalid_codepoint_string.push_back('\xFF');
      // The second is not.
      invalid_codepoint_string.push_back(0xD8);
      invalid_codepoint_string.push_back('\xFF');
  
      tests.push_back({"to_code_points",
                       {String(invalid_codepoint_string)},
                       null_array,
                       OUT_OF_RANGE});
    }
  
    {
      std::string invalid_codepoint_string;
      // The first character is a valid codepoint.
      invalid_codepoint_string.push_back(0xE0);
      invalid_codepoint_string.push_back(0x00);
      // The second is not.
      invalid_codepoint_string.push_back(0xDF);
      invalid_codepoint_string.push_back('\xFF');
  
      tests.push_back({"to_code_points",
                       {String(invalid_codepoint_string)},
                       null_array,
                       OUT_OF_RANGE});
    }
  
    {
      std::string invalid_codepoint_string;
      // Invalid three-byte codepoint (above the valid range).
      invalid_codepoint_string.push_back(0x11);
      invalid_codepoint_string.push_back('\xFF');
      invalid_codepoint_string.push_back('\xFF');
  
      tests.push_back({"to_code_points",
                       {String(invalid_codepoint_string)},
                       null_array,
                       OUT_OF_RANGE});
    }
  
    // Invalid ASCII values.
    tests.push_back({"code_points_to_bytes",
                     {values::Int64Array({0, -1})},
                     values::NullBytes(),
                     OUT_OF_RANGE});
    tests.push_back({"code_points_to_bytes",
                     {values::Int64Array({256, 10})},
                     values::NullBytes(),
                     OUT_OF_RANGE});
    tests.push_back({"code_points_to_bytes",
                     {values::Int64Array({0, 1, 512})},
                     values::NullBytes(),
                     OUT_OF_RANGE});
  
    // Invalid codepoints.
    tests.push_back({"code_points_to_string",
                     {values::Int64Array({0, -1})},
                     values::NullString(),
                     OUT_OF_RANGE});
    tests.push_back({"code_points_to_string",
                     {values::Int64Array({-100})},
                     values::NullString(),
                     OUT_OF_RANGE});
    tests.push_back({"code_points_to_string",
                     {values::Int64Array({0, 1, 0xD800})},
                     values::NullString(),
                     OUT_OF_RANGE});
    tests.push_back({"code_points_to_string",
                     {values::Int64Array({10, 100, 0x10FFFF + 1})},
                     values::NullString(),
                     OUT_OF_RANGE});
    tests.push_back({"code_points_to_string",
                     {values::Int64Array({std::numeric_limits<int64_t>::max()})},
                     values::NullString(),
                     OUT_OF_RANGE});
  
    return tests;
  }
  
  std::vector<FunctionTestCall> GetFunctionTestsPadding() {
    std::vector<FunctionTestCall> tests = {
        {"lpad_bytes",
         {Bytes("google"), Int64(-8), Bytes("")},
         NullBytes(),
         OUT_OF_RANGE},
        {"lpad_bytes",
         {Bytes("goog"), Int64(10), Bytes("")},
         NullBytes(),
         OUT_OF_RANGE},
        {"lpad_bytes", {Bytes("abcdef"), Int64(0), Bytes("defgh")}, ""},
        {"lpad_bytes", {Bytes("abcdef"), Int64(6), Bytes("defgh")}, "abcdef"},
        {"lpad_bytes", {Bytes("abcdef"), Int64(4), Bytes("defgh")}, "abcd"},
        {"lpad_bytes", {Bytes("abcdef"), Int64(3), Bytes("defgh")}, "abc"},
        {"lpad_bytes", {Bytes("abcde"), Int64(4), Bytes("defgh")}, "abcd"},
        {"lpad_bytes", {Bytes("abcde"), Int64(3), Bytes("defgh")}, "abc"},
        {"lpad_bytes", {Bytes("abc"), Int64(5), Bytes("defgh")}, "deabc"},
        {"lpad_bytes", {Bytes("abc"), Int64(7), Bytes("defg")}, "defgabc"},
        {"lpad_bytes", {Bytes("abc"), Int64(4), Bytes("def")}, "dabc"},
        {"lpad_bytes", {Bytes("abc"), Int64(10), Bytes("defg")}, "defgdefabc"},
        {"lpad_bytes", {Bytes("abcx"), Int64(5), Bytes("defgh")}, "dabcx"},
        {"lpad_bytes", {Bytes("abcx"), Int64(7), Bytes("defg")}, "defabcx"},
        {"lpad_bytes", {Bytes("abcx"), Int64(10), Bytes("defg")}, "defgdeabcx"},
        {"lpad_bytes", {Bytes("abc"), Int64(7), Bytes("-")}, "----abc"},
        {"lpad_bytes", {Bytes(""), Int64(7), Bytes("-")}, "-------"},
        {"lpad_bytes", {Bytes(""), Int64(7), Bytes("def")}, "defdefd"},
  
        {"lpad_bytes", {Bytes("abc"), Int64(7)}, "    abc"},
        {"lpad_bytes", {Bytes(""), Int64(7)}, "       "},
        {"lpad_bytes", {Bytes("abcx"), Int64(10)}, "      abcx"},
  
        {"rpad_bytes",
         {Bytes("google"), Int64(-8), Bytes("")},
         NullBytes(),
         OUT_OF_RANGE},
        {"rpad_bytes",
         {Bytes("goog"), Int64(10), Bytes("")},
         NullBytes(),
         OUT_OF_RANGE},
        {"rpad_bytes", {Bytes("abcdef"), Int64(0), Bytes("defgh")}, ""},
        {"rpad_bytes", {Bytes("abcdef"), Int64(6), Bytes("defgh")}, "abcdef"},
        {"rpad_bytes", {Bytes("abcdef"), Int64(4), Bytes("defgh")}, "abcd"},
        {"rpad_bytes", {Bytes("abcdef"), Int64(3), Bytes("defgh")}, "abc"},
        {"rpad_bytes", {Bytes("abc"), Int64(5), Bytes("defgh")}, "abcde"},
        {"rpad_bytes", {Bytes("abc"), Int64(7), Bytes("defg")}, "abcdefg"},
        {"rpad_bytes", {Bytes("abc"), Int64(4), Bytes("def")}, "abcd"},
        {"rpad_bytes", {Bytes("abc"), Int64(10), Bytes("defg")}, "abcdefgdef"},
        {"rpad_bytes", {Bytes("abcx"), Int64(5), Bytes("defgh")}, "abcxd"},
        {"rpad_bytes", {Bytes("abcx"), Int64(7), Bytes("defg")}, "abcxdef"},
        {"rpad_bytes", {Bytes("abcx"), Int64(8), Bytes("def")}, "abcxdefd"},
        {"rpad_bytes", {Bytes("abcx"), Int64(10), Bytes("defg")}, "abcxdefgde"},
        {"rpad_bytes", {Bytes("abc"), Int64(7), Bytes("-")}, "abc----"},
        {"rpad_bytes", {Bytes(""), Int64(7), Bytes("-")}, "-------"},
        {"rpad_bytes", {Bytes(""), Int64(7), Bytes("def")}, "defdefd"},
  
        {"rpad_bytes", {Bytes("abc"), Int64(7)}, "abc    "},
        {"rpad_bytes", {Bytes(""), Int64(7)}, "       "},
        {"rpad_bytes", {Bytes("abcx"), Int64(10)}, "abcx      "},
  
        {"rpad_string",
         {"者不終朝ef而", Int64(-8), ""},
         NullString(),
         OUT_OF_RANGE},
        {"rpad_string",
         {"者不終朝ef而", Int64(10), ""},
         NullString(),
         OUT_OF_RANGE},
        {"rpad_string", {"abcdef", Int64(0), "defgh"}, ""},
        {"rpad_string", {"abcdef", Int64(6), "defgh"}, "abcdef"},
        {"rpad_string", {"abcdef", Int64(4), "defgh"}, "abcd"},
        {"rpad_string", {"abcdef", Int64(3), "defgh"}, "abc"},
        {"rpad_string", {"abc", Int64(5), "defgh"}, "abcde"},
        {"rpad_string", {"abc", Int64(7), "defg"}, "abcdefg"},
        {"rpad_string", {"abc", Int64(4), "def"}, "abcd"},
        {"rpad_string", {"abc", Int64(10), "defg"}, "abcdefgdef"},
        {"rpad_string", {"abcx", Int64(5), "defgh"}, "abcxd"},
        {"rpad_string", {"abcx", Int64(7), "defg"}, "abcxdef"},
        {"rpad_string", {"abcx", Int64(8), "def"}, "abcxdefd"},
        {"rpad_string", {"abcx", Int64(10), "defg"}, "abcxdefgde"},
        {"rpad_string", {"abc", Int64(7), "-"}, "abc----"},
        {"rpad_string", {"", Int64(7), "-"}, "-------"},
        {"rpad_string", {"", Int64(7), "def"}, "defdefd"},
        {"rpad_string", {"¼¼¼𠈓𠈓𠈓", Int64(6), "智者不終朝"}, "¼¼¼𠈓𠈓𠈓"},
        {"rpad_string", {"¼¼¼𠈓𠈓𠈓", Int64(5), "智者不終朝"}, "¼¼¼𠈓𠈓"},
        {"rpad_string", {"¼¼¼𠈓𠈓𠈓", Int64(7), "智者不終朝"}, "¼¼¼𠈓𠈓𠈓智"},
        {"rpad_string", {"¼¼¼𠈓𠈓𠈓", Int64(10), "智者朝"}, "¼¼¼𠈓𠈓𠈓智者朝智"},
  
        {"rpad_string", {"¼¼¼𠈓𠈓𠈓", Int64(7)}, "¼¼¼𠈓𠈓𠈓 "},
        {"rpad_string", {"¼¼¼𠈓𠈓𠈓", Int64(10)}, "¼¼¼𠈓𠈓𠈓    "},
        {"rpad_string", {"", Int64(5)}, "     "},
  
        {"lpad_string", {"google", Int64(-8), ""}, NullString(), OUT_OF_RANGE},
        {"lpad_string", {"goog", Int64(10), ""}, NullString(), OUT_OF_RANGE},
        {"lpad_string", {"abcdef", Int64(0), "defgh"}, ""},
        {"lpad_string", {"abcdef", Int64(6), "defgh"}, "abcdef"},
        {"lpad_string", {"abcdef", Int64(4), "defgh"}, "abcd"},
        {"lpad_string", {"abcdef", Int64(3), "defgh"}, "abc"},
        {"lpad_string", {"abcde", Int64(4), "defgh"}, "abcd"},
        {"lpad_string", {"abcde", Int64(3), "defgh"}, "abc"},
        {"lpad_string", {"abc", Int64(5), "defgh"}, "deabc"},
        {"lpad_string", {"abc", Int64(7), "defg"}, "defgabc"},
        {"lpad_string", {"abc", Int64(4), "def"}, "dabc"},
        {"lpad_string", {"abc", Int64(10), "defg"}, "defgdefabc"},
        {"lpad_string", {"abcx", Int64(5), "defgh"}, "dabcx"},
        {"lpad_string", {"abcx", Int64(7), "defg"}, "defabcx"},
        {"lpad_string", {"abcx", Int64(10), "defg"}, "defgdeabcx"},
        {"lpad_string", {"abc", Int64(7), "-"}, "----abc"},
        {"lpad_string", {"", Int64(7), "-"}, "-------"},
        {"lpad_string", {"", Int64(7), "def"}, "defdefd"},
        {"lpad_string", {"¼¼¼𠈓𠈓𠈓", Int64(6), "智者不終朝"}, "¼¼¼𠈓𠈓𠈓"},
        {"lpad_string", {"¼¼¼𠈓𠈓𠈓", Int64(5), "智者不終朝"}, "¼¼¼𠈓𠈓"},
        {"lpad_string", {"¼¼¼𠈓𠈓𠈓", Int64(7), "智者不終朝"}, "智¼¼¼𠈓𠈓𠈓"},
        {"lpad_string", {"¼¼¼𠈓𠈓𠈓", Int64(10), "智者朝"}, "智者朝智¼¼¼𠈓𠈓𠈓"},
        {"lpad_string", {"¼¼𠈓𠈓", Int64(10), "智者朝"}, "智者朝智者朝¼¼𠈓𠈓"},
  
        {"lpad_string", {"¼¼¼𠈓𠈓𠈓", Int64(7)}, " ¼¼¼𠈓𠈓𠈓"},
        {"lpad_string", {"¼¼¼𠈓𠈓𠈓", Int64(10)}, "    ¼¼¼𠈓𠈓𠈓"},
        {"lpad_string", {"", Int64(5)}, "     "},
    };
  
    {
      std::string bad_utf8;
  
      bad_utf8.push_back(0xD7);
      bad_utf8.push_back('\xFF');
      bad_utf8.push_back(0xD8);
      bad_utf8.push_back('\xFF');
  
      tests.push_back({"lpad_string",
                       {"valid", Int64(10), bad_utf8},
                       NullString(),
                       OUT_OF_RANGE});
  
      tests.push_back({"lpad_string",
                       {bad_utf8, Int64(10), "valid"},
                       NullString(),
                       OUT_OF_RANGE});
  
      tests.push_back({"rpad_string",
                       {"valid", Int64(10), bad_utf8},
                       NullString(),
                       OUT_OF_RANGE});
  
      tests.push_back({"rpad_string",
                       {bad_utf8, Int64(10), "valid"},
                       NullString(),
                       OUT_OF_RANGE});
    }
    return tests;
  }
  
  std::vector<FunctionTestCall> GetFunctionTestsRepeat() {
    return {
        {"repeat", {Bytes("google"), Int64(-8)}, NullString(), OUT_OF_RANGE},
        {"repeat", {Bytes("abcx"), Int64(0)}, ""},
        {"repeat", {Bytes("abcx"), Int64(1)}, "abcx"},
        {"repeat", {Bytes("abcx"), Int64(2)}, "abcxabcx"},
        {"repeat", {Bytes("abcx"), Int64(3)}, "abcxabcxabcx"},
        {"repeat", {Bytes("abc"), Int64(2)}, "abcabc"},
        {"repeat", {Bytes(""), Int64(3)}, ""},
        {"repeat", {Bytes(""), Int64(2147483648)}, ""},
        {"repeat", {"", Int64(100)}, ""},
        {"repeat", {"¼¼¼𠈓𠈓𠈓", Int64(1)}, "¼¼¼𠈓𠈓𠈓"},
        {"repeat", {"¼¼¼a", Int64(2)}, "¼¼¼a¼¼¼a"},
        {"repeat", {"¼¼¼a", Int64(3)}, "¼¼¼a¼¼¼a¼¼¼a"},
        {"repeat", {"¼¼¼a", Int64((1 << 28))}, NullString(), OUT_OF_RANGE},
        {"repeat",
         {"¼¼¼a", Int64(std::numeric_limits<int64_t>::max())},
         NullString(),
         OUT_OF_RANGE},
    };
  }
  
  std::vector<FunctionTestCall> GetFunctionTestsReverse() {
    return {
        // String inputs.
        {"reverse", {NullString()}, NullString()},
        {"reverse", {String("")}, String("")},
        {"reverse", {String("abcABC")}, String("CBAcba")},
        {"reverse", {String("abcABCжщфЖЩФ¼𠈓")}, String("𠈓¼ФЩЖфщжCBAcba")},
        // Byte inputs.
        {"reverse", {NullBytes()}, NullBytes()},
        {"reverse", {Bytes("")}, Bytes("")},
        {"reverse", {Bytes("abcABC")}, Bytes("CBAcba")},
        {"reverse", {Bytes("\0\0\1\2\3\4")}, Bytes("\4\3\2\1\0\0")},
    };
  }
  
  std::vector<FunctionTestCall> GetFunctionTestsFromProto() {
    return {
        // Proto3 Timestamp Conversions
        {"from_proto", {Proto3Timestamp(1234, 5000)}, Timestamp(1234000005)},
        {"from_proto",
         {Proto3Timestamp(1391258096, 123450000)},
         Timestamp(1391258096123450)},
        {"from_proto",
         {Proto3Timestamp(962409600, 123456000)},
         Timestamp(962409600123456)},
        {"from_proto",
         {Proto3Timestamp(1391258096, 0)},
         Timestamp(1391258096000000)},
        {"from_proto", {Proto3Timestamp(-50400, 1000)}, Timestamp(-50399999999)},
        {"from_proto",
         {Proto3Timestamp(1391258096, 123450000)},
         Timestamp(1391258096123450)},
        {"from_proto", {Proto3Timestamp(50400, 1000)}, Timestamp(50400000001)},
        {"from_proto",
         {Proto3Timestamp(1232496059, 0)},
         Timestamp(1232496059000000)},
        {"from_proto",
         {Proto3Timestamp(253402300799, 999999999)},
         Timestamp(types::kTimestampMax)},
        {"from_proto",
         {Proto3Timestamp(-62135596800, 0)},
         Timestamp(types::kTimestampMin)},
        {"from_proto", {Proto3Timestamp(123, -1)}, NullTimestamp(), OUT_OF_RANGE},
        {"from_proto",
         {Proto3Timestamp(0, 1000000000)},
         NullTimestamp(),
         OUT_OF_RANGE},
        {"from_proto",
         {Proto3Timestamp(-62135596825, 0)},
         NullTimestamp(),
         OUT_OF_RANGE},
  
        // Proto3 Date Conversions
        {"from_proto", {Proto3Date(9999, 12, 31)}, DateFromStr("9999-12-31")},
        {"from_proto", {Proto3Date(0001, 1, 1)}, DateFromStr("0001-01-01")},
        {"from_proto", {Proto3Date(1960, 1, 07)}, DateFromStr("1960-01-07")},
        {"from_proto", {Proto3Date(1999, 12, 31)}, DateFromStr("1999-12-31")},
        {"from_proto", {Proto3Date(500, 8, 30)}, DateFromStr("0500-08-30")},
        {"from_proto", {Proto3Date(2016, 2, 29)}, DateFromStr("2016-02-29")},
        {"from_proto", {Proto3Date(2017, 2, 29)}, NullDate(), OUT_OF_RANGE},
        {"from_proto", {Proto3Date(10000, 9, 17)}, NullDate(), OUT_OF_RANGE},
        {"from_proto", {Proto3Date(2017, 11, 31)}, NullDate(), OUT_OF_RANGE},
        {"from_proto", {Proto3Date(2014, 13, 15)}, NullDate(), OUT_OF_RANGE},
        {"from_proto", {Proto3Date(0, 1, 1)}, NullDate(), OUT_OF_RANGE},
        {"from_proto", {Proto3Date(1, 0, 1)}, NullDate(), OUT_OF_RANGE},
        {"from_proto", {Proto3Date(1, 1, 0)}, NullDate(), OUT_OF_RANGE},
  
        // Proto3 Wrapper Conversions
        {"from_proto",
         {Proto3Wrapper<google::protobuf::Int32Value>(-100)},
         Int32(-100)},
        {"from_proto",
         {Proto3Wrapper<google::protobuf::Int32Value>(0)},
         Int32(0)},
        {"from_proto",
         {Proto3Wrapper<google::protobuf::Int32Value>(500)},
         Int32(500)},
        {"from_proto",
         {Proto3Wrapper<google::protobuf::Int32Value>(int32max)},
         Int32(int32max)},
        {"from_proto",
         {Proto3Wrapper<google::protobuf::Int32Value>(int32min)},
         Int32(int32min)},
  
        {"from_proto",
         {Proto3Wrapper<google::protobuf::Int64Value>(-1000000)},
         Int64(-1000000)},
        {"from_proto",
         {Proto3Wrapper<google::protobuf::Int64Value>(0)},
         Int64(0)},
        {"from_proto",
         {Proto3Wrapper<google::protobuf::Int64Value>(200000000)},
         Int64(200000000)},
        {"from_proto",
         {Proto3Wrapper<google::protobuf::Int64Value>(int64max)},
         Int64(int64max)},
  
        {"from_proto",
         {Proto3Wrapper<google::protobuf::UInt32Value>(1000000)},
         Uint32(1000000)},
        {"from_proto",
         {Proto3Wrapper<google::protobuf::UInt32Value>(0)},
         Uint32(0)},
        {"from_proto",
         {Proto3Wrapper<google::protobuf::UInt32Value>(1000000000)},
         Uint32(1000000000)},
        {"from_proto",
         {Proto3Wrapper<google::protobuf::UInt32Value>(uint32max)},
         Uint32(uint32max)},
  
        {"from_proto",
         {Proto3Wrapper<google::protobuf::UInt64Value>(10000000)},
         Uint64(10000000)},
        {"from_proto",
         {Proto3Wrapper<google::protobuf::UInt64Value>(0)},
         Uint64(0)},
        {"from_proto",
         {Proto3Wrapper<google::protobuf::UInt64Value>(3000000000)},
         Uint64(3000000000)},
        {"from_proto",
         {Proto3Wrapper<google::protobuf::UInt64Value>(uint64max)},
         Uint64(uint64max)},
  
        {"from_proto",
         {Proto3Wrapper<google::protobuf::DoubleValue>(-12345467.89111)},
         Double(-12345467.89111)},
        {"from_proto",
         {Proto3Wrapper<google::protobuf::DoubleValue>(0)},
         Double(0)},
        {"from_proto",
         {Proto3Wrapper<google::protobuf::DoubleValue>(9876543210.123456)},
         Double(9876543210.123456)},
        {"from_proto",
         {Proto3Wrapper<google::protobuf::DoubleValue>(doublemax)},
         Double(doublemax)},
        {"from_proto",
         {Proto3Wrapper<google::protobuf::DoubleValue>(doublemin)},
         Double(doublemin)},
        {"from_proto",
         {Proto3Wrapper<google::protobuf::DoubleValue>(double_nan)},
         Double(double_nan)},
  
        {"from_proto",
         {Proto3Wrapper<google::protobuf::FloatValue>(-1234.891f)},
         Float(-1234.891f)},
        {"from_proto",
         {Proto3Wrapper<google::protobuf::FloatValue>(0)},
         Float(0)},
        {"from_proto",
         {Proto3Wrapper<google::protobuf::FloatValue>(9910.12f)},
         Float(9910.12f)},
        {"from_proto",
         {Proto3Wrapper<google::protobuf::FloatValue>(floatmin)},
         Float(floatmin)},
        {"from_proto",
         {Proto3Wrapper<google::protobuf::FloatValue>(floatmax)},
         Float(floatmax)},
        {"from_proto",
         {Proto3Wrapper<google::protobuf::FloatValue>(float_nan)},
         Float(float_nan)},
  
        {"from_proto",
         {Proto3Wrapper<google::protobuf::StringValue>("abcdefg")},
         String("abcdefg")},
        {"from_proto",
         {Proto3Wrapper<google::protobuf::StringValue>("")},
         String("")},
        {"from_proto",
         {Proto3Wrapper<google::protobuf::StringValue>("?!#$%^&*!")},
         String("?!#$%^&*!")},
        {"from_proto",
         {Proto3Wrapper<google::protobuf::StringValue>("   ыфabcщ   ")},
         String("   ыфabcщ   ")},
        {"from_proto",
         {Proto3Wrapper<google::protobuf::StringValue>("12356789")},
         String("12356789")},
        {"from_proto",
         {Proto3Wrapper<google::protobuf::BytesValue>(absl::Cord("abcdefg"))},
         Bytes(absl::Cord("abcdefg"))},
        {"from_proto",
         {Proto3Wrapper<google::protobuf::BytesValue>(absl::Cord(""))},
         Bytes(absl::Cord(""))},
        {"from_proto",
         {Proto3Wrapper<google::protobuf::BytesValue>(absl::Cord("\xd7\x00"))},
         Bytes("\xd7")},
        {"from_proto",
         {Proto3Wrapper<google::protobuf::BytesValue>(
             absl::Cord("\xFF\x80\x81xyz\x81\x80\xFF"))},
         Bytes("\xFF\x80\x81xyz\x81\x80\xFF")},
        {"from_proto",
         {Proto3Wrapper<google::protobuf::BytesValue>(absl::Cord("a \0xyza \0"))},
         Bytes("a ")},
        {"from_proto",
         {Proto3Wrapper<google::protobuf::BoolValue>(true)},
         Bool(true)},
        {"from_proto",
         {Proto3Wrapper<google::protobuf::BoolValue>(false)},
         Bool(false)},
  
        // Idempotent tests
        {"from_proto", {Bool(false)}, Bool(false)},
        {"from_proto", {Bytes("abc")}, Bytes("abc")},
        {"from_proto", {String("abc")}, String("abc")},
        {"from_proto", {Int32(123)}, Int32(123)},
        {"from_proto", {Uint32(123)}, Uint32(123)},
        {"from_proto", {Int64(123)}, Int64(123)},
        {"from_proto", {Uint64(123)}, Uint64(123)},
        {"from_proto", {Double(12.3)}, Double(12.3)},
        {"from_proto", {Float(9910.12f)}, Float(9910.12f)},
        {"from_proto", {DateFromStr("1960-01-07")}, DateFromStr("1960-01-07")},
        {"from_proto", {Timestamp(1234000005)}, Timestamp(1234000005)},
        {"from_proto", {Bool(false)}, Bool(false)},
  
        // Null input
        {"from_proto", {NullInt64()}, NullInt64()},
        {"from_proto", {Value::Null(Proto3DateType())}, NullDate()},
        {"from_proto", {Value::Null(Proto3TimestampType())}, NullTimestamp()},
  
        // Invalid argument
        {"from_proto",
         {KitchenSink("int64_key_1: 1 int64_key_2: 2")},
         NullInt64(),
         INVALID_ARGUMENT},
    };
  }
  
  static absl::Status FunctionEvalError() {
    return absl::Status(absl::StatusCode::kOutOfRange,
                        "Function Evaluation Error");
  }
  
  std::vector<QueryParamsWithResult>  GetFunctionTestsFromProto3TimeOfDay() {
    std::vector<CivilTimeTestCase> test_cases = {
        {{Proto3TimeOfDay(0, 0, 0, 0)}, TimeFromStr("00:00:00")},
        {{{Proto3TimeOfDay(12, 34, 56, 123456)}},
         TimeFromStr("12:34:56.000123"),
         TimeFromStr("12:34:56.000123456", functions::kNanoseconds)},
        {{{Proto3TimeOfDay(23, 59, 59, 999999)}},
         TimeFromStr("23:59:59.000999"),
         TimeFromStr("23:59:59.000999999", functions::kNanoseconds)},
        {{{Proto3TimeOfDay(7, 0, 6, 654321)}},
         TimeFromStr("07:00:06.000654"),
         TimeFromStr("07:00:06.000654321", functions::kNanoseconds)},
        {{{Proto3TimeOfDay(13, 30, 17, 987654)}},
         TimeFromStr("13:30:17.000987"),
         TimeFromStr("13:30:17.000987654", functions::kNanoseconds)},
        {{TimeFromStr("12:34:56.000987")}, TimeFromStr("12:34:56.000987")},
        {{TimeFromStr("12:34:56.000987654", functions::kNanoseconds)},
         TimeFromStr("12:34:56.000987654", functions::kNanoseconds)},
        {{Proto3TimeOfDay(02, 0, 59, 0)}, TimeFromStr("02:00:59")},
        {{Proto3TimeOfDay(02, 0, 60, 0)}, FunctionEvalError(), TimeType()},
        {{Proto3TimeOfDay(02, 0, 30, 1000000000)},
         FunctionEvalError(),
         TimeType()},
        {{Proto3TimeOfDay(24, 0, 0, 0)}, FunctionEvalError(), TimeType()}};
  
    std::vector<QueryParamsWithResult> result;
    result.reserve(test_cases.size());
    for (const CivilTimeTestCase& test : test_cases) {
      result.push_back(WrapResultForCivilTimeAndNanos(test));
    }
  
    return result;
  }
  
  
  // To generate the TO_PROTO tests, we take the FROM_PROTO tests and swap
  // the argument and result values.  For tests where the FROM_PROTO argument
  // is a proto (the normal case), we also add an idempotent TO_PROTO test.
  std::vector<FunctionTestCall> GetFunctionTestsToProto() {
    const std::string kFunctionName = "to_proto";
    std::vector<FunctionTestCall> test_cases;
    test_cases.reserve(GetFunctionTestsFromProto().size());
    for (const FunctionTestCall& test : GetFunctionTestsFromProto()) {
      if (!test.params.status().ok() || !test.params.param(0).type()->IsProto() ||
          test.params.result() == Timestamp(types::kTimestampMax)) {
        // Skip FROM_PROTO tests where the argument is not a proto (FROM_PROTO
        // idempotent tests), and tests that return errors.  Also skip tests
        // where the FROM_PROTO result is kTimestampMax (micros precision) as it
        // not possible for TO_PROTO to produce the max Proto3 Timestamp (nanos
        // precision) value from a micros TIMESTAMP.
        continue;
      }
      test_cases.emplace_back(
          kFunctionName, ValueConstructor::FromValues({test.params.param(0)}),
          test.params.param(0));
      test_cases.emplace_back(
          kFunctionName, ValueConstructor::FromValues({test.params.result()}),
          test.params.param(0));
    }
  
    // Null input
    test_cases.push_back(
        {"to_proto",
         {NullInt64()},
         Null(Proto3Wrapper<google::protobuf::Int64Value>(0).type())});
  
    // Invalid input
    test_cases.push_back({"to_proto",
                                {zetasql::values::Int64Array({13})},
                                NullInt64(),
                                INVALID_ARGUMENT});
  
    return test_cases;
  }
  
  std::vector<QueryParamsWithResult> GetFunctionTestsToProto3TimeOfDay() {
    std::vector<QueryParamsWithResult> test_cases = {
        {{TimeFromStr("00:00:00")}, Proto3TimeOfDay(0, 0, 0, 0)},
        {{TimeFromStr("12:34:56.000123")}, Proto3TimeOfDay(12, 34, 56, 123000)},
        {{TimeFromStr("23:59:59.000999")}, Proto3TimeOfDay(23, 59, 59, 999000)},
        {{TimeFromStr("07:00:06.000654")}, Proto3TimeOfDay(7, 0, 6, 654000)},
        {{TimeFromStr("13:30:17.000987")}, Proto3TimeOfDay(13, 30, 17, 987000)},
        {{TimeFromStr("02:00:59")}, Proto3TimeOfDay(02, 0, 59, 0)},
        {{Proto3TimeOfDay(13, 30, 17, 987000)},
         Proto3TimeOfDay(13, 30, 17, 987000)}};
  
    for (auto&& test : test_cases) {
      test = test.WrapWithFeature(FEATURE_V_1_2_CIVIL_TIME);
    }
  
    std::vector<QueryParamsWithResult> nanos_test_cases = {
        {{TimeFromStr("12:34:56.000123456", functions::kNanoseconds)},
         Proto3TimeOfDay(12, 34, 56, 123456)},
        {{TimeFromStr("23:59:59.000999999", functions::kNanoseconds)},
         Proto3TimeOfDay(23, 59, 59, 999999)},
        {{TimeFromStr("07:00:06.000654321", functions::kNanoseconds)},
         Proto3TimeOfDay(7, 0, 6, 654321)},
        {{TimeFromStr("13:30:17.000987654", functions::kNanoseconds)},
         Proto3TimeOfDay(13, 30, 17, 987654)},
        {{TimeFromStr("13:30:17.000987654", functions::kNanoseconds)},
         Proto3TimeOfDay(13, 30, 17, 987654)},
        {{TimeFromStr("13:30:17.123456789", functions::kNanoseconds)},
         Proto3TimeOfDay(13, 30, 17, 123456789)},
        {{Proto3TimeOfDay(13, 30, 17, 123456789)},
         Proto3TimeOfDay(13, 30, 17, 123456789)}};
  
    for (auto&& test : nanos_test_cases) {
      test = test.WrapWithFeatureSet(
          {FEATURE_V_1_2_CIVIL_TIME, FEATURE_TIMESTAMP_NANOS});
      test_cases.push_back(test);
    }
    return test_cases;
  }
  
  std::vector<FunctionTestCall> GetFunctionTestsBytesStringConversion() {
    const std::map<std::string, std::vector<std::pair<Value, Value>>>
        format_bytes_string = {
            {"hex",
             {
                 {Bytes("abcABC"), String("616263414243")},
                 {Bytes("abcABCжщфЖЩФ"),
                  String("616263414243d0b6d189d184d096d0a9d0a4")},
                 {Bytes("\0\0a\ff\xee"), String("0000610c66ee")},
                 {Bytes("\x01\x23\x45\x67\x89\xAB\xCD\xEF\x55\xAA"),
                  String("0123456789abcdef55aa")},
                 {Bytes("\xFE\xDC\xBA\x98\x76\x54\x32\x10\xAA\x55"),
                  String("fedcba9876543210aa55")},
             }},
            {"base64",
             {
                 {Bytes(" "), String("IA==")},
                 {Bytes("abcABC"), String("YWJjQUJD")},
                 {Bytes("abcABCжщфЖЩФ"), String("YWJjQUJD0LbRidGE0JbQqdCk")},
                 {Bytes("Ḋ"), String("4biK")},
                 {Bytes("abca\0b\0c\0"), String("YWJjYQBiAGMA")},
                 {Bytes("\x5a\x1b\x5a\x5a\x1b\x5a\x5a\x1b\x5a\x5a\x1b\x5a\x5a\x1b"
                        "\x5a\x5a\x1b\x5a\x5a\x1b\x5a\x5a\x1b\x5a\x5a\x1b\x5a\x5a"
                        "\x1b\x5a\x5a\x1b\x5a\x5a\x1b\x5a\x5a\x1b\x5a\x5a\x1b\x5a"
                        "\x5a\x1b\x5a\x5a\x1b\x5a\x5a\x1b\x5a\x5a\x1b\x5a\x5a\x1b"
                        "\x5a\x5a\x1b\x5a"),
                  String("WhtaWhtaWhtaWhtaWhtaWhtaWhtaWhtaWhtaWhtaWhtaWhtaWhtaWht"
                         "aWhtaWhtaWhtaWhtaWhtaWhta")},
             }},
            {"base64m",
             {
                 {Bytes(" "), String("IA==")},
                 {Bytes("abcABC"), String("YWJjQUJD")},
                 {Bytes("abcABCжщфЖЩФ"), String("YWJjQUJD0LbRidGE0JbQqdCk")},
                 {Bytes("Ḋ"), String("4biK")},
                 {Bytes("abca\0b\0c\0"), String("YWJjYQBiAGMA")},
                 {Bytes("\x5a\x1b\x5a\x5a\x1b\x5a\x5a\x1b\x5a\x5a\x1b\x5a\x5a\x1b"
                        "\x5a\x5a\x1b\x5a\x5a\x1b\x5a\x5a\x1b\x5a\x5a\x1b\x5a\x5a"
                        "\x1b\x5a\x5a\x1b\x5a\x5a\x1b\x5a\x5a\x1b\x5a\x5a\x1b\x5a"
                        "\x5a\x1b\x5a\x5a\x1b\x5a\x5a\x1b\x5a\x5a\x1b\x5a\x5a\x1b"
                        "\x5a\x5a\x1b\x5a"),
                  String("WhtaWhtaWhtaWhtaWhtaWhtaWhtaWhtaWhtaWhtaWhtaWhtaWhtaWht"
                         "aWhtaWhtaWhtaWhtaWhta\nWhta")},
                 {Bytes("\x5a\x1b\x5a\x5a\x1b\x5a\x5a\x1b\x5a\x5a\x1b\x5a\x5a\x1b"
                        "\x5a\x5a\x1b\x5a\x5a\x1b\x5a\x5a\x1b\x5a\x5a\x1b\x5a\x5a"
                        "\x1b\x5a\x5a\x1b\x5a\x5a\x1b\x5a\x5a\x1b\x5a\x5a\x1b\x5a"
                        "\x5a\x1b\x5a\x5a\x1b\x5a\x5a\x1b\x5a\x5a\x1b\x5a\x5a\x1b"
                        "\x5a\x5a\x1b\x5a\x5a\x1b\x5a\x5a\x1b\x5a\x5a\x1b\x5a\x5a"
                        "\x1b\x5a\x5a\x1b\x5a\x5a\x1b\x5a\x5a\x1b\x5a\x5a\x1b\x5a"
                        "\x5a\x1b\x5a\x5a\x1b\x5a\x5a\x1b\x5a\x5a\x1b\x5a\x5a\x1b"
                        "\x5a\x5a\x1b\x5a\x5a\x1b\x5a\x5a\x1b\x5a\x5a\x1b\x5a\x5a"
                        "\x1b\x5a\x5a\x1b\x5a"),
                  String("WhtaWhtaWhtaWhtaWhtaWhtaWhtaWhtaWhtaWhtaWhtaWhtaWhtaWht"
                         "aWhtaWhtaWhtaWhtaWhta\nWhtaWhtaWhtaWhtaWhtaWhtaWhtaWhta"
                         "WhtaWhtaWhtaWhtaWhtaWhtaWhtaWhtaWhtaWhtaWhta\nWhta")},
                 {Bytes("\x5a\x1b\x5a\x5a\x1b\x5a\x5a\x1b\x5a\x5a\x1b\x5a\x5a\x1b"
                        "\x5a\x5a\x1b\x5a\x5a\x1b\x5a\x5a\x1b\x5a\x5a\x1b\x5a\x5a"
                        "\x1b\x5a\x5a\x1b\x5a\x5a\x1b\x5a\x5a\x1b\x5a\x5a\x1b\x5a"
                        "\x5a\x1b\x5a\x5a\x1b\x5a\x5a\x1b\x5a\x5a\x1b\x5a\x5a\x1b"
                        "\x5a\x5a\x1b\x5a\x5a\x1b\x5a\x5a\x1b\x5a\x5a\x1b\x5a\x5a"
                        "\x1b\x5a\x5a\x1b\x5a\x5a\x1b\x5a\x5a\x1b\x5a\x5a\x1b\x5a"
                        "\x5a\x1b\x5a\x5a\x1b\x5a\x5a\x1b\x5a\x5a\x1b\x5a\x5a\x1b"
                        "\x5a\x5a\x1b\x5a\x5a\x1b\x5a\x5a\x1b\x5a\x5a\x1b\x5a\x5a"
                        "\x1b\x5a"),
                  String("WhtaWhtaWhtaWhtaWhtaWhtaWhtaWhtaWhtaWhtaWhtaWhtaWhtaWht"
                         "aWhtaWhtaWhtaWhtaWhta\nWhtaWhtaWhtaWhtaWhtaWhtaWhtaWhta"
                         "WhtaWhtaWhtaWhtaWhtaWhtaWhtaWhtaWhtaWhtaWhta")},
             }},
            {"base2",
             {
                 {Bytes("\x6A"), String("01101010")},
                 {Bytes("\x17\x6A"), String("0001011101101010")},
             }},
            {"base8",
             {
                 {Bytes("\x3F"), String("077")},
                 {Bytes("\x11\x3B"), String("010473")},
                 {Bytes("\x02\x11\x3B"), String("00410473")},
                 {Bytes("\x2C\x26\x02\x11\x3B"), String("02604600410473")},
             }},
            {"base32",
             {
                 {Bytes("1"), String("GE======")},
                 {Bytes("1a"), String("GFQQ====")},
                 {Bytes("12345"), String("GEZDGNBV")},
                 {Bytes("123456"), String("GEZDGNBVGY======")},
                 {Bytes("1234567890123456"),
                  String("GEZDGNBVGY3TQOJQGEZDGNBVGY======")},
             }},
            {"ascii",
             {
                 {Bytes("\x61"), String("a")},
                 {Bytes("\x61\x62\x63"), String("abc")},
             }},
            {"utf8",
             {
                 {Bytes("\x24"), String("$")},
                 {Bytes("\xC2\xA3"), String("£")},
                 {Bytes("\xE2\x82\xAC"), String("€")},
                 {Bytes("\xE2\x82\xAC\xC2\xA3"), String("€£")},
             }},
        };
  
    const std::vector<std::pair<Value, Value>> common_string_bytes = {
        {NullBytes(), NullString()},
        {Bytes(""), String("")},
    };
  
    std::vector<FunctionTestCall> tests;
    const std::vector<std::string> supported_formats = {
        "base2",  "base8",   "base16", "hex",
        "base64", "base64m", "ascii",  "utf-8", "utf8"};
    for (const std::string& supported_format : supported_formats) {
      std::string format_key = supported_format;
      if (format_key == "base16")
        format_key = "hex";
      else if (format_key == "utf-8")
        format_key = "utf8";
  
      for (const auto& entry : common_string_bytes) {
        tests.push_back(
            {"bytes_to_string", {entry.first, supported_format}, entry.second});
        tests.push_back(
            {"string_to_bytes", {entry.second, supported_format}, entry.first});
      }
      for (const auto& entry : format_bytes_string.at(format_key)) {
        tests.push_back(
            {"bytes_to_string", {entry.first, supported_format}, entry.second});
        tests.push_back(
            {"string_to_bytes", {entry.second, supported_format}, entry.first});
      }
    }
  
    // Null or unsupported format
    tests.push_back(
        {"bytes_to_string", {Bytes("\x17\x6A"), NullString()}, NullString()});
    tests.push_back({"bytes_to_string",
                     {Bytes("\x17\x6A"), "base37"},
                     NullString(),
                     OUT_OF_RANGE});
    tests.push_back({"string_to_bytes",
                     {String("0001011101101010"), NullString()},
                     NullBytes()});
    tests.push_back({"string_to_bytes",
                     {String("0001011101101010"), "base37"},
                     NullBytes(),
                     OUT_OF_RANGE});
  
    // Not encodable input bytes for specific encodings
    tests.push_back({"bytes_to_string",
                     {Bytes("\xff"), "ascii"},
                     NullString(),
                     OUT_OF_RANGE});
    tests.push_back({"bytes_to_string",
                     {Bytes("\x61\x61\xff\x61"), "ascii"},
                     NullString(),
                     OUT_OF_RANGE});
    tests.push_back({"bytes_to_string",
                     {Bytes("\xff"), "utf-8"},
                     NullString(),
                     OUT_OF_RANGE});
    tests.push_back({"bytes_to_string",
                     {Bytes("\xe2\x82\xac\xff"), "utf-8"},
                     NullString(),
                     OUT_OF_RANGE});
  
    // irregular number of digits to unescape
    tests.push_back(
        {"string_to_bytes", {String("1101010"), "base2"}, Bytes("\x6A")});
    tests.push_back({"string_to_bytes",
                     {String("1011101101010"), "base2"},
                     Bytes("\x17\x6A")});
    tests.push_back({"string_to_bytes",
                     {String("01011101101010"), "base2"},
                     Bytes("\x17\x6A")});
    tests.push_back({"string_to_bytes",
                     {String("001011101101010"), "base2"},
                     Bytes("\x17\x6A")});
  
    tests.push_back({"string_to_bytes", {String("77"), "base8"}, Bytes("\x3F")});
    tests.push_back(
        {"string_to_bytes", {String("10473"), "base8"}, Bytes("\x11\x3B")});
    tests.push_back(
        {"string_to_bytes", {String("0410473"), "base8"}, Bytes("\x02\x11\x3B")});
    tests.push_back({"string_to_bytes",
                     {String("2604600410473"), "base8"},
                     Bytes("\x2C\x26\x02\x11\x3B")});
  
    // Not decodable input string for specific encodings
    tests.push_back(
        {"string_to_bytes", {String("012"), "base2"}, NullBytes(), OUT_OF_RANGE});
    tests.push_back(
        {"string_to_bytes", {String("099"), "base8"}, NullBytes(), OUT_OF_RANGE});
    tests.push_back({"string_to_bytes",
                     {String("123g321"), "base16"},
                     NullBytes(),
                     OUT_OF_RANGE});
    tests.push_back({"string_to_bytes",
                     {String("123g321"), "hex"},
                     NullBytes(),
                     OUT_OF_RANGE});
    tests.push_back({"string_to_bytes",
                     {String("3!2+7w=="), "base64"},
                     NullBytes(),
                     OUT_OF_RANGE});
    tests.push_back({"string_to_bytes",
                     {String("3!2+7w=="), "base64m"},
                     NullBytes(),
                     OUT_OF_RANGE});
    tests.push_back({"string_to_bytes",
                     {String("sd£sd"), "ascii"},
                     NullBytes(),
                     OUT_OF_RANGE});
    tests.push_back({"string_to_bytes",
                     {String("sd\xffsd"), "ascii"},
                     NullBytes(),
                     OUT_OF_RANGE});
    tests.push_back({"string_to_bytes",
                     {String("£\xff£"), "utf8"},
                     NullBytes(),
                     OUT_OF_RANGE});
    tests.push_back({"string_to_bytes",
                     {String("£\xff£"), "utf-8"},
                     NullBytes(),
                     OUT_OF_RANGE});
  
    return tests;
  }
  
  }  // namespace zetasql
  