| /* | |
| * 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/utils/range_helper.h" | |
| #include <optional> | |
| #include "gtest/gtest.h" | |
| #include "paimon/status.h" | |
| #include "paimon/testing/utils/testharness.h" | |
| namespace paimon::test { | |
| class RangeHelperTest : public ::testing::Test { | |
| public: | |
| void SetUp() override { | |
| start_func_ = [](const Range& range) -> Result<int64_t> { | |
| if (range.start) { | |
| return range.start.value(); | |
| } | |
| return Status::Invalid("start is null"); | |
| }; | |
| end_func_ = [](const Range& range) -> Result<int64_t> { | |
| if (range.end) { | |
| return range.end.value(); | |
| } | |
| return Status::Invalid("end is null"); | |
| }; | |
| } | |
| void TearDown() override {} | |
| struct Range { | |
| Range(const std::optional<int64_t>& _start, const std::optional<int64_t>& _end) | |
| : start(_start), end(_end) {} | |
| Range(Range&& other) : start(other.start), end(other.end) {} | |
| Range(const Range& other) = default; | |
| Range& operator=(Range&& other) noexcept { | |
| if (&other == this) { | |
| return *this; | |
| } | |
| start = other.start; | |
| end = other.end; | |
| return *this; | |
| } | |
| Range& operator=(const Range& other) noexcept { | |
| if (&other == this) { | |
| return *this; | |
| } | |
| start = other.start; | |
| end = other.end; | |
| return *this; | |
| } | |
| bool operator==(const Range& other) const { | |
| return start == other.start && end == other.end; | |
| } | |
| std::optional<int64_t> start; | |
| std::optional<int64_t> end; | |
| }; | |
| private: | |
| std::function<Result<int64_t>(const Range&)> start_func_; | |
| std::function<Result<int64_t>(const Range&)> end_func_; | |
| }; | |
| TEST_F(RangeHelperTest, TestAreAllRangesSame) { | |
| { | |
| std::vector<Range> ranges = {Range(0l, 100l), Range(0l, 100l), Range(1l, 100l)}; | |
| ASSERT_OK_AND_ASSIGN(bool same, | |
| RangeHelper(start_func_, end_func_).AreAllRangesSame(ranges)); | |
| ASSERT_FALSE(same); | |
| } | |
| { | |
| std::vector<Range> ranges = {Range(0l, 100l), Range(0l, 100l), Range(0l, 300l)}; | |
| ASSERT_OK_AND_ASSIGN(bool same, | |
| RangeHelper(start_func_, end_func_).AreAllRangesSame(ranges)); | |
| ASSERT_FALSE(same); | |
| } | |
| { | |
| std::vector<Range> ranges = {Range(0l, 100l), Range(0l, 100l), Range(0l, 100l)}; | |
| ASSERT_OK_AND_ASSIGN(bool same, | |
| RangeHelper(start_func_, end_func_).AreAllRangesSame(ranges)); | |
| ASSERT_TRUE(same); | |
| } | |
| { | |
| ASSERT_OK_AND_ASSIGN(bool same, RangeHelper(start_func_, end_func_).AreAllRangesSame({})); | |
| ASSERT_TRUE(same); | |
| } | |
| { | |
| std::vector<Range> ranges = {Range(0l, 100l)}; | |
| ASSERT_OK_AND_ASSIGN(bool same, | |
| RangeHelper(start_func_, end_func_).AreAllRangesSame(ranges)); | |
| ASSERT_TRUE(same); | |
| } | |
| { | |
| std::vector<Range> ranges = {Range(0l, std::nullopt)}; | |
| ASSERT_NOK_WITH_MSG(RangeHelper(start_func_, end_func_).AreAllRangesSame(ranges), | |
| "end is null"); | |
| } | |
| } | |
| TEST_F(RangeHelperTest, TestMergeOverlappingRanges) { | |
| { | |
| std::vector<Range> ranges = {Range(200, 299), Range(0, 99), Range(110, 199), | |
| Range(100, 109), Range(100, 199), Range(0, 49), | |
| Range(50, 99)}; | |
| ASSERT_OK_AND_ASSIGN( | |
| auto merged_ranges, | |
| RangeHelper(start_func_, end_func_).MergeOverlappingRanges(std::move(ranges))); | |
| std::vector<std::vector<Range>> expected = { | |
| {Range(0, 99), Range(0, 49), Range(50, 99)}, | |
| {Range(110, 199), Range(100, 109), Range(100, 199)}, | |
| {Range(200, 299)}, | |
| }; | |
| ASSERT_EQ(expected, merged_ranges); | |
| } | |
| { | |
| ASSERT_OK_AND_ASSIGN(auto merged_ranges, | |
| RangeHelper(start_func_, end_func_).MergeOverlappingRanges({})); | |
| ASSERT_TRUE(merged_ranges.empty()); | |
| } | |
| { | |
| std::vector<Range> ranges = {Range(0, 99)}; | |
| ASSERT_OK_AND_ASSIGN( | |
| auto merged_ranges, | |
| RangeHelper(start_func_, end_func_).MergeOverlappingRanges(std::move(ranges))); | |
| std::vector<std::vector<Range>> expected = {{Range(0, 99)}}; | |
| ASSERT_EQ(expected, merged_ranges); | |
| } | |
| { | |
| std::vector<Range> ranges = {Range(200, 299), Range(std::nullopt, 299)}; | |
| ASSERT_NOK_WITH_MSG( | |
| RangeHelper(start_func_, end_func_).MergeOverlappingRanges(std::move(ranges)), | |
| "start is null"); | |
| } | |
| } | |
| } // namespace paimon::test |