| /* | |
| * Licensed to the Apache Software Foundation (ASF) under one | |
| * or more contributor license agreements. See the NOTICE file | |
| * distributed with this work for additional information | |
| * regarding copyright ownership. The ASF licenses this file | |
| * to you 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 "paimon/common/data/data_define.h" | |
| #include "arrow/api.h" | |
| #include "arrow/array/array_base.h" | |
| #include "arrow/array/array_binary.h" | |
| #include "arrow/ipc/json_simple.h" | |
| #include "gtest/gtest.h" | |
| #include "paimon/common/data/binary_array.h" | |
| #include "paimon/common/data/binary_row.h" | |
| #include "paimon/common/data/binary_string.h" | |
| #include "paimon/common/utils/decimal_utils.h" | |
| #include "paimon/data/decimal.h" | |
| #include "paimon/data/timestamp.h" | |
| #include "paimon/memory/bytes.h" | |
| #include "paimon/memory/memory_pool.h" | |
| #include "paimon/testing/utils/testharness.h" | |
| namespace paimon::test { | |
| // Test case: IsVariantNull should return true for NullType | |
| TEST(DataDefineTest, IsVariantNullReturnsTrueForNull) { | |
| VariantType null_variant = NullType{}; | |
| ASSERT_TRUE(DataDefine::IsVariantNull(null_variant)); | |
| } | |
| // Test case: IsVariantNull should return false for non-NullType variants | |
| TEST(DataDefineTest, IsVariantNullReturnsFalseForNonNullTypes) { | |
| VariantType non_null_variant = 42; // Example with int | |
| ASSERT_FALSE(DataDefine::IsVariantNull(non_null_variant)); | |
| non_null_variant = true; // Example with bool | |
| ASSERT_FALSE(DataDefine::IsVariantNull(non_null_variant)); | |
| } | |
| // Test case: GetVariantValue should return valid value for matched types | |
| TEST(DataDefineTest, GetVariantValue) { | |
| { | |
| VariantType int_variant = 42; // Variant holding an int | |
| const auto int_value = DataDefine::GetVariantValue<int32_t>(int_variant); | |
| ASSERT_EQ(int_value, 42); | |
| } | |
| { | |
| VariantType bool_variant = true; // Variant holding a bool | |
| const bool bool_value = DataDefine::GetVariantValue<bool>(bool_variant); | |
| ASSERT_EQ(bool_value, true); | |
| } | |
| { | |
| auto array = std::dynamic_pointer_cast<arrow::StringArray>( | |
| arrow::ipc::internal::json::ArrayFromJSON(arrow::utf8(), R"(["abc", "def", "hello"])") | |
| .ValueOrDie()); | |
| VariantType view_variant = array->GetView(2); // Variant holding a StringView | |
| const auto view_value = DataDefine::GetVariantValue<std::string_view>(view_variant); | |
| ASSERT_EQ(std::string(view_value), "hello"); | |
| ASSERT_EQ(DataDefine::VariantValueToString(view_variant), "hello"); | |
| } | |
| } | |
| // Test case: GetVariantValue should return valid value for matching types | |
| TEST(DataDefineTest, GetVariantValueReturnsPointerForMatchingType) {} | |
| // Test case: VariantValueToString should handle NullType | |
| TEST(DataDefineTest, VariantValueToStringReturnsStringForNullType) { | |
| VariantType null_variant = NullType{}; | |
| ASSERT_EQ(DataDefine::VariantValueToString(null_variant), "null"); | |
| } | |
| // Test case: VariantValueToString should handle bool | |
| TEST(DataDefineTest, VariantValueToStringReturnsStringForBool) { | |
| VariantType bool_variant = true; | |
| ASSERT_EQ(DataDefine::VariantValueToString(bool_variant), "true"); | |
| bool_variant = false; | |
| ASSERT_EQ(DataDefine::VariantValueToString(bool_variant), "false"); | |
| } | |
| // Test case: VariantValueToString should handle integer types | |
| TEST(DataDefineTest, VariantValueToStringReturnsStringForInt) { | |
| VariantType int_variant = 42; | |
| ASSERT_EQ(DataDefine::VariantValueToString(int_variant), "42"); | |
| } | |
| // Test case: VariantValueToString should print a negative TINYINT as a negative number, which | |
| // it holds as a plain char whose signedness follows the ABI | |
| TEST(DataDefineTest, VariantValueToStringReturnsSignedStringForTinyInt) { | |
| VariantType tiny_int_variant = static_cast<char>(-20); | |
| ASSERT_EQ(DataDefine::VariantValueToString(tiny_int_variant), "-20"); | |
| tiny_int_variant = static_cast<char>(127); | |
| ASSERT_EQ(DataDefine::VariantValueToString(tiny_int_variant), "127"); | |
| tiny_int_variant = static_cast<char>(-128); | |
| ASSERT_EQ(DataDefine::VariantValueToString(tiny_int_variant), "-128"); | |
| } | |
| // Test case: VariantValueToString should handle string data (BinaryString) | |
| TEST(DataDefineTest, VariantValueToStringReturnsStringForBinaryString) { | |
| auto pool = GetDefaultPool(); | |
| auto binary_str = BinaryString::FromString("Hello, world!", pool.get()); | |
| VariantType binary_variant = binary_str; | |
| ASSERT_EQ(DataDefine::VariantValueToString(binary_variant), "Hello, world!"); | |
| } | |
| // Test case: VariantValueToString should handle shared_ptr<Bytes> | |
| TEST(DataDefineTest, VariantValueToStringReturnsStringForSharedPtrBytes) { | |
| auto pool = GetDefaultPool(); | |
| std::shared_ptr<Bytes> bytes_ptr = Bytes::AllocateBytes("abc", pool.get()); | |
| VariantType bytes_variant = bytes_ptr; | |
| ASSERT_EQ(DataDefine::VariantValueToString(bytes_variant), "abc"); | |
| } | |
| // Test case: VariantValueToString should handle Timestamp | |
| TEST(DataDefineTest, VariantValueToStringReturnsStringForTimestamp) { | |
| auto timestamp = | |
| Timestamp(/*millisecond=*/1622520000000l, /*nano_of_millisecond=*/0); // A timestamp value | |
| VariantType timestamp_variant = timestamp; | |
| ASSERT_EQ(DataDefine::VariantValueToString(timestamp_variant), timestamp.ToString()); | |
| } | |
| // Test case: VariantValueToString should handle Decimal | |
| TEST(DataDefineTest, VariantValueToStringReturnsStringForDecimal) { | |
| Decimal decimal(38, 38, DecimalUtils::StrToInt128("12345678998765432145678").value()); | |
| VariantType decimal_variant = decimal; | |
| ASSERT_EQ(DataDefine::VariantValueToString(decimal_variant), decimal.ToString()); | |
| } | |
| // Test case: VariantValueToString should handle shared_ptr<InternalRow> (mocking with a string) | |
| TEST(DataDefineTest, VariantValueToStringReturnsStringForInternalRow) { | |
| std::shared_ptr<InternalRow> row_ptr = std::make_shared<BinaryRow>(0); | |
| VariantType row_variant = row_ptr; | |
| ASSERT_EQ(DataDefine::VariantValueToString(row_variant), "row"); | |
| } | |
| // Test case: VariantValueToString should handle shared_ptr<InternalArray> (mocking with a string) | |
| TEST(DataDefineTest, VariantValueToStringReturnsStringForInternalArray) { | |
| auto pool = GetDefaultPool(); | |
| std::shared_ptr<InternalArray> array_ptr = std::make_shared<BinaryArray>(); | |
| VariantType array_variant = array_ptr; | |
| ASSERT_EQ(DataDefine::VariantValueToString(array_variant), "array"); | |
| } | |
| // Test case: GetStringView should handle all variant types and edge cases | |
| TEST(DataDefineTest, GetStringView) { | |
| auto pool = GetDefaultPool(); | |
| { | |
| // from string_view | |
| std::string original = "hello world"; | |
| VariantType view_variant = std::string_view(original.data(), original.size()); | |
| auto result = DataDefine::GetStringView(view_variant); | |
| ASSERT_EQ(result, "hello world"); | |
| ASSERT_EQ(result.data(), original.data()); | |
| } | |
| { | |
| // from shared_ptr<Bytes> | |
| std::shared_ptr<Bytes> bytes = Bytes::AllocateBytes("test bytes", pool.get()); | |
| VariantType bytes_variant = bytes; | |
| auto result = DataDefine::GetStringView(bytes_variant); | |
| ASSERT_EQ(std::string(result), "test bytes"); | |
| ASSERT_EQ(result.size(), 10); | |
| } | |
| { | |
| // from BinaryString | |
| auto binary_str = BinaryString::FromString("binary string content", pool.get()); | |
| VariantType binary_variant = binary_str; | |
| auto result = DataDefine::GetStringView(binary_variant); | |
| ASSERT_EQ(std::string(result), "binary string content"); | |
| } | |
| { | |
| // empty string_view | |
| VariantType view_variant = std::string_view(); | |
| auto result = DataDefine::GetStringView(view_variant); | |
| ASSERT_TRUE(result.empty()); | |
| ASSERT_EQ(result.size(), 0); | |
| } | |
| { | |
| // empty Bytes | |
| std::shared_ptr<Bytes> bytes = Bytes::AllocateBytes("", pool.get()); | |
| VariantType bytes_variant = bytes; | |
| auto result = DataDefine::GetStringView(bytes_variant); | |
| ASSERT_TRUE(result.empty()); | |
| ASSERT_EQ(result.size(), 0); | |
| } | |
| { | |
| // empty BinaryString | |
| VariantType binary_variant = BinaryString::EmptyUtf8(); | |
| auto result = DataDefine::GetStringView(binary_variant); | |
| ASSERT_TRUE(result.empty()); | |
| ASSERT_EQ(result.size(), 0); | |
| } | |
| } | |
| TEST(DataDefineTest, VariantValueToLiteral) { | |
| auto pool = GetDefaultPool(); | |
| { | |
| // BOOL | |
| VariantType value = true; | |
| ASSERT_OK_AND_ASSIGN(auto literal, | |
| DataDefine::VariantValueToLiteral(value, arrow::Type::type::BOOL)); | |
| ASSERT_EQ(literal.GetValue<bool>(), true); | |
| } | |
| { | |
| // INT8 | |
| VariantType value = static_cast<char>(42); | |
| ASSERT_OK_AND_ASSIGN(auto literal, | |
| DataDefine::VariantValueToLiteral(value, arrow::Type::type::INT8)); | |
| ASSERT_EQ(literal.GetValue<int8_t>(), 42); | |
| } | |
| { | |
| // INT16 | |
| VariantType value = static_cast<int16_t>(1000); | |
| ASSERT_OK_AND_ASSIGN(auto literal, | |
| DataDefine::VariantValueToLiteral(value, arrow::Type::type::INT16)); | |
| ASSERT_EQ(literal.GetValue<int16_t>(), 1000); | |
| } | |
| { | |
| // INT32 | |
| VariantType value = static_cast<int32_t>(100000); | |
| ASSERT_OK_AND_ASSIGN(auto literal, | |
| DataDefine::VariantValueToLiteral(value, arrow::Type::type::INT32)); | |
| ASSERT_EQ(literal.GetValue<int32_t>(), 100000); | |
| } | |
| { | |
| // INT64 | |
| VariantType value = static_cast<int64_t>(123456789L); | |
| ASSERT_OK_AND_ASSIGN(auto literal, | |
| DataDefine::VariantValueToLiteral(value, arrow::Type::type::INT64)); | |
| ASSERT_EQ(literal.GetValue<int64_t>(), 123456789L); | |
| } | |
| { | |
| // FLOAT | |
| VariantType value = 3.14f; | |
| ASSERT_OK_AND_ASSIGN(auto literal, | |
| DataDefine::VariantValueToLiteral(value, arrow::Type::type::FLOAT)); | |
| ASSERT_FLOAT_EQ(literal.GetValue<float>(), 3.14f); | |
| } | |
| { | |
| // DOUBLE | |
| VariantType value = 2.718; | |
| ASSERT_OK_AND_ASSIGN(auto literal, | |
| DataDefine::VariantValueToLiteral(value, arrow::Type::type::DOUBLE)); | |
| ASSERT_DOUBLE_EQ(literal.GetValue<double>(), 2.718); | |
| } | |
| { | |
| // STRING from BinaryString | |
| auto binary_str = BinaryString::FromString("hello", pool.get()); | |
| VariantType value = binary_str; | |
| ASSERT_OK_AND_ASSIGN(auto literal, | |
| DataDefine::VariantValueToLiteral(value, arrow::Type::type::STRING)); | |
| ASSERT_EQ(literal.GetValue<std::string>(), "hello"); | |
| } | |
| { | |
| // STRING from shared_ptr<Bytes> | |
| std::shared_ptr<Bytes> bytes = Bytes::AllocateBytes("world", pool.get()); | |
| VariantType value = bytes; | |
| ASSERT_OK_AND_ASSIGN(auto literal, | |
| DataDefine::VariantValueToLiteral(value, arrow::Type::type::STRING)); | |
| ASSERT_EQ(literal.GetValue<std::string>(), "world"); | |
| } | |
| { | |
| // STRING from string_view | |
| std::string original = "view_str"; | |
| VariantType value = std::string_view(original.data(), original.size()); | |
| ASSERT_OK_AND_ASSIGN(auto literal, | |
| DataDefine::VariantValueToLiteral(value, arrow::Type::type::STRING)); | |
| ASSERT_EQ(literal.GetValue<std::string>(), "view_str"); | |
| } | |
| { | |
| // BINARY from shared_ptr<Bytes> | |
| std::shared_ptr<Bytes> bytes = Bytes::AllocateBytes("binary_data", pool.get()); | |
| VariantType value = bytes; | |
| ASSERT_OK_AND_ASSIGN(auto literal, | |
| DataDefine::VariantValueToLiteral(value, arrow::Type::type::BINARY)); | |
| ASSERT_EQ(literal.GetValue<std::string>(), "binary_data"); | |
| } | |
| { | |
| // BINARY from BinaryString | |
| auto binary_str = BinaryString::FromString("bin_str", pool.get()); | |
| VariantType value = binary_str; | |
| ASSERT_OK_AND_ASSIGN(auto literal, | |
| DataDefine::VariantValueToLiteral(value, arrow::Type::type::BINARY)); | |
| ASSERT_EQ(literal.GetValue<std::string>(), "bin_str"); | |
| } | |
| { | |
| // TIMESTAMP | |
| Timestamp ts(12345, 1); | |
| VariantType value = ts; | |
| ASSERT_OK_AND_ASSIGN( | |
| auto literal, DataDefine::VariantValueToLiteral(value, arrow::Type::type::TIMESTAMP)); | |
| ASSERT_EQ(literal.GetValue<Timestamp>(), ts); | |
| } | |
| { | |
| // DECIMAL128 | |
| Decimal decimal(20, 3, 123456); | |
| VariantType value = decimal; | |
| ASSERT_OK_AND_ASSIGN( | |
| auto literal, DataDefine::VariantValueToLiteral(value, arrow::Type::type::DECIMAL128)); | |
| ASSERT_EQ(literal.GetValue<Decimal>(), decimal); | |
| } | |
| { | |
| // DATE32 | |
| VariantType value = static_cast<int32_t>(19000); | |
| ASSERT_OK_AND_ASSIGN(auto literal, | |
| DataDefine::VariantValueToLiteral(value, arrow::Type::type::DATE32)); | |
| ASSERT_EQ(literal.GetValue<int32_t>(), 19000); | |
| } | |
| { | |
| // unsupported type | |
| VariantType value = static_cast<int32_t>(0); | |
| ASSERT_NOK_WITH_MSG(DataDefine::VariantValueToLiteral(value, arrow::Type::type::LIST), | |
| "Not support arrow type"); | |
| } | |
| } | |
| } // namespace paimon::test |