| /* | |
| * 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/utils/row_range_index.h" | |
| #include "paimon/testing/utils/testharness.h" | |
| namespace paimon::test { | |
| // ======================== Create ======================== | |
| TEST(RowRangeIndexTest, CreateWithEmptyRangesReturnsEmptyIndex) { | |
| ASSERT_OK_AND_ASSIGN(auto index, RowRangeIndex::Create({})); | |
| ASSERT_TRUE(index.Ranges().empty()); | |
| } | |
| TEST(RowRangeIndexTest, CreateWithSingleRange) { | |
| ASSERT_OK_AND_ASSIGN(auto index, RowRangeIndex::Create({Range(10, 20)})); | |
| ASSERT_EQ(index.Ranges().size(), 1); | |
| ASSERT_EQ(index.Ranges()[0], Range(10, 20)); | |
| } | |
| TEST(RowRangeIndexTest, CreateSortsAndMergesOverlappingRanges) { | |
| ASSERT_OK_AND_ASSIGN(auto index, | |
| RowRangeIndex::Create({Range(20, 30), Range(0, 10), Range(5, 15)})); | |
| std::vector<Range> expected = {Range(0, 15), Range(20, 30)}; | |
| ASSERT_EQ(index.Ranges(), expected); | |
| } | |
| TEST(RowRangeIndexTest, CreateMergesAdjacentRanges) { | |
| ASSERT_OK_AND_ASSIGN(auto index, RowRangeIndex::Create({Range(0, 10), Range(11, 20)})); | |
| std::vector<Range> expected = {Range(0, 20)}; | |
| ASSERT_EQ(index.Ranges(), expected); | |
| } | |
| TEST(RowRangeIndexTest, CreateMergesDuplicateRanges) { | |
| ASSERT_OK_AND_ASSIGN(auto index, RowRangeIndex::Create({Range(0, 10), Range(0, 10)})); | |
| std::vector<Range> expected = {Range(0, 10)}; | |
| ASSERT_EQ(index.Ranges(), expected); | |
| } | |
| TEST(RowRangeIndexTest, CreateWithMultipleDisjointRanges) { | |
| ASSERT_OK_AND_ASSIGN(auto index, | |
| RowRangeIndex::Create({Range(0, 5), Range(10, 15), Range(20, 25)})); | |
| std::vector<Range> expected = {Range(0, 5), Range(10, 15), Range(20, 25)}; | |
| ASSERT_EQ(index.Ranges(), expected); | |
| } | |
| // ======================== Ranges ======================== | |
| TEST(RowRangeIndexTest, RangesReturnsUnmodifiableReference) { | |
| ASSERT_OK_AND_ASSIGN(auto index, RowRangeIndex::Create({Range(0, 10), Range(20, 30)})); | |
| const auto& ranges1 = index.Ranges(); | |
| const auto& ranges2 = index.Ranges(); | |
| ASSERT_EQ(&ranges1, &ranges2); | |
| } | |
| // ======================== Intersects ======================== | |
| TEST(RowRangeIndexTest, IntersectsExactMatch) { | |
| ASSERT_OK_AND_ASSIGN(auto index, RowRangeIndex::Create({Range(10, 20)})); | |
| ASSERT_TRUE(index.Intersects(10, 20)); | |
| } | |
| TEST(RowRangeIndexTest, IntersectsPartialOverlapFromLeft) { | |
| ASSERT_OK_AND_ASSIGN(auto index, RowRangeIndex::Create({Range(10, 20)})); | |
| ASSERT_TRUE(index.Intersects(5, 15)); | |
| } | |
| TEST(RowRangeIndexTest, IntersectsPartialOverlapFromRight) { | |
| ASSERT_OK_AND_ASSIGN(auto index, RowRangeIndex::Create({Range(10, 20)})); | |
| ASSERT_TRUE(index.Intersects(15, 25)); | |
| } | |
| TEST(RowRangeIndexTest, IntersectsContainedRange) { | |
| ASSERT_OK_AND_ASSIGN(auto index, RowRangeIndex::Create({Range(10, 20)})); | |
| ASSERT_TRUE(index.Intersects(12, 18)); | |
| } | |
| TEST(RowRangeIndexTest, IntersectsContainingRange) { | |
| ASSERT_OK_AND_ASSIGN(auto index, RowRangeIndex::Create({Range(10, 20)})); | |
| ASSERT_TRUE(index.Intersects(0, 30)); | |
| } | |
| TEST(RowRangeIndexTest, IntersectsTouchingLeftBoundary) { | |
| ASSERT_OK_AND_ASSIGN(auto index, RowRangeIndex::Create({Range(10, 20)})); | |
| ASSERT_TRUE(index.Intersects(5, 10)); | |
| } | |
| TEST(RowRangeIndexTest, IntersectsTouchingRightBoundary) { | |
| ASSERT_OK_AND_ASSIGN(auto index, RowRangeIndex::Create({Range(10, 20)})); | |
| ASSERT_TRUE(index.Intersects(20, 25)); | |
| } | |
| TEST(RowRangeIndexTest, IntersectsNoOverlapBefore) { | |
| ASSERT_OK_AND_ASSIGN(auto index, RowRangeIndex::Create({Range(10, 20)})); | |
| ASSERT_FALSE(index.Intersects(0, 9)); | |
| } | |
| TEST(RowRangeIndexTest, IntersectsNoOverlapAfter) { | |
| ASSERT_OK_AND_ASSIGN(auto index, RowRangeIndex::Create({Range(10, 20)})); | |
| ASSERT_FALSE(index.Intersects(21, 30)); | |
| } | |
| TEST(RowRangeIndexTest, IntersectsMultipleRangesHitsFirst) { | |
| ASSERT_OK_AND_ASSIGN(auto index, | |
| RowRangeIndex::Create({Range(0, 10), Range(20, 30), Range(40, 50)})); | |
| ASSERT_TRUE(index.Intersects(5, 8)); | |
| } | |
| TEST(RowRangeIndexTest, IntersectsMultipleRangesHitsMiddle) { | |
| ASSERT_OK_AND_ASSIGN(auto index, | |
| RowRangeIndex::Create({Range(0, 10), Range(20, 30), Range(40, 50)})); | |
| ASSERT_TRUE(index.Intersects(22, 28)); | |
| } | |
| TEST(RowRangeIndexTest, IntersectsMultipleRangesHitsLast) { | |
| ASSERT_OK_AND_ASSIGN(auto index, | |
| RowRangeIndex::Create({Range(0, 10), Range(20, 30), Range(40, 50)})); | |
| ASSERT_TRUE(index.Intersects(42, 48)); | |
| } | |
| TEST(RowRangeIndexTest, IntersectsMultipleRangesSpansGap) { | |
| ASSERT_OK_AND_ASSIGN(auto index, RowRangeIndex::Create({Range(0, 10), Range(20, 30)})); | |
| ASSERT_TRUE(index.Intersects(8, 22)); | |
| } | |
| TEST(RowRangeIndexTest, IntersectsMultipleRangesFallsInGap) { | |
| ASSERT_OK_AND_ASSIGN(auto index, RowRangeIndex::Create({Range(0, 10), Range(20, 30)})); | |
| ASSERT_FALSE(index.Intersects(11, 19)); | |
| } | |
| TEST(RowRangeIndexTest, IntersectsMultipleRangesBeforeAll) { | |
| ASSERT_OK_AND_ASSIGN(auto index, RowRangeIndex::Create({Range(10, 20), Range(30, 40)})); | |
| ASSERT_FALSE(index.Intersects(0, 5)); | |
| } | |
| TEST(RowRangeIndexTest, IntersectsMultipleRangesAfterAll) { | |
| ASSERT_OK_AND_ASSIGN(auto index, RowRangeIndex::Create({Range(10, 20), Range(30, 40)})); | |
| ASSERT_FALSE(index.Intersects(50, 60)); | |
| } | |
| TEST(RowRangeIndexTest, IntersectsSinglePointMatch) { | |
| ASSERT_OK_AND_ASSIGN(auto index, RowRangeIndex::Create({Range(10, 10)})); | |
| ASSERT_TRUE(index.Intersects(10, 10)); | |
| } | |
| TEST(RowRangeIndexTest, IntersectsSinglePointNoMatch) { | |
| ASSERT_OK_AND_ASSIGN(auto index, RowRangeIndex::Create({Range(10, 10)})); | |
| ASSERT_FALSE(index.Intersects(11, 11)); | |
| } | |
| // ======================== Contains ======================== | |
| TEST(RowRangeIndexTest, ContainsAndContainsExactlyExactRange) { | |
| ASSERT_OK_AND_ASSIGN(auto index, RowRangeIndex::Create({Range(10, 20), Range(30, 40)})); | |
| Range query(10, 20); | |
| ASSERT_TRUE(index.Contains(query)); | |
| ASSERT_TRUE(index.ContainsExactly(query)); | |
| } | |
| TEST(RowRangeIndexTest, ContainsAndContainsExactlyBoundarySubRanges) { | |
| ASSERT_OK_AND_ASSIGN(auto index, RowRangeIndex::Create({Range(10, 20)})); | |
| ASSERT_TRUE(index.Contains(Range(10, 19))); | |
| ASSERT_FALSE(index.ContainsExactly(Range(10, 19))); | |
| ASSERT_TRUE(index.Contains(Range(11, 20))); | |
| ASSERT_FALSE(index.ContainsExactly(Range(11, 20))); | |
| } | |
| TEST(RowRangeIndexTest, ContainsAndContainsExactlyOutOfBoundaryRanges) { | |
| ASSERT_OK_AND_ASSIGN(auto index, RowRangeIndex::Create({Range(10, 20)})); | |
| ASSERT_FALSE(index.Contains(Range(9, 20))); | |
| ASSERT_FALSE(index.ContainsExactly(Range(9, 20))); | |
| ASSERT_FALSE(index.Contains(Range(10, 21))); | |
| ASSERT_FALSE(index.ContainsExactly(Range(10, 21))); | |
| } | |
| TEST(RowRangeIndexTest, ContainsAndContainsExactlyRangeAcrossTwoDisjointRanges) { | |
| ASSERT_OK_AND_ASSIGN(auto index, RowRangeIndex::Create({Range(0, 10), Range(11, 20)}, false)); | |
| ASSERT_FALSE(index.Contains(Range(10, 11))); | |
| ASSERT_FALSE(index.ContainsExactly(Range(10, 11))); | |
| ASSERT_FALSE(index.ContainsExactly(Range(0, 20))); | |
| } | |
| TEST(RowRangeIndexTest, ContainsAndContainsExactlyAdjacentMergeFlagDifference) { | |
| ASSERT_OK_AND_ASSIGN(auto merged_index, | |
| RowRangeIndex::Create({Range(0, 10), Range(11, 20)}, true)); | |
| ASSERT_OK_AND_ASSIGN(auto non_merged_index, | |
| RowRangeIndex::Create({Range(0, 10), Range(11, 20)}, false)); | |
| Range query(10, 11); | |
| ASSERT_TRUE(merged_index.Contains(query)); | |
| ASSERT_FALSE(merged_index.ContainsExactly(query)); | |
| ASSERT_FALSE(non_merged_index.Contains(query)); | |
| ASSERT_FALSE(non_merged_index.ContainsExactly(query)); | |
| } | |
| // ======================== merge_adjacent ======================== | |
| TEST(RowRangeIndexTest, CreateDoesNotMergeAdjacentRangesWhenDisabled) { | |
| ASSERT_OK_AND_ASSIGN(auto index, RowRangeIndex::Create({Range(0, 10), Range(11, 20)}, false)); | |
| std::vector<Range> expected = {Range(0, 10), Range(11, 20)}; | |
| ASSERT_EQ(index.Ranges(), expected); | |
| } | |
| // ======================== IntersectedRanges ======================== | |
| TEST(RowRangeIndexTest, IntersectedRangesExactMatch) { | |
| ASSERT_OK_AND_ASSIGN(auto index, RowRangeIndex::Create({Range(10, 20)})); | |
| auto intersected = index.IntersectedRanges(10, 20); | |
| std::vector<Range> expected = {Range(10, 20)}; | |
| ASSERT_EQ(intersected, expected); | |
| } | |
| TEST(RowRangeIndexTest, IntersectedRangesClippedFromLeft) { | |
| ASSERT_OK_AND_ASSIGN(auto index, RowRangeIndex::Create({Range(10, 20)})); | |
| auto intersected = index.IntersectedRanges(5, 15); | |
| std::vector<Range> expected = {Range(10, 15)}; | |
| ASSERT_EQ(intersected, expected); | |
| } | |
| TEST(RowRangeIndexTest, IntersectedRangesClippedFromRight) { | |
| ASSERT_OK_AND_ASSIGN(auto index, RowRangeIndex::Create({Range(10, 20)})); | |
| auto intersected = index.IntersectedRanges(15, 25); | |
| std::vector<Range> expected = {Range(15, 20)}; | |
| ASSERT_EQ(intersected, expected); | |
| } | |
| TEST(RowRangeIndexTest, IntersectedRangesClippedBothSides) { | |
| ASSERT_OK_AND_ASSIGN(auto index, RowRangeIndex::Create({Range(10, 20)})); | |
| auto intersected = index.IntersectedRanges(12, 18); | |
| std::vector<Range> expected = {Range(12, 18)}; | |
| ASSERT_EQ(intersected, expected); | |
| } | |
| TEST(RowRangeIndexTest, IntersectedRangesContainingRange) { | |
| ASSERT_OK_AND_ASSIGN(auto index, RowRangeIndex::Create({Range(10, 20)})); | |
| auto intersected = index.IntersectedRanges(0, 30); | |
| std::vector<Range> expected = {Range(10, 20)}; | |
| ASSERT_EQ(intersected, expected); | |
| } | |
| TEST(RowRangeIndexTest, IntersectedRangesNoOverlapBefore) { | |
| ASSERT_OK_AND_ASSIGN(auto index, RowRangeIndex::Create({Range(10, 20)})); | |
| auto intersected = index.IntersectedRanges(0, 9); | |
| ASSERT_TRUE(intersected.empty()); | |
| } | |
| TEST(RowRangeIndexTest, IntersectedRangesNoOverlapAfter) { | |
| ASSERT_OK_AND_ASSIGN(auto index, RowRangeIndex::Create({Range(10, 20)})); | |
| auto intersected = index.IntersectedRanges(21, 30); | |
| ASSERT_TRUE(intersected.empty()); | |
| } | |
| TEST(RowRangeIndexTest, IntersectedRangesTouchingLeftBoundary) { | |
| ASSERT_OK_AND_ASSIGN(auto index, RowRangeIndex::Create({Range(10, 20)})); | |
| auto intersected = index.IntersectedRanges(5, 10); | |
| std::vector<Range> expected = {Range(10, 10)}; | |
| ASSERT_EQ(intersected, expected); | |
| } | |
| TEST(RowRangeIndexTest, IntersectedRangesTouchingRightBoundary) { | |
| ASSERT_OK_AND_ASSIGN(auto index, RowRangeIndex::Create({Range(10, 20)})); | |
| auto intersected = index.IntersectedRanges(20, 25); | |
| std::vector<Range> expected = {Range(20, 20)}; | |
| ASSERT_EQ(intersected, expected); | |
| } | |
| TEST(RowRangeIndexTest, IntersectedRangesMultipleRangesHitsFirst) { | |
| ASSERT_OK_AND_ASSIGN(auto index, | |
| RowRangeIndex::Create({Range(0, 10), Range(20, 30), Range(40, 50)})); | |
| auto intersected = index.IntersectedRanges(3, 8); | |
| std::vector<Range> expected = {Range(3, 8)}; | |
| ASSERT_EQ(intersected, expected); | |
| } | |
| TEST(RowRangeIndexTest, IntersectedRangesMultipleRangesHitsLast) { | |
| ASSERT_OK_AND_ASSIGN(auto index, | |
| RowRangeIndex::Create({Range(0, 10), Range(20, 30), Range(40, 50)})); | |
| auto intersected = index.IntersectedRanges(42, 48); | |
| std::vector<Range> expected = {Range(42, 48)}; | |
| ASSERT_EQ(intersected, expected); | |
| } | |
| TEST(RowRangeIndexTest, IntersectedRangesSpansTwoRanges) { | |
| ASSERT_OK_AND_ASSIGN(auto index, RowRangeIndex::Create({Range(0, 10), Range(20, 30)})); | |
| auto intersected = index.IntersectedRanges(5, 25); | |
| std::vector<Range> expected = {Range(5, 10), Range(20, 25)}; | |
| ASSERT_EQ(intersected, expected); | |
| } | |
| TEST(RowRangeIndexTest, IntersectedRangesSpansThreeRangesMiddleFullyContained) { | |
| ASSERT_OK_AND_ASSIGN(auto index, | |
| RowRangeIndex::Create({Range(0, 10), Range(20, 30), Range(40, 50)})); | |
| auto intersected = index.IntersectedRanges(5, 45); | |
| std::vector<Range> expected = {Range(5, 10), Range(20, 30), Range(40, 45)}; | |
| ASSERT_EQ(intersected, expected); | |
| } | |
| TEST(RowRangeIndexTest, IntersectedRangesSpansAllRanges) { | |
| ASSERT_OK_AND_ASSIGN(auto index, | |
| RowRangeIndex::Create({Range(0, 10), Range(20, 30), Range(40, 50)})); | |
| auto intersected = index.IntersectedRanges(0, 50); | |
| std::vector<Range> expected = {Range(0, 10), Range(20, 30), Range(40, 50)}; | |
| ASSERT_EQ(intersected, expected); | |
| } | |
| TEST(RowRangeIndexTest, IntersectedRangesSpansAllRangesWider) { | |
| ASSERT_OK_AND_ASSIGN(auto index, | |
| RowRangeIndex::Create({Range(10, 20), Range(30, 40), Range(50, 60)})); | |
| auto intersected = index.IntersectedRanges(0, 100); | |
| std::vector<Range> expected = {Range(10, 20), Range(30, 40), Range(50, 60)}; | |
| ASSERT_EQ(intersected, expected); | |
| } | |
| TEST(RowRangeIndexTest, IntersectedRangesFallsInGap) { | |
| ASSERT_OK_AND_ASSIGN(auto index, RowRangeIndex::Create({Range(0, 10), Range(20, 30)})); | |
| auto intersected = index.IntersectedRanges(11, 19); | |
| ASSERT_TRUE(intersected.empty()); | |
| } | |
| TEST(RowRangeIndexTest, IntersectedRangesBeforeAll) { | |
| ASSERT_OK_AND_ASSIGN(auto index, RowRangeIndex::Create({Range(10, 20), Range(30, 40)})); | |
| auto intersected = index.IntersectedRanges(0, 5); | |
| ASSERT_TRUE(intersected.empty()); | |
| } | |
| TEST(RowRangeIndexTest, IntersectedRangesAfterAll) { | |
| ASSERT_OK_AND_ASSIGN(auto index, RowRangeIndex::Create({Range(10, 20), Range(30, 40)})); | |
| auto intersected = index.IntersectedRanges(50, 60); | |
| ASSERT_TRUE(intersected.empty()); | |
| } | |
| TEST(RowRangeIndexTest, IntersectedRangesSinglePointMatch) { | |
| ASSERT_OK_AND_ASSIGN(auto index, RowRangeIndex::Create({Range(10, 20)})); | |
| auto intersected = index.IntersectedRanges(15, 15); | |
| std::vector<Range> expected = {Range(15, 15)}; | |
| ASSERT_EQ(intersected, expected); | |
| } | |
| TEST(RowRangeIndexTest, IntersectedRangesSinglePointRangeMatch) { | |
| ASSERT_OK_AND_ASSIGN(auto index, RowRangeIndex::Create({Range(10, 10)})); | |
| auto intersected = index.IntersectedRanges(10, 10); | |
| std::vector<Range> expected = {Range(10, 10)}; | |
| ASSERT_EQ(intersected, expected); | |
| } | |
| TEST(RowRangeIndexTest, IntersectedRangesSinglePointRangeNoMatch) { | |
| ASSERT_OK_AND_ASSIGN(auto index, RowRangeIndex::Create({Range(10, 10)})); | |
| auto intersected = index.IntersectedRanges(11, 11); | |
| ASSERT_TRUE(intersected.empty()); | |
| } | |
| TEST(RowRangeIndexTest, IntersectedRangesLastRangeStartsBeyondEnd) { | |
| ASSERT_OK_AND_ASSIGN(auto index, RowRangeIndex::Create({Range(0, 10), Range(30, 40)})); | |
| auto intersected = index.IntersectedRanges(5, 25); | |
| std::vector<Range> expected = {Range(5, 10)}; | |
| ASSERT_EQ(intersected, expected); | |
| } | |
| TEST(RowRangeIndexTest, IntersectedRangesFourRangesClipBothEnds) { | |
| ASSERT_OK_AND_ASSIGN(auto index, RowRangeIndex::Create({Range(0, 10), Range(20, 30), | |
| Range(40, 50), Range(60, 70)})); | |
| auto intersected = index.IntersectedRanges(5, 65); | |
| std::vector<Range> expected = {Range(5, 10), Range(20, 30), Range(40, 50), Range(60, 65)}; | |
| ASSERT_EQ(intersected, expected); | |
| } | |
| TEST(RowRangeIndexTest, IntersectedRangesFiveRangesThreeMiddleFullyContained) { | |
| ASSERT_OK_AND_ASSIGN(auto index, | |
| RowRangeIndex::Create({Range(0, 10), Range(20, 30), Range(40, 50), | |
| Range(60, 70), Range(80, 90)})); | |
| auto intersected = index.IntersectedRanges(5, 85); | |
| std::vector<Range> expected = {Range(5, 10), Range(20, 30), Range(40, 50), Range(60, 70), | |
| Range(80, 85)}; | |
| ASSERT_EQ(intersected, expected); | |
| } | |
| } // namespace paimon::test |