| /* |
| * 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 |