| /* |
| * 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 <memory> |
| #include <string> |
| |
| #include <gtest/gtest.h> |
| |
| #include "iceberg/test/matchers.h" |
| #include "iceberg/transform.h" |
| |
| namespace iceberg { |
| |
| struct HumanStringTestParam { |
| std::string test_name; |
| std::shared_ptr<Type> source_type; |
| Literal literal; |
| std::vector<std::string> expecteds; |
| }; |
| |
| class IdentityHumanStringTest : public ::testing::TestWithParam<HumanStringTestParam> { |
| protected: |
| std::vector<std::shared_ptr<Transform>> transforms_{{Transform::Identity()}}; |
| }; |
| |
| TEST_P(IdentityHumanStringTest, ToHumanString) { |
| const auto& param = GetParam(); |
| for (int32_t i = 0; i < transforms_.size(); ++i) { |
| EXPECT_THAT(transforms_[i]->ToHumanString(param.literal), |
| HasValue(::testing::Eq(param.expecteds[i]))); |
| } |
| } |
| |
| INSTANTIATE_TEST_SUITE_P( |
| IdentityHumanStringTestCases, IdentityHumanStringTest, |
| ::testing::Values( |
| HumanStringTestParam{.test_name = "Null", |
| .literal = Literal::Null(std::make_shared<IntType>()), |
| .expecteds{"null"}}, |
| HumanStringTestParam{.test_name = "Binary", |
| .literal = Literal::Binary(std::vector<uint8_t>{1, 2, 3}), |
| .expecteds{"AQID"}}, |
| HumanStringTestParam{.test_name = "Fixed", |
| .literal = Literal::Fixed(std::vector<uint8_t>{1, 2, 3}), |
| .expecteds{"AQID"}}, |
| HumanStringTestParam{.test_name = "Date", |
| .literal = Literal::Date(17501), |
| .expecteds{"2017-12-01"}}, |
| HumanStringTestParam{.test_name = "Time", |
| .literal = Literal::Time(36775038194), |
| .expecteds{"10:12:55.038194"}}, |
| HumanStringTestParam{.test_name = "TimestampWithZone", |
| .literal = Literal::TimestampTz(1512151975038194), |
| .expecteds{"2017-12-01T18:12:55.038194+00:00"}}, |
| HumanStringTestParam{.test_name = "TimestampWithoutZone", |
| .literal = Literal::Timestamp(1512123175038194), |
| .expecteds{"2017-12-01T10:12:55.038194"}}, |
| HumanStringTestParam{.test_name = "Long", |
| .literal = Literal::Long(-1234567890000L), |
| .expecteds{"-1234567890000"}}, |
| HumanStringTestParam{.test_name = "String", |
| .literal = Literal::String("a/b/c=d"), |
| .expecteds{"a/b/c=d"}}), |
| [](const ::testing::TestParamInfo<HumanStringTestParam>& info) { |
| return info.param.test_name; |
| }); |
| |
| class DateHumanStringTest : public ::testing::TestWithParam<HumanStringTestParam> { |
| protected: |
| std::vector<std::shared_ptr<Transform>> transforms_{ |
| Transform::Year(), Transform::Month(), Transform::Day()}; |
| }; |
| |
| TEST_P(DateHumanStringTest, ToHumanString) { |
| const auto& param = GetParam(); |
| |
| for (uint32_t i = 0; i < transforms_.size(); i++) { |
| ICEBERG_UNWRAP_OR_FAIL(auto trans_func, |
| transforms_[i]->Bind(std::make_shared<DateType>())); |
| ICEBERG_UNWRAP_OR_FAIL(auto literal, trans_func->Transform(param.literal)); |
| EXPECT_THAT(transforms_[i]->ToHumanString(literal), |
| HasValue(::testing::Eq(param.expecteds[i]))); |
| } |
| } |
| |
| INSTANTIATE_TEST_SUITE_P( |
| DateHumanStringTestCases, DateHumanStringTest, |
| ::testing::Values( |
| HumanStringTestParam{.test_name = "Date", |
| .literal = Literal::Date(17501), |
| .expecteds = {"2017", "2017-12", "2017-12-01"}}, |
| HumanStringTestParam{.test_name = "NegativeDate", |
| .literal = Literal::Date(-2), |
| .expecteds = {"1969", "1969-12", "1969-12-30"}}, |
| HumanStringTestParam{.test_name = "DateLowerBound", |
| .literal = Literal::Date(0), |
| .expecteds = {"1970", "1970-01", "1970-01-01"}}, |
| HumanStringTestParam{.test_name = "NegativeDateLowerBound", |
| .literal = Literal::Date(-365), |
| .expecteds = {"1969", "1969-01", "1969-01-01"}}, |
| HumanStringTestParam{.test_name = "NegativeDateUpperBound", |
| .literal = Literal::Date(-1), |
| .expecteds = {"1969", "1969-12", "1969-12-31"}}, |
| HumanStringTestParam{.test_name = "Null", |
| .literal = Literal::Null(std::make_shared<DateType>()), |
| .expecteds = {"null", "null", "null"}}), |
| [](const ::testing::TestParamInfo<HumanStringTestParam>& info) { |
| return info.param.test_name; |
| }); |
| |
| class TimestampHumanStringTest : public ::testing::TestWithParam<HumanStringTestParam> { |
| protected: |
| std::vector<std::shared_ptr<Transform>> transforms_{ |
| Transform::Year(), Transform::Month(), Transform::Day(), Transform::Hour()}; |
| }; |
| |
| TEST_F(TimestampHumanStringTest, InvalidType) { |
| ICEBERG_UNWRAP_OR_FAIL(auto above_max, |
| Literal::Long(std::numeric_limits<int64_t>::max()) |
| .CastTo(std::make_shared<IntType>())); |
| ICEBERG_UNWRAP_OR_FAIL(auto below_min, |
| Literal::Long(std::numeric_limits<int64_t>::min()) |
| .CastTo(std::make_shared<IntType>())); |
| |
| auto unmatch_type_literal = Literal::Long(std::numeric_limits<int64_t>::max()); |
| |
| for (const auto& transform : transforms_) { |
| auto result = transform->ToHumanString(above_max); |
| EXPECT_THAT(result, IsError(ErrorKind::kNotSupported)); |
| EXPECT_THAT(result, |
| HasErrorMessage("Cannot transfrom human string for value: aboveMax")); |
| |
| result = transform->ToHumanString(below_min); |
| EXPECT_THAT(result, IsError(ErrorKind::kNotSupported)); |
| EXPECT_THAT(result, |
| HasErrorMessage("Cannot transfrom human string for value: belowMin")); |
| |
| result = transform->ToHumanString(unmatch_type_literal); |
| EXPECT_THAT(result, IsError(ErrorKind::kNotSupported)); |
| EXPECT_THAT(result, HasErrorMessage(std::format( |
| "Transfrom human {} from type {} is not supported", |
| TransformTypeToString(transform->transform_type()), |
| unmatch_type_literal.type()->ToString()))); |
| } |
| } |
| |
| TEST_P(TimestampHumanStringTest, ToHumanString) { |
| const auto& param = GetParam(); |
| for (uint32_t i = 0; i < transforms_.size(); i++) { |
| ICEBERG_UNWRAP_OR_FAIL(auto trans_func, transforms_[i]->Bind(param.source_type)); |
| ICEBERG_UNWRAP_OR_FAIL(auto literal, trans_func->Transform(param.literal)); |
| EXPECT_THAT(transforms_[i]->ToHumanString(literal), |
| HasValue(::testing::Eq(param.expecteds[i]))); |
| } |
| } |
| |
| INSTANTIATE_TEST_SUITE_P( |
| TimestampHumanStringTestCases, TimestampHumanStringTest, |
| ::testing::Values( |
| HumanStringTestParam{ |
| .test_name = "Timestamp", |
| .source_type = std::make_shared<TimestampType>(), |
| .literal = Literal::Timestamp(1512123175038194), |
| .expecteds = {"2017", "2017-12", "2017-12-01", "2017-12-01-10"}}, |
| HumanStringTestParam{ |
| .test_name = "NegativeTimestamp", |
| .source_type = std::make_shared<TimestampType>(), |
| .literal = Literal::Timestamp(-136024961806), |
| .expecteds = {"1969", "1969-12", "1969-12-30", "1969-12-30-10"}}, |
| HumanStringTestParam{ |
| .test_name = "TimestampLowerBound", |
| .source_type = std::make_shared<TimestampType>(), |
| .literal = Literal::Timestamp(0), |
| .expecteds = {"1970", "1970-01", "1970-01-01", "1970-01-01-00"}}, |
| HumanStringTestParam{ |
| .test_name = "NegativeTimestampLowerBound", |
| .source_type = std::make_shared<TimestampType>(), |
| .literal = Literal::Timestamp(-172800000000), |
| .expecteds = {"1969", "1969-12", "1969-12-30", "1969-12-30-00"}, |
| }, |
| HumanStringTestParam{ |
| .test_name = "NegativeTimestampUpperBound", |
| .source_type = std::make_shared<TimestampType>(), |
| .literal = Literal::Timestamp(-1), |
| .expecteds = {"1969", "1969-12", "1969-12-31", "1969-12-31-23"}}, |
| HumanStringTestParam{ |
| .test_name = "TimestampTz", |
| .source_type = std::make_shared<TimestampTzType>(), |
| .literal = Literal::TimestampTz(1512151975038194), |
| .expecteds = {"2017", "2017-12", "2017-12-01", "2017-12-01-18"}}, |
| HumanStringTestParam{.test_name = "Null", |
| .source_type = std::make_shared<TimestampType>(), |
| .literal = Literal::Null(std::make_shared<TimestampType>()), |
| .expecteds = {"null", "null", "null", "null"}}), |
| [](const ::testing::TestParamInfo<HumanStringTestParam>& info) { |
| return info.param.test_name; |
| }); |
| |
| } // namespace iceberg |