| /* | |
| * 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/range.h" | |
| #include "gtest/gtest.h" | |
| namespace paimon::test { | |
| TEST(RangeTest, TestSimple) { | |
| Range range(/*from=*/0, /*to=*/5); | |
| ASSERT_EQ(range.Count(), 6); | |
| ASSERT_EQ(range.ToString(), "[0, 5]"); | |
| } | |
| TEST(RangeTest, TestHasIntersection) { | |
| { | |
| Range r1(10, 20); | |
| Range r2(15, 25); | |
| ASSERT_TRUE(Range::HasIntersection(r1, r2)); | |
| ASSERT_TRUE(Range::HasIntersection(r2, r1)); | |
| ASSERT_TRUE(Range::HasIntersection(r1, r1)); | |
| ASSERT_TRUE(Range::HasIntersection(r2, r2)); | |
| } | |
| { | |
| Range r1(10, 20); | |
| Range r2(21, 30); | |
| ASSERT_FALSE(Range::HasIntersection(r1, r2)); | |
| ASSERT_FALSE(Range::HasIntersection(r2, r1)); | |
| } | |
| { | |
| Range r1(10, 20); | |
| Range r2(20, 30); | |
| ASSERT_TRUE(Range::HasIntersection(r1, r2)); | |
| ASSERT_TRUE(Range::HasIntersection(r2, r1)); | |
| } | |
| { | |
| Range r1(10, 20); | |
| Range r2(12, 18); | |
| ASSERT_TRUE(Range::HasIntersection(r1, r2)); | |
| ASSERT_TRUE(Range::HasIntersection(r2, r1)); | |
| } | |
| } | |
| TEST(RangeTest, TestIntersection) { | |
| { | |
| Range r1(10, 20); | |
| Range r2(15, 25); | |
| ASSERT_EQ(Range::Intersection(r1, r2), Range(15, 20)); | |
| ASSERT_EQ(Range::Intersection(r2, r1), Range(15, 20)); | |
| ASSERT_EQ(Range::Intersection(r1, r1), r1); | |
| ASSERT_EQ(Range::Intersection(r2, r2), r2); | |
| } | |
| { | |
| Range r1(10, 20); | |
| Range r2(21, 30); | |
| ASSERT_FALSE(Range::Intersection(r1, r2)); | |
| ASSERT_FALSE(Range::Intersection(r2, r1)); | |
| } | |
| { | |
| Range r1(10, 20); | |
| Range r2(20, 30); | |
| ASSERT_EQ(Range::Intersection(r1, r2), Range(20, 20)); | |
| ASSERT_EQ(Range::Intersection(r2, r1), Range(20, 20)); | |
| } | |
| { | |
| Range r1(10, 20); | |
| Range r2(12, 18); | |
| ASSERT_EQ(Range::Intersection(r1, r2), r2); | |
| ASSERT_EQ(Range::Intersection(r2, r1), r2); | |
| } | |
| } | |
| TEST(RangeTest, TestCompare) { | |
| Range r1(10, 20); | |
| Range r2(15, 25); | |
| Range r3(10, 30); | |
| ASSERT_EQ(r1, r1); | |
| ASSERT_LT(r1, r2); | |
| ASSERT_LT(r1, r3); | |
| ASSERT_LT(r3, r2); | |
| } | |
| TEST(RangeTest, TestSortAndMergeOverlap) { | |
| { | |
| // test simple | |
| std::vector<Range> ranges = {Range(0, 10), Range(5, 15)}; | |
| auto result = Range::SortAndMergeOverlap(ranges, /*adjacent=*/false); | |
| std::vector<Range> expected = {Range(0, 15)}; | |
| ASSERT_EQ(result, expected); | |
| } | |
| { | |
| // test no overlap with adjacent = true | |
| std::vector<Range> ranges = {Range(0, 10), Range(11, 20)}; | |
| auto result = Range::SortAndMergeOverlap(ranges, /*adjacent=*/true); | |
| std::vector<Range> expected = {Range(0, 20)}; | |
| ASSERT_EQ(result, expected); | |
| } | |
| { | |
| // test no overlap with adjacent = false | |
| std::vector<Range> ranges = {Range(0, 10), Range(11, 20)}; | |
| auto result = Range::SortAndMergeOverlap(ranges, /*adjacent=*/false); | |
| std::vector<Range> expected = {Range(0, 10), Range(11, 20)}; | |
| ASSERT_EQ(result, expected); | |
| } | |
| { | |
| // test overlap multiple | |
| std::vector<Range> ranges = {Range(0, 10), Range(5, 15), Range(12, 20)}; | |
| auto result = Range::SortAndMergeOverlap(ranges, /*adjacent=*/false); | |
| std::vector<Range> expected = {Range(0, 20)}; | |
| ASSERT_EQ(result, expected); | |
| } | |
| { | |
| // test overlap mixed | |
| std::vector<Range> ranges = {Range(0, 10), Range(5, 15), Range(20, 30), Range(25, 35)}; | |
| auto result = Range::SortAndMergeOverlap(ranges, /*adjacent=*/false); | |
| std::vector<Range> expected = {Range(0, 15), Range(20, 35)}; | |
| ASSERT_EQ(result, expected); | |
| } | |
| { | |
| // test overlap unsorted | |
| std::vector<Range> ranges = {Range(20, 30), Range(0, 10), Range(5, 15)}; | |
| auto result = Range::SortAndMergeOverlap(ranges, /*adjacent=*/false); | |
| std::vector<Range> expected = {Range(0, 15), Range(20, 30)}; | |
| ASSERT_EQ(result, expected); | |
| } | |
| { | |
| // test overlap contained | |
| std::vector<Range> ranges = {Range(0, 20), Range(5, 10)}; | |
| auto result = Range::SortAndMergeOverlap(ranges, /*adjacent=*/false); | |
| std::vector<Range> expected = {Range(0, 20)}; | |
| ASSERT_EQ(result, expected); | |
| } | |
| { | |
| // test single | |
| std::vector<Range> ranges = {Range(0, 10)}; | |
| auto result = Range::SortAndMergeOverlap(ranges, /*adjacent=*/false); | |
| std::vector<Range> expected = {Range(0, 10)}; | |
| ASSERT_EQ(result, expected); | |
| } | |
| { | |
| // test identical | |
| std::vector<Range> ranges = {Range(0, 10), Range(0, 10)}; | |
| auto result = Range::SortAndMergeOverlap(ranges, /*adjacent=*/false); | |
| std::vector<Range> expected = {Range(0, 10)}; | |
| ASSERT_EQ(result, expected); | |
| } | |
| { | |
| // test overlap touching exactly | |
| std::vector<Range> ranges = {Range(0, 10), Range(10, 20)}; | |
| auto result = Range::SortAndMergeOverlap(ranges, /*adjacent=*/false); | |
| std::vector<Range> expected = {Range(0, 20)}; | |
| ASSERT_EQ(result, expected); | |
| } | |
| { | |
| // test overlap complex | |
| std::vector<Range> ranges = {Range(0, 5), Range(3, 8), Range(10, 15), | |
| Range(20, 25), Range(22, 28), Range(30, 35)}; | |
| auto result = Range::SortAndMergeOverlap(ranges, /*adjacent=*/false); | |
| std::vector<Range> expected = {Range(0, 8), Range(10, 15), Range(20, 28), Range(30, 35)}; | |
| ASSERT_EQ(result, expected); | |
| } | |
| } | |
| TEST(RangeTest, TestAnd) { | |
| { | |
| // test and basic | |
| std::vector<Range> left = {Range(0, 10), Range(20, 30)}; | |
| std::vector<Range> right = {Range(5, 15), Range(25, 35)}; | |
| auto result = Range::And(left, right); | |
| std::vector<Range> expected = {Range(5, 10), Range(25, 30)}; | |
| ASSERT_EQ(result, expected); | |
| } | |
| { | |
| // test no intersection | |
| std::vector<Range> left = {Range(0, 10)}; | |
| std::vector<Range> right = {Range(20, 30)}; | |
| auto result = Range::And(left, right); | |
| ASSERT_TRUE(result.empty()); | |
| } | |
| { | |
| // test and same ranges | |
| std::vector<Range> left = {Range(0, 10)}; | |
| std::vector<Range> right = {Range(0, 10)}; | |
| auto result = Range::And(left, right); | |
| std::vector<Range> expected = {Range(0, 10)}; | |
| ASSERT_EQ(result, expected); | |
| } | |
| { | |
| // test and partial overlap | |
| std::vector<Range> left = {Range(0, 10)}; | |
| std::vector<Range> right = {Range(5, 15)}; | |
| auto result = Range::And(left, right); | |
| std::vector<Range> expected = {Range(5, 10)}; | |
| ASSERT_EQ(result, expected); | |
| } | |
| { | |
| // test and contained | |
| std::vector<Range> left = {Range(0, 20)}; | |
| std::vector<Range> right = {Range(5, 10)}; | |
| auto result = Range::And(left, right); | |
| std::vector<Range> expected = {Range(5, 10)}; | |
| ASSERT_EQ(result, expected); | |
| } | |
| { | |
| // test and multiple ranges | |
| std::vector<Range> left = {Range(0, 10), Range(20, 30), Range(40, 50)}; | |
| std::vector<Range> right = {Range(5, 25), Range(35, 45)}; | |
| auto result = Range::And(left, right); | |
| std::vector<Range> expected = {Range(5, 10), Range(20, 25), Range(40, 45)}; | |
| ASSERT_EQ(result, expected); | |
| } | |
| { | |
| // test and empty left | |
| std::vector<Range> left = {}; | |
| std::vector<Range> right = {Range(0, 10)}; | |
| auto result = Range::And(left, right); | |
| ASSERT_TRUE(result.empty()); | |
| } | |
| { | |
| // test and empty right | |
| std::vector<Range> left = {Range(0, 10)}; | |
| std::vector<Range> right = {}; | |
| auto result = Range::And(left, right); | |
| ASSERT_TRUE(result.empty()); | |
| } | |
| { | |
| // test and touching at boundary | |
| std::vector<Range> left = {Range(0, 10)}; | |
| std::vector<Range> right = {Range(10, 20)}; | |
| auto result = Range::And(left, right); | |
| std::vector<Range> expected = {Range(10, 10)}; | |
| ASSERT_EQ(result, expected); | |
| } | |
| { | |
| // test and complex | |
| std::vector<Range> left = {Range(0, 5), Range(10, 15), Range(20, 25), Range(30, 35)}; | |
| std::vector<Range> right = {Range(3, 12), Range(18, 28), Range(32, 40)}; | |
| auto result = Range::And(left, right); | |
| std::vector<Range> expected = {Range(3, 5), Range(10, 12), Range(20, 25), Range(32, 35)}; | |
| ASSERT_EQ(result, expected); | |
| } | |
| } | |
| TEST(RangeTest, TestExclude) { | |
| { | |
| // test basic | |
| // [0, 10000] exclude [1000,2000],[3000,4000],[5000,6000] | |
| // Expected: [0, 999],[2001,2999],[4001,4999],[6001, 10000] | |
| Range range(0, 10000); | |
| std::vector<Range> excludes = {Range(1000, 2000), Range(3000, 4000), Range(5000, 6000)}; | |
| auto result = range.Exclude(excludes); | |
| std::vector<Range> expected = {Range(0, 999), Range(2001, 2999), Range(4001, 4999), | |
| Range(6001, 10000)}; | |
| ASSERT_EQ(result, expected); | |
| } | |
| { | |
| // Same as basic but with unsorted exclusions | |
| Range range(0, 10000); | |
| std::vector<Range> excludes = {Range(5000, 6000), Range(1000, 2000), Range(3000, 4000)}; | |
| auto result = range.Exclude(excludes); | |
| std::vector<Range> expected = {Range(0, 999), Range(2001, 2999), Range(4001, 4999), | |
| Range(6001, 10000)}; | |
| ASSERT_EQ(result, expected); | |
| } | |
| { | |
| // exclude empty exclusions | |
| Range range(100, 200); | |
| std::vector<Range> excludes = {}; | |
| auto result = range.Exclude(excludes); | |
| std::vector<Range> expected = {Range(100, 200)}; | |
| ASSERT_EQ(result, expected); | |
| } | |
| { | |
| // exclude no intersection | |
| Range range(100, 200); | |
| std::vector<Range> excludes = {Range(300, 400), Range(500, 600)}; | |
| auto result = range.Exclude(excludes); | |
| std::vector<Range> expected = {Range(100, 200)}; | |
| ASSERT_EQ(result, expected); | |
| } | |
| { | |
| // exclude at start | |
| Range range(0, 100); | |
| std::vector<Range> excludes = {Range(0, 10)}; | |
| auto result = range.Exclude(excludes); | |
| std::vector<Range> expected = {Range(11, 100)}; | |
| ASSERT_EQ(result, expected); | |
| } | |
| { | |
| // exclude at end | |
| Range range(0, 100); | |
| std::vector<Range> excludes = {Range(90, 100)}; | |
| auto result = range.Exclude(excludes); | |
| std::vector<Range> expected = {Range(0, 89)}; | |
| ASSERT_EQ(result, expected); | |
| } | |
| { | |
| // exclusion extends past the end of the range | |
| Range range(100, 200); | |
| std::vector<Range> excludes = {Range(150, 300)}; | |
| auto result = range.Exclude(excludes); | |
| std::vector<Range> expected = {Range(100, 149)}; | |
| ASSERT_EQ(result, expected); | |
| } | |
| { | |
| // exclusion starts before the range | |
| Range range(100, 200); | |
| std::vector<Range> excludes = {Range(50, 150)}; | |
| auto result = range.Exclude(excludes); | |
| std::vector<Range> expected = {Range(151, 200)}; | |
| ASSERT_EQ(result, expected); | |
| } | |
| { | |
| // overlapping exclusion ranges | |
| Range range(0, 100); | |
| std::vector<Range> excludes = {Range(20, 50), Range(40, 70)}; | |
| auto result = range.Exclude(excludes); | |
| std::vector<Range> expected = {Range(0, 19), Range(71, 100)}; | |
| ASSERT_EQ(result, expected); | |
| } | |
| { | |
| // exclusion completely covers the range | |
| Range range(50, 60); | |
| std::vector<Range> excludes = {Range(0, 100)}; | |
| auto result = range.Exclude(excludes); | |
| ASSERT_TRUE(result.empty()); | |
| } | |
| { | |
| // exclusion completely matches the range | |
| Range range(50, 60); | |
| std::vector<Range> excludes = {Range(50, 60)}; | |
| auto result = range.Exclude(excludes); | |
| ASSERT_TRUE(result.empty()); | |
| } | |
| { | |
| // single exclusion in the middle | |
| Range range(0, 100); | |
| std::vector<Range> excludes = {Range(40, 60)}; | |
| auto result = range.Exclude(excludes); | |
| std::vector<Range> expected = {Range(0, 39), Range(61, 100)}; | |
| ASSERT_EQ(result, expected); | |
| } | |
| { | |
| // adjacent exclusion ranges | |
| Range range(0, 100); | |
| std::vector<Range> excludes = {Range(20, 30), Range(31, 40)}; | |
| auto result = range.Exclude(excludes); | |
| std::vector<Range> expected = {Range(0, 19), Range(41, 100)}; | |
| ASSERT_EQ(result, expected); | |
| } | |
| { | |
| // range is a single point | |
| Range range(50, 50); | |
| std::vector<Range> excludes = {Range(50, 50)}; | |
| auto result = range.Exclude(excludes); | |
| ASSERT_TRUE(result.empty()); | |
| } | |
| { | |
| // single point exclusion | |
| Range range(0, 100); | |
| std::vector<Range> excludes = {Range(50, 50)}; | |
| auto result = range.Exclude(excludes); | |
| std::vector<Range> expected = {Range(0, 49), Range(51, 100)}; | |
| ASSERT_EQ(result, expected); | |
| } | |
| } | |
| } // namespace paimon::test |