| // Copyright 2017-2020 The Verible Authors. | |
| // | |
| // Licensed 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 "common/util/interval_set.h" | |
| #include <initializer_list> | |
| #include <sstream> | |
| #include "gmock/gmock.h" | |
| #include "gtest/gtest.h" | |
| namespace verible { | |
| namespace { | |
| using ::testing::ElementsAre; | |
| using interval_type = Interval<int>; | |
| using interval_set_type = IntervalSet<int>; | |
| // For constructing golden test values, without relying on ::Add(). | |
| class UnsafeIntervalSet : public interval_set_type { | |
| public: | |
| // intervals must be non-overlapping, but can be any order. | |
| UnsafeIntervalSet(std::initializer_list<interval_type> intervals) { | |
| for (const auto& interval : intervals) { | |
| AddUnsafe(interval); | |
| } | |
| // Ensure class invariants. | |
| this->CheckIntegrity(); | |
| } | |
| }; | |
| // UnsafeIntervalTests excercise failure of IntervalSet::CheckIntegrity. | |
| TEST(UnsafeIntervalTest, NullInterval) { | |
| EXPECT_DEATH((UnsafeIntervalSet{{3, 3}}), ""); | |
| } | |
| TEST(UnsafeIntervalTest, NullIntervalSecond) { | |
| EXPECT_DEATH((UnsafeIntervalSet{{0, 1}, {3, 3}}), ""); | |
| } | |
| TEST(UnsafeIntervalTest, OverlappingInputs) { | |
| EXPECT_DEATH((UnsafeIntervalSet{{0, 3}, {1, 2}}), ""); | |
| } | |
| TEST(UnsafeIntervalTest, BackwardsInterval) { | |
| EXPECT_DEATH((UnsafeIntervalSet{{3, 2}}), ""); | |
| } | |
| TEST(UnsafeIntervalTest, BackwardsIntervalSecond) { | |
| EXPECT_DEATH((UnsafeIntervalSet{{0, 1}, {3, 2}}), ""); | |
| } | |
| TEST(UnsafeIntervalTest, AbuttingInputs) { | |
| EXPECT_DEATH((UnsafeIntervalSet{{0, 3}, {3, 5}}), ""); | |
| } | |
| TEST(IntervalSetTest, DefaultConstruction) { | |
| const interval_set_type iset; | |
| EXPECT_TRUE(iset.empty()); | |
| EXPECT_EQ(iset.size(), 0); | |
| EXPECT_FALSE(iset.Contains(0)); | |
| EXPECT_FALSE(iset.Contains({0, 0})); | |
| EXPECT_FALSE(iset.Contains({0, 1})); | |
| } | |
| TEST(IntervalSetTest, EqualityBothEmpty) { | |
| const interval_set_type iset1, iset2; | |
| EXPECT_EQ(iset1, iset2); | |
| EXPECT_EQ(iset2, iset1); | |
| } | |
| TEST(IntervalSetTest, EqualityOneEmpty) { | |
| const interval_set_type iset1; | |
| const interval_set_type iset2{{4, 5}}; | |
| EXPECT_NE(iset1, iset2); | |
| EXPECT_NE(iset2, iset1); | |
| } | |
| TEST(IntervalSetTest, EqualitySame) { | |
| const interval_set_type iset1{{4, 5}}; | |
| const interval_set_type iset2{{4, 5}}; | |
| EXPECT_EQ(iset1, iset2); | |
| EXPECT_EQ(iset2, iset1); | |
| } | |
| TEST(IntervalSetTest, EqualityDifferentNonOverlap) { | |
| const interval_set_type iset1{{4, 5}}; | |
| const interval_set_type iset2{{3, 4}}; | |
| EXPECT_NE(iset1, iset2); | |
| EXPECT_NE(iset2, iset1); | |
| } | |
| TEST(IntervalSetTest, EqualityDifferentAsymmetricOverlapLeft) { | |
| const interval_set_type iset1{{4, 5}}; | |
| const interval_set_type iset2{{3, 5}}; | |
| EXPECT_NE(iset1, iset2); | |
| EXPECT_NE(iset2, iset1); | |
| } | |
| TEST(IntervalSetTest, EqualityDifferentAsymmetricOverlapRight) { | |
| const interval_set_type iset1{{4, 5}}; | |
| const interval_set_type iset2{{4, 6}}; | |
| EXPECT_NE(iset1, iset2); | |
| EXPECT_NE(iset2, iset1); | |
| } | |
| typedef std::map<int, int>::value_type pair_t; | |
| TEST(IntervalSetTest, ConstructionWithInitializerOneInterval) { | |
| const interval_set_type iset{{2, 4}}; | |
| EXPECT_FALSE(iset.empty()); | |
| EXPECT_EQ(iset.size(), 1); | |
| EXPECT_EQ(iset, iset); | |
| EXPECT_THAT(iset, ElementsAre(pair_t{2, 4})); | |
| EXPECT_FALSE(iset.Contains(0)); | |
| EXPECT_FALSE(iset.Contains(1)); | |
| EXPECT_TRUE(iset.Contains(2)); | |
| EXPECT_TRUE(iset.Contains(3)); | |
| EXPECT_FALSE(iset.Contains(4)); | |
| EXPECT_FALSE(iset.Contains({0, 1})); | |
| EXPECT_FALSE(iset.Contains({1, 2})); | |
| EXPECT_TRUE(iset.Contains({2, 3})); | |
| EXPECT_TRUE(iset.Contains({3, 4})); | |
| EXPECT_FALSE(iset.Contains({4, 5})); | |
| EXPECT_FALSE(iset.Contains({0, 2})); | |
| EXPECT_FALSE(iset.Contains({1, 3})); | |
| EXPECT_TRUE(iset.Contains({2, 4})); | |
| EXPECT_FALSE(iset.Contains({3, 5})); | |
| EXPECT_FALSE(iset.Contains({0, 3})); | |
| EXPECT_FALSE(iset.Contains({1, 4})); | |
| EXPECT_FALSE(iset.Contains({2, 5})); | |
| } | |
| // Reminder: constructor tests are actually testing Add(interval). | |
| TEST(IntervalSetTest, ConstructionWithInitializerDisjoint) { | |
| const interval_set_type iset{{2, 4}, {5, 7}}; | |
| EXPECT_EQ(iset, iset); | |
| EXPECT_THAT(iset, ElementsAre(pair_t{2, 4}, pair_t{5, 7})); | |
| } | |
| TEST(IntervalSetTest, ConstructionWithInitializerDisjointReverse) { | |
| const interval_set_type iset{{5, 7}, {2, 4}}; | |
| EXPECT_EQ(iset, iset); | |
| EXPECT_THAT(iset, ElementsAre(pair_t{2, 4}, pair_t{5, 7})); | |
| } | |
| TEST(IntervalSetTest, ConstructionWithInitializerRedundantIdentical) { | |
| const interval_set_type iset{{3, 7}, {3, 7}}; | |
| EXPECT_EQ(iset, iset); | |
| EXPECT_THAT(iset, ElementsAre(pair_t{3, 7})); | |
| } | |
| TEST(IntervalSetTest, ConstructionWithInitializerAbutting) { | |
| const interval_set_type iset{{3, 5}, {5, 7}}; | |
| EXPECT_EQ(iset, iset); | |
| EXPECT_THAT(iset, ElementsAre(pair_t{3, 7})); | |
| } | |
| TEST(IntervalSetTest, ConstructionWithInitializerAbuttingReverse) { | |
| const interval_set_type iset{{5, 7}, {3, 5}}; | |
| EXPECT_EQ(iset, iset); | |
| EXPECT_THAT(iset, ElementsAre(pair_t{3, 7})); | |
| } | |
| TEST(IntervalSetTest, ConstructionWithInitializerEngulfed) { | |
| const interval_set_type iset{{3, 7}, {4, 6}}; | |
| EXPECT_EQ(iset, iset); | |
| EXPECT_THAT(iset, ElementsAre(pair_t{3, 7})); | |
| } | |
| TEST(IntervalSetTest, ConstructionWithInitializerEngulfedReverse) { | |
| const interval_set_type iset{{4, 6}, {3, 7}}; | |
| EXPECT_EQ(iset, iset); | |
| EXPECT_THAT(iset, ElementsAre(pair_t{3, 7})); | |
| } | |
| TEST(IntervalSetTest, ConstructionWithInitializerSameMin) { | |
| const interval_set_type iset{{3, 6}, {3, 7}}; | |
| EXPECT_EQ(iset, iset); | |
| EXPECT_THAT(iset, ElementsAre(pair_t{3, 7})); | |
| } | |
| TEST(IntervalSetTest, ConstructionWithInitializerSameMinReverse) { | |
| const interval_set_type iset{{3, 7}, {3, 6}}; | |
| EXPECT_EQ(iset, iset); | |
| EXPECT_THAT(iset, ElementsAre(pair_t{3, 7})); | |
| } | |
| TEST(IntervalSetTest, ConstructionWithInitializerSameMax) { | |
| const interval_set_type iset{{3, 7}, {4, 7}}; | |
| EXPECT_EQ(iset, iset); | |
| EXPECT_THAT(iset, ElementsAre(pair_t{3, 7})); | |
| } | |
| TEST(IntervalSetTest, ConstructionWithInitializerSameMaxReverse) { | |
| const interval_set_type iset{{4, 8}, {3, 8}}; | |
| EXPECT_EQ(iset, iset); | |
| EXPECT_THAT(iset, ElementsAre(pair_t{3, 8})); | |
| } | |
| TEST(IntervalSetTest, Swap) { | |
| UnsafeIntervalSet iset1{{3, 8}}; | |
| UnsafeIntervalSet iset2{{2, 5}, {10, 11}}; | |
| EXPECT_NE(iset1, iset2); | |
| EXPECT_NE(iset2, iset1); | |
| swap(iset1, iset2); | |
| EXPECT_THAT(iset2, ElementsAre(pair_t{3, 8})); | |
| EXPECT_THAT(iset1, ElementsAre(pair_t{2, 5}, pair_t{10, 11})); | |
| } | |
| TEST(IntervalSetTest, Assign) { | |
| UnsafeIntervalSet iset1{{3, 8}}; | |
| UnsafeIntervalSet iset2{{2, 5}, {10, 11}}; | |
| iset1 = iset2; | |
| EXPECT_EQ(iset1, iset2); | |
| EXPECT_EQ(iset2, iset1); | |
| EXPECT_THAT(iset1, ElementsAre(pair_t{2, 5}, pair_t{10, 11})); | |
| EXPECT_THAT(iset2, ElementsAre(pair_t{2, 5}, pair_t{10, 11})); | |
| } | |
| TEST(IntervalSetTest, CopyConstruct) { | |
| UnsafeIntervalSet iset{{2, 5}, {10, 11}}; | |
| const interval_set_type copy(iset); | |
| EXPECT_THAT(iset, ElementsAre(pair_t{2, 5}, pair_t{10, 11})); | |
| EXPECT_THAT(copy, ElementsAre(pair_t{2, 5}, pair_t{10, 11})); | |
| } | |
| TEST(IntervalSetTest, CopyAssign) { | |
| UnsafeIntervalSet iset{{2, 5}, {10, 11}}; | |
| const interval_set_type copy = iset; | |
| EXPECT_THAT(iset, ElementsAre(pair_t{2, 5}, pair_t{10, 11})); | |
| EXPECT_THAT(copy, ElementsAre(pair_t{2, 5}, pair_t{10, 11})); | |
| } | |
| TEST(IntervalSetTest, MoveConstruct) { | |
| interval_set_type iset{{2, 5}, {10, 11}}; | |
| const interval_set_type copy(std::move(iset)); | |
| EXPECT_THAT(copy, ElementsAre(pair_t{2, 5}, pair_t{10, 11})); | |
| } | |
| TEST(IntervalSetTest, MoveAssign) { | |
| interval_set_type iset{{2, 5}, {10, 11}}; | |
| interval_set_type copy; | |
| copy = std::move(iset); | |
| EXPECT_THAT(copy, ElementsAre(pair_t{2, 5}, pair_t{10, 11})); | |
| } | |
| TEST(IntervalSetTest, ClearEmpty) { | |
| interval_set_type iset; | |
| EXPECT_TRUE(iset.empty()); | |
| iset.clear(); | |
| EXPECT_TRUE(iset.empty()); | |
| } | |
| TEST(IntervalSetTest, ClearNonEmpty) { | |
| interval_set_type iset{{4, 5}, {6, 7}}; | |
| EXPECT_FALSE(iset.empty()); | |
| iset.clear(); | |
| EXPECT_TRUE(iset.empty()); | |
| } | |
| TEST(IntervalSetTest, LowerBound) { | |
| const UnsafeIntervalSet iset{{3, 5}, {7, 9}}; | |
| const auto front_iter = iset.begin(); | |
| const auto back_iter = std::next(front_iter); | |
| const auto end = iset.end(); | |
| EXPECT_EQ(iset.LowerBound(2), front_iter); | |
| EXPECT_EQ(iset.LowerBound(3), front_iter); | |
| EXPECT_EQ(iset.LowerBound(4), front_iter); | |
| EXPECT_EQ(iset.LowerBound(5), back_iter); | |
| EXPECT_EQ(iset.LowerBound(6), back_iter); | |
| EXPECT_EQ(iset.LowerBound(7), back_iter); | |
| EXPECT_EQ(iset.LowerBound(8), back_iter); | |
| EXPECT_EQ(iset.LowerBound(9), end); | |
| EXPECT_EQ(iset.LowerBound(10), end); | |
| } | |
| TEST(IntervalSetTest, UpperBound) { | |
| const UnsafeIntervalSet iset{{3, 5}, {7, 9}}; | |
| const auto front_iter = iset.begin(); | |
| const auto back_iter = std::next(front_iter); | |
| const auto end = iset.end(); | |
| EXPECT_EQ(iset.UpperBound(2), front_iter); | |
| EXPECT_EQ(iset.UpperBound(3), back_iter); | |
| EXPECT_EQ(iset.UpperBound(4), back_iter); | |
| EXPECT_EQ(iset.UpperBound(5), back_iter); | |
| EXPECT_EQ(iset.UpperBound(6), back_iter); | |
| EXPECT_EQ(iset.UpperBound(7), end); | |
| EXPECT_EQ(iset.UpperBound(8), end); | |
| EXPECT_EQ(iset.UpperBound(9), end); | |
| EXPECT_EQ(iset.UpperBound(10), end); | |
| } | |
| TEST(IntervalSetTest, FindValue) { | |
| const UnsafeIntervalSet iset{{3, 5}, {7, 9}}; | |
| const auto front_iter = iset.begin(); | |
| const auto back_iter = std::next(front_iter); | |
| const auto end = iset.end(); | |
| EXPECT_EQ(iset.Find(2), end); | |
| EXPECT_EQ(iset.Find(3), front_iter); | |
| EXPECT_EQ(iset.Find(4), front_iter); | |
| EXPECT_EQ(iset.Find(5), end); | |
| EXPECT_EQ(iset.Find(6), end); | |
| EXPECT_EQ(iset.Find(7), back_iter); | |
| EXPECT_EQ(iset.Find(8), back_iter); | |
| EXPECT_EQ(iset.Find(9), end); | |
| EXPECT_EQ(iset.Find(10), end); | |
| } | |
| TEST(IntervalSetTest, FindInterval) { | |
| const UnsafeIntervalSet iset{{3, 5}, {7, 9}}; | |
| const auto front_iter = iset.begin(); | |
| const auto back_iter = std::next(front_iter); | |
| const auto end = iset.end(); | |
| // empty intervals | |
| for (int i = 2; i < 10; ++i) { | |
| EXPECT_EQ(iset.Find({i, i}), end); | |
| } | |
| // end points outside of the set's span | |
| for (int i = 2; i < 10; ++i) { | |
| EXPECT_EQ(iset.Find({2, i}), end); | |
| EXPECT_EQ(iset.Find({i, 10}), end); | |
| } | |
| for (int i = 5; i < 10; ++i) { | |
| EXPECT_EQ(iset.Find({5, i}), end); | |
| } | |
| for (int i = 6; i < 10; ++i) { | |
| EXPECT_EQ(iset.Find({6, i}), end); | |
| } | |
| for (int i = 2; i < 6; ++i) { | |
| EXPECT_EQ(iset.Find({i, 6}), end); | |
| } | |
| for (int i = 2; i < 7; ++i) { | |
| EXPECT_EQ(iset.Find({i, 7}), end); | |
| } | |
| EXPECT_EQ(iset.Find({3, 4}), front_iter); | |
| EXPECT_EQ(iset.Find({4, 5}), front_iter); | |
| EXPECT_EQ(iset.Find({3, 5}), front_iter); | |
| EXPECT_EQ(iset.Find({7, 8}), back_iter); | |
| EXPECT_EQ(iset.Find({8, 9}), back_iter); | |
| EXPECT_EQ(iset.Find({7, 9}), back_iter); | |
| // interval spans the [5,7) gap | |
| for (int i = 2; i < 7; ++i) { | |
| for (int j = 6; j < 10; ++j) { | |
| if (i <= j) { | |
| EXPECT_EQ(iset.Find({i, j}), end) << "{i,j}=" << i << ',' << j; | |
| } | |
| } | |
| } | |
| } | |
| TEST(IntervalSetTest, FindInvalid) { | |
| const UnsafeIntervalSet iset{}; | |
| EXPECT_DEATH((iset.Find({2, 1})), ""); | |
| } | |
| struct AddSingleValueTestData { | |
| int value; | |
| UnsafeIntervalSet expected; | |
| }; | |
| TEST(IntervalSetTest, AddSingleValue) { | |
| const UnsafeIntervalSet init{{10, 20}, {30, 40}}; | |
| const AddSingleValueTestData kTestCases[] = { | |
| {5, {{5, 6}, {10, 20}, {30, 40}}}, | |
| {9, {{9, 20}, {30, 40}}}, | |
| {10, {{10, 20}, {30, 40}}}, | |
| {19, {{10, 20}, {30, 40}}}, | |
| {20, {{10, 21}, {30, 40}}}, | |
| {22, {{10, 20}, {22, 23}, {30, 40}}}, | |
| {28, {{10, 20}, {28, 29}, {30, 40}}}, | |
| {29, {{10, 20}, {29, 40}}}, | |
| {30, {{10, 20}, {30, 40}}}, | |
| {39, {{10, 20}, {30, 40}}}, | |
| {40, {{10, 20}, {30, 41}}}, | |
| {41, {{10, 20}, {30, 40}, {41, 42}}}, | |
| }; | |
| for (const auto& test : kTestCases) { | |
| UnsafeIntervalSet copy(init); | |
| copy.Add(test.value); | |
| EXPECT_EQ(copy, test.expected); | |
| } | |
| } | |
| struct AddIntervalTestData { | |
| interval_type value; | |
| UnsafeIntervalSet expected; | |
| }; | |
| TEST(IntervalSetTest, AddEmptyIntervalToEmptySet) { | |
| UnsafeIntervalSet init{}; | |
| for (int i = 5; i < 45; ++i) { | |
| init.Add({i, i}); | |
| EXPECT_TRUE(init.empty()); | |
| } | |
| } | |
| TEST(IntervalSetTest, AddEmptyIntervalToNonEmptySet) { | |
| const UnsafeIntervalSet init{{10, 20}, {30, 40}}; | |
| UnsafeIntervalSet copy(init); | |
| for (int i = 5; i < 45; ++i) { | |
| copy.Add({i, i}); | |
| EXPECT_EQ(copy, init); | |
| } | |
| } | |
| TEST(IntervalSetTest, AddIntervalNonEmpty) { | |
| const UnsafeIntervalSet init{{10, 20}, {30, 40}}; | |
| const AddIntervalTestData kTestCases[] = { | |
| {{5, 9}, {{5, 9}, {10, 20}, {30, 40}}}, | |
| {{5, 10}, {{5, 20}, {30, 40}}}, | |
| {{5, 20}, {{5, 20}, {30, 40}}}, | |
| {{5, 21}, {{5, 21}, {30, 40}}}, | |
| {{5, 29}, {{5, 29}, {30, 40}}}, | |
| {{5, 30}, {{5, 40}}}, | |
| {{5, 40}, {{5, 40}}}, | |
| {{5, 41}, {{5, 41}}}, | |
| {{10, 19}, {{10, 20}, {30, 40}}}, | |
| {{10, 20}, {{10, 20}, {30, 40}}}, | |
| {{10, 21}, {{10, 21}, {30, 40}}}, | |
| {{10, 29}, {{10, 29}, {30, 40}}}, | |
| {{10, 30}, {{10, 40}}}, | |
| {{10, 40}, {{10, 40}}}, | |
| {{10, 41}, {{10, 41}}}, | |
| {{20, 21}, {{10, 21}, {30, 40}}}, | |
| {{20, 29}, {{10, 29}, {30, 40}}}, | |
| {{20, 30}, {{10, 40}}}, // seals the gap, abutting both ends | |
| {{20, 40}, {{10, 40}}}, | |
| {{20, 41}, {{10, 41}}}, | |
| {{21, 29}, {{10, 20}, {21, 29}, {30, 40}}}, | |
| {{21, 30}, {{10, 20}, {21, 40}}}, | |
| {{21, 40}, {{10, 20}, {21, 40}}}, | |
| {{21, 41}, {{10, 20}, {21, 41}}}, | |
| {{29, 30}, {{10, 20}, {29, 40}}}, | |
| {{29, 40}, {{10, 20}, {29, 40}}}, | |
| {{29, 41}, {{10, 20}, {29, 41}}}, | |
| {{30, 40}, {{10, 20}, {30, 40}}}, | |
| {{30, 41}, {{10, 20}, {30, 41}}}, | |
| {{40, 41}, {{10, 20}, {30, 41}}}, | |
| {{41, 42}, {{10, 20}, {30, 40}, {41, 42}}}, | |
| }; | |
| for (const auto& test : kTestCases) { | |
| UnsafeIntervalSet copy(init); | |
| copy.Add(test.value); | |
| EXPECT_EQ(copy, test.expected); | |
| } | |
| } | |
| TEST(IntervalSetTest, AddInvalidInterval) { | |
| UnsafeIntervalSet iset{}; | |
| EXPECT_DEATH((iset.Add({2, 1})), ""); | |
| } | |
| typedef AddIntervalTestData DifferenceIntervalTestData; | |
| TEST(IntervalSetTest, DifferenceInvalidInterval) { | |
| UnsafeIntervalSet iset{}; | |
| EXPECT_DEATH((iset.Difference({2, 1})), ""); | |
| } | |
| TEST(IntervalSetTest, DifferenceEmptyIntervalFromEmptySet) { | |
| UnsafeIntervalSet init{}; | |
| for (int i = 5; i < 45; ++i) { | |
| init.Difference({i, i}); | |
| EXPECT_TRUE(init.empty()); | |
| } | |
| } | |
| TEST(IntervalSetTest, DifferenceEmptyIntervalFromNonEmptySet) { | |
| const UnsafeIntervalSet init{{10, 20}, {30, 40}}; | |
| UnsafeIntervalSet copy(init); | |
| for (int i = 5; i < 45; ++i) { | |
| copy.Difference({i, i}); | |
| EXPECT_EQ(copy, init); | |
| } | |
| } | |
| typedef AddSingleValueTestData DifferenceSingleValueTestData; | |
| TEST(IntervalSetTest, DifferenceSingleValue) { | |
| const UnsafeIntervalSet init{{10, 20}, {30, 40}}; | |
| const DifferenceSingleValueTestData kTestCases[] = { | |
| {9, {{10, 20}, {30, 40}}}, | |
| {10, {{11, 20}, {30, 40}}}, | |
| {11, {{10, 11}, {12, 20}, {30, 40}}}, | |
| {18, {{10, 18}, {19, 20}, {30, 40}}}, | |
| {19, {{10, 19}, {30, 40}}}, | |
| {20, {{10, 20}, {30, 40}}}, | |
| {21, {{10, 20}, {30, 40}}}, | |
| {29, {{10, 20}, {30, 40}}}, | |
| {30, {{10, 20}, {31, 40}}}, | |
| {31, {{10, 20}, {30, 31}, {32, 40}}}, | |
| {38, {{10, 20}, {30, 38}, {39, 40}}}, | |
| {39, {{10, 20}, {30, 39}}}, | |
| {40, {{10, 20}, {30, 40}}}, | |
| {41, {{10, 20}, {30, 40}}}, | |
| }; | |
| for (const auto& test : kTestCases) { | |
| VLOG(1) << "remove: " << test.value << " expect: " << test.expected; | |
| UnsafeIntervalSet copy(init); | |
| copy.Difference(test.value); | |
| EXPECT_EQ(copy, test.expected); | |
| } | |
| } | |
| TEST(IntervalSetTest, DifferenceIntervalNonEmpty) { | |
| const UnsafeIntervalSet init{{10, 20}, {30, 40}}; | |
| const DifferenceIntervalTestData kTestCases[] = { | |
| {{5, 9}, {{10, 20}, {30, 40}}}, | |
| {{5, 10}, {{10, 20}, {30, 40}}}, | |
| {{5, 11}, {{11, 20}, {30, 40}}}, | |
| {{5, 19}, {{19, 20}, {30, 40}}}, | |
| {{5, 20}, {{30, 40}}}, | |
| {{5, 21}, {{30, 40}}}, | |
| {{5, 29}, {{30, 40}}}, | |
| {{5, 30}, {{30, 40}}}, | |
| {{5, 31}, {{31, 40}}}, | |
| {{5, 39}, {{39, 40}}}, | |
| {{5, 40}, {}}, | |
| {{5, 41}, {}}, | |
| {{10, 10}, {{10, 20}, {30, 40}}}, // ok to remove empty interval | |
| {{10, 11}, {{11, 20}, {30, 40}}}, | |
| {{10, 19}, {{19, 20}, {30, 40}}}, | |
| {{10, 20}, {{30, 40}}}, | |
| {{10, 21}, {{30, 40}}}, | |
| {{10, 29}, {{30, 40}}}, | |
| {{10, 30}, {{30, 40}}}, | |
| {{10, 31}, {{31, 40}}}, | |
| {{10, 39}, {{39, 40}}}, | |
| {{10, 40}, {}}, | |
| {{10, 41}, {}}, | |
| {{11, 11}, {{10, 20}, {30, 40}}}, | |
| {{11, 19}, {{10, 11}, {19, 20}, {30, 40}}}, | |
| {{11, 20}, {{10, 11}, {30, 40}}}, | |
| {{11, 21}, {{10, 11}, {30, 40}}}, | |
| {{11, 29}, {{10, 11}, {30, 40}}}, | |
| {{11, 30}, {{10, 11}, {30, 40}}}, | |
| {{11, 31}, {{10, 11}, {31, 40}}}, | |
| {{11, 39}, {{10, 11}, {39, 40}}}, | |
| {{11, 40}, {{10, 11}}}, | |
| {{11, 41}, {{10, 11}}}, | |
| {{19, 19}, {{10, 20}, {30, 40}}}, | |
| {{19, 20}, {{10, 19}, {30, 40}}}, | |
| {{19, 21}, {{10, 19}, {30, 40}}}, | |
| {{19, 29}, {{10, 19}, {30, 40}}}, | |
| {{19, 30}, {{10, 19}, {30, 40}}}, | |
| {{19, 31}, {{10, 19}, {31, 40}}}, | |
| {{19, 39}, {{10, 19}, {39, 40}}}, | |
| {{19, 40}, {{10, 19}}}, | |
| {{19, 41}, {{10, 19}}}, | |
| {{20, 20}, {{10, 20}, {30, 40}}}, | |
| {{20, 21}, {{10, 20}, {30, 40}}}, | |
| {{20, 29}, {{10, 20}, {30, 40}}}, | |
| {{20, 30}, {{10, 20}, {30, 40}}}, | |
| {{20, 31}, {{10, 20}, {31, 40}}}, | |
| {{20, 39}, {{10, 20}, {39, 40}}}, | |
| {{20, 40}, {{10, 20}}}, | |
| {{20, 41}, {{10, 20}}}, | |
| {{21, 21}, {{10, 20}, {30, 40}}}, | |
| {{21, 29}, {{10, 20}, {30, 40}}}, | |
| {{21, 30}, {{10, 20}, {30, 40}}}, | |
| {{21, 31}, {{10, 20}, {31, 40}}}, | |
| {{21, 39}, {{10, 20}, {39, 40}}}, | |
| {{21, 40}, {{10, 20}}}, | |
| {{21, 41}, {{10, 20}}}, | |
| {{29, 29}, {{10, 20}, {30, 40}}}, | |
| {{29, 30}, {{10, 20}, {30, 40}}}, | |
| {{29, 31}, {{10, 20}, {31, 40}}}, | |
| {{29, 39}, {{10, 20}, {39, 40}}}, | |
| {{29, 40}, {{10, 20}}}, | |
| {{29, 41}, {{10, 20}}}, | |
| {{30, 30}, {{10, 20}, {30, 40}}}, | |
| {{30, 31}, {{10, 20}, {31, 40}}}, | |
| {{30, 39}, {{10, 20}, {39, 40}}}, | |
| {{30, 40}, {{10, 20}}}, | |
| {{30, 41}, {{10, 20}}}, | |
| {{31, 31}, {{10, 20}, {30, 40}}}, | |
| {{31, 39}, {{10, 20}, {30, 31}, {39, 40}}}, | |
| {{31, 40}, {{10, 20}, {30, 31}}}, | |
| {{39, 39}, {{10, 20}, {30, 40}}}, | |
| {{39, 40}, {{10, 20}, {30, 39}}}, | |
| {{39, 41}, {{10, 20}, {30, 39}}}, | |
| {{40, 40}, {{10, 20}, {30, 40}}}, | |
| {{40, 41}, {{10, 20}, {30, 40}}}, | |
| {{41, 41}, {{10, 20}, {30, 40}}}, | |
| }; | |
| for (const auto& test : kTestCases) { | |
| VLOG(1) << "remove: " << test.value << " expect: " << test.expected; | |
| UnsafeIntervalSet copy(init); | |
| copy.Difference(test.value); | |
| EXPECT_EQ(copy, test.expected); | |
| } | |
| } | |
| struct SetOperationTestData { | |
| // roles of a,b,c can be interchanged, e.g. op(a,b)=c vs. op(c,a)=b | |
| UnsafeIntervalSet a; | |
| UnsafeIntervalSet b; | |
| UnsafeIntervalSet c; | |
| }; | |
| TEST(IntervalSetTest, SetDifferences) { | |
| const SetOperationTestData kTestCases[] = { | |
| {{}, {}, {}}, // empty - empty = empty | |
| {{}, {{5, 6}}, {}}, // empty - anything = empty | |
| {{}, {{5, 6}, {7, 8}}, {}}, // empty - anything = empty | |
| {{{1, 2}}, {}, {{1, 2}}}, // anything - empty = (same) | |
| {{{1, 2}, {7, 9}}, {}, {{1, 2}, {7, 9}}}, // anything - empty = (same) | |
| {{{0, 100}}, {{30, 40}, {60, 70}}, {{0, 30}, {40, 60}, {70, 100}}}, | |
| {{{0, 50}}, {{30, 40}, {60, 70}}, {{0, 30}, {40, 50}}}, | |
| {{{50, 100}}, {{30, 40}, {60, 70}}, {{50, 60}, {70, 100}}}, | |
| {{{10, 20}, {30, 40}}, {{5, 9}}, {{10, 20}, {30, 40}}}, | |
| {{{1, 2}, {3, 4}, {5, 6}, {7, 8}}, {{2, 7}}, {{1, 2}, {7, 8}}}, | |
| {{{1, 2}, {3, 4}, {5, 6}, {7, 8}}, {{4, 9}}, {{1, 2}, {3, 4}}}, | |
| {{{1, 2}, {3, 4}, {5, 6}, {7, 8}}, {{0, 4}}, {{5, 6}, {7, 8}}}, | |
| {{{1, 2}, {3, 4}, {5, 6}, {7, 8}}, {{1, 9}}, {}}, | |
| }; | |
| for (const auto& test : kTestCases) { | |
| VLOG(1) << test.a << " - " << test.b << " == " << test.c; | |
| UnsafeIntervalSet set(test.a); | |
| set.Difference(test.b); | |
| EXPECT_EQ(set, test.c); | |
| } | |
| } | |
| TEST(IntervalSetTest, SetUnions) { | |
| const SetOperationTestData kTestCases[] = { | |
| {{}, {}, {}}, // empty U empty = empty | |
| {{}, {{3, 7}}, {{3, 7}}}, | |
| {{{3, 7}}, {{3, 7}}, {{3, 7}}}, | |
| {{{4, 6}}, {{3, 7}}, {{3, 7}}}, | |
| {{{12, 14}}, {{3, 7}}, {{3, 7}, {12, 14}}}, | |
| {{{1, 3}}, {{3, 7}}, {{1, 7}}}, | |
| {{{1, 2}, {3, 4}, {5, 6}}, {{2, 3}, {4, 5}, {6, 7}}, {{1, 7}}}, | |
| {{{1, 2}, {3, 4}, {5, 6}}, {{2, 7}}, {{1, 7}}}, | |
| {{{1, 2}, {5, 6}}, {{3, 4}, {7, 8}}, {{1, 2}, {3, 4}, {5, 6}, {7, 8}}}, | |
| }; | |
| for (const auto& test : kTestCases) { | |
| VLOG(1) << test.a << " U " << test.b << " == " << test.c; | |
| UnsafeIntervalSet set(test.a); | |
| set.Union(test.b); | |
| EXPECT_EQ(set, test.c); | |
| } | |
| // commutative test | |
| for (const auto& test : kTestCases) { | |
| VLOG(1) << test.b << " U " << test.a << " == " << test.c; | |
| UnsafeIntervalSet set(test.b); | |
| set.Union(test.a); | |
| EXPECT_EQ(set, test.c); | |
| } | |
| } | |
| typedef AddIntervalTestData ComplementTestData; | |
| TEST(IntervalSetTest, ComplementEmptyInitial) { | |
| const interval_type kTestCases[] = { | |
| {0, 0}, // | |
| {0, 1}, // | |
| {1, 10}, // | |
| {10, 100}, // | |
| }; | |
| for (const auto& test : kTestCases) { | |
| interval_set_type set; | |
| set.Complement(test); | |
| EXPECT_EQ(set, interval_set_type{test}); | |
| } | |
| } | |
| TEST(IntervalSetTest, ComplementGeneral) { | |
| const UnsafeIntervalSet initial{{10, 20}, {30, 40}}; | |
| const ComplementTestData kTestCases[] = { | |
| {{5, 10}, {{5, 10}}}, | |
| {{5, 11}, {{5, 10}}}, | |
| {{5, 20}, {{5, 10}}}, | |
| {{5, 21}, {{5, 10}, {20, 21}}}, | |
| {{5, 29}, {{5, 10}, {20, 29}}}, | |
| {{5, 30}, {{5, 10}, {20, 30}}}, | |
| {{5, 31}, {{5, 10}, {20, 30}}}, | |
| {{5, 39}, {{5, 10}, {20, 30}}}, | |
| {{5, 40}, {{5, 10}, {20, 30}}}, | |
| {{5, 41}, {{5, 10}, {20, 30}, {40, 41}}}, | |
| {{10, 11}, {}}, | |
| {{10, 20}, {}}, | |
| {{10, 21}, {{20, 21}}}, | |
| {{10, 29}, {{20, 29}}}, | |
| {{10, 30}, {{20, 30}}}, | |
| {{10, 31}, {{20, 30}}}, | |
| {{10, 39}, {{20, 30}}}, | |
| {{10, 40}, {{20, 30}}}, | |
| {{10, 41}, {{20, 30}, {40, 41}}}, | |
| {{20, 21}, {{20, 21}}}, | |
| {{20, 29}, {{20, 29}}}, | |
| {{20, 30}, {{20, 30}}}, | |
| {{20, 31}, {{20, 30}}}, | |
| {{20, 39}, {{20, 30}}}, | |
| {{20, 40}, {{20, 30}}}, | |
| {{20, 41}, {{20, 30}, {40, 41}}}, | |
| {{21, 29}, {{21, 29}}}, | |
| {{21, 30}, {{21, 30}}}, | |
| {{21, 31}, {{21, 30}}}, | |
| {{21, 39}, {{21, 30}}}, | |
| {{21, 40}, {{21, 30}}}, | |
| {{21, 41}, {{21, 30}, {40, 41}}}, | |
| {{29, 29}, {}}, | |
| {{29, 30}, {{29, 30}}}, | |
| {{29, 31}, {{29, 30}}}, | |
| {{29, 39}, {{29, 30}}}, | |
| {{29, 40}, {{29, 30}}}, | |
| {{29, 41}, {{29, 30}, {40, 41}}}, | |
| {{30, 30}, {}}, | |
| {{30, 31}, {}}, | |
| {{30, 39}, {}}, | |
| {{30, 40}, {}}, | |
| {{30, 41}, {{40, 41}}}, | |
| {{39, 39}, {}}, | |
| {{39, 40}, {}}, | |
| {{39, 41}, {{40, 41}}}, | |
| {{40, 40}, {}}, | |
| {{40, 41}, {{40, 41}}}, | |
| {{40, 45}, {{40, 45}}}, | |
| }; | |
| for (const auto& test : kTestCases) { | |
| VLOG(1) << "comp " << test.value << " == " << test.expected; | |
| UnsafeIntervalSet set(initial); | |
| set.Complement(test.value); | |
| EXPECT_EQ(set, test.expected); | |
| } | |
| } | |
| TEST(IntervalSetTest, MonotonicTransformShiftUp) { | |
| const UnsafeIntervalSet initial{{10, 20}, {30, 40}}; | |
| const interval_set_type result = | |
| initial.MonotonicTransform<int>([](const int x) { return x + 5; }); | |
| const UnsafeIntervalSet expected{{15, 25}, {35, 45}}; | |
| EXPECT_EQ(result, expected); | |
| } | |
| TEST(IntervalSetTest, MonotonicTransformScaleUp) { | |
| const UnsafeIntervalSet initial{{10, 20}, {30, 40}}; | |
| const interval_set_type result = | |
| initial.MonotonicTransform<int>([](const int x) { return x * 2; }); | |
| const UnsafeIntervalSet expected{{20, 40}, {60, 80}}; | |
| EXPECT_EQ(result, expected); | |
| } | |
| TEST(IntervalSetTest, MonotonicTransformScaleDown) { | |
| const UnsafeIntervalSet initial{{10, 11}, {13, 14}, {30, 40}}; | |
| const interval_set_type result = | |
| initial.MonotonicTransform<int>([](const int x) { return x / 2; }); | |
| // Note that {10,11} -> {5,5} (empty) when truncated (integer division), | |
| // so the result doesn't include it. | |
| const UnsafeIntervalSet expected{{6, 7}, {15, 20}}; | |
| EXPECT_EQ(result, expected); | |
| } | |
| TEST(IntervalSetTest, MonotonicTransformReflect) { | |
| const UnsafeIntervalSet initial{{10, 20}, {30, 50}}; | |
| // function is inverting | |
| const interval_set_type result = | |
| initial.MonotonicTransform<int>([](const int x) { return 100 - x; }); | |
| const UnsafeIntervalSet expected{{50, 70}, {80, 90}}; | |
| EXPECT_EQ(result, expected); | |
| } | |
| TEST(IntervalSetTest, StreamOutputEmpty) { | |
| const UnsafeIntervalSet initial{}; | |
| std::ostringstream stream; | |
| stream << initial; | |
| EXPECT_EQ(stream.str(), ""); | |
| } | |
| TEST(IntervalSetTest, StreamOutputNonEmpty) { | |
| const UnsafeIntervalSet initial{{3, 5}, {7, 9}}; | |
| std::ostringstream stream; | |
| stream << initial; | |
| EXPECT_EQ(stream.str(), "[3, 5), [7, 9)"); | |
| } | |
| TEST(ParseInclusivesRangesTest, Empty) { | |
| const std::initializer_list<absl::string_view> kRanges{}; | |
| interval_set_type iset; | |
| std::ostringstream errstream; | |
| EXPECT_TRUE( | |
| ParseInclusiveRanges(&iset, kRanges.begin(), kRanges.end(), &errstream)); | |
| EXPECT_TRUE(errstream.str().empty()); | |
| EXPECT_TRUE(iset.empty()); | |
| } | |
| TEST(ParseInclusivesRangesTest, ParseErrorSingle) { | |
| const std::initializer_list<absl::string_view> kRanges{"yyy"}; | |
| interval_set_type iset; | |
| std::ostringstream errstream; | |
| EXPECT_FALSE( | |
| ParseInclusiveRanges(&iset, kRanges.begin(), kRanges.end(), &errstream)); | |
| EXPECT_FALSE(errstream.str().empty()); | |
| EXPECT_TRUE(iset.empty()); | |
| } | |
| TEST(ParseInclusivesRangesTest, ParseErrorRange) { | |
| const std::initializer_list<absl::string_view> kRanges{"1-x"}; | |
| interval_set_type iset; | |
| std::ostringstream errstream; | |
| EXPECT_FALSE( | |
| ParseInclusiveRanges(&iset, kRanges.begin(), kRanges.end(), &errstream)); | |
| EXPECT_FALSE(errstream.str().empty()); | |
| EXPECT_TRUE(iset.empty()); | |
| } | |
| TEST(ParseInclusivesRangesTest, EmptyString) { | |
| // Empty string can come from splitting. | |
| const std::initializer_list<absl::string_view> kRanges{""}; | |
| interval_set_type iset; | |
| std::ostringstream errstream; | |
| EXPECT_TRUE( | |
| ParseInclusiveRanges(&iset, kRanges.begin(), kRanges.end(), &errstream)); | |
| EXPECT_TRUE(errstream.str().empty()); | |
| EXPECT_TRUE(iset.empty()); | |
| const UnsafeIntervalSet expected{}; | |
| EXPECT_EQ(iset, expected); | |
| } | |
| TEST(ParseInclusivesRangesTest, SingleValues) { | |
| const std::initializer_list<absl::string_view> kRanges{"1", "3", "4", "5"}; | |
| interval_set_type iset; | |
| std::ostringstream errstream; | |
| EXPECT_TRUE( | |
| ParseInclusiveRanges(&iset, kRanges.begin(), kRanges.end(), &errstream)); | |
| EXPECT_TRUE(errstream.str().empty()); | |
| const UnsafeIntervalSet expected{{1, 2}, {3, 6}}; | |
| EXPECT_EQ(iset, expected); | |
| } | |
| TEST(ParseInclusivesRangesTest, SingleValuesAndEmpty) { | |
| const std::initializer_list<absl::string_view> kRanges{"1", "", "4", "5"}; | |
| interval_set_type iset; | |
| std::ostringstream errstream; | |
| EXPECT_TRUE( | |
| ParseInclusiveRanges(&iset, kRanges.begin(), kRanges.end(), &errstream)); | |
| EXPECT_TRUE(errstream.str().empty()); | |
| const UnsafeIntervalSet expected{{1, 2}, {4, 6}}; | |
| EXPECT_EQ(iset, expected); | |
| } | |
| TEST(ParseInclusivesRangesTest, PairValues) { | |
| const std::initializer_list<absl::string_view> kRanges{"1-10", "3-11", | |
| "41-52"}; | |
| interval_set_type iset; | |
| std::ostringstream errstream; | |
| EXPECT_TRUE( | |
| ParseInclusiveRanges(&iset, kRanges.begin(), kRanges.end(), &errstream)); | |
| EXPECT_TRUE(errstream.str().empty()); | |
| const UnsafeIntervalSet expected{{1, 12}, {41, 53}}; | |
| EXPECT_EQ(iset, expected); | |
| } | |
| TEST(ParseInclusivesRangesTest, PairValuesCustomSeparator) { | |
| const std::initializer_list<absl::string_view> kRanges{"1:10", "3:11", | |
| "41:52"}; | |
| interval_set_type iset; | |
| std::ostringstream errstream; | |
| EXPECT_TRUE(ParseInclusiveRanges(&iset, kRanges.begin(), kRanges.end(), | |
| &errstream, ':')); | |
| EXPECT_TRUE(errstream.str().empty()); | |
| const UnsafeIntervalSet expected{{1, 12}, {41, 53}}; | |
| EXPECT_EQ(iset, expected); | |
| } | |
| TEST(ParseInclusivesRangesTest, MixedValues) { | |
| const std::initializer_list<absl::string_view> kRanges{"2-10", "11-3", "41", | |
| "42-52"}; | |
| interval_set_type iset; | |
| std::ostringstream errstream; | |
| EXPECT_TRUE( | |
| ParseInclusiveRanges(&iset, kRanges.begin(), kRanges.end(), &errstream)); | |
| EXPECT_TRUE(errstream.str().empty()); | |
| const UnsafeIntervalSet expected{{2, 12}, {41, 53}}; | |
| EXPECT_EQ(iset, expected); | |
| } | |
| TEST(FormatInclusiveRangesTest, Various) { | |
| const interval_set_type iset{{2, 4}, {5, 6}, {7, 9}}; | |
| { | |
| std::ostringstream formatted; | |
| iset.FormatInclusive(formatted, false); | |
| EXPECT_EQ(formatted.str(), "2-3,5-5,7-8"); | |
| } | |
| { | |
| std::ostringstream formatted; | |
| iset.FormatInclusive(formatted, true); | |
| EXPECT_EQ(formatted.str(), "2-3,5,7-8"); | |
| } | |
| } | |
| TEST(UniformRandomGeneratorTest, EmptyInvalid) { | |
| interval_set_type iset; | |
| EXPECT_DEATH(iset.UniformRandomGenerator(), | |
| "Non-empty interval set required"); | |
| } | |
| TEST(UniformRandomGeneratorTest, Singleton) { | |
| interval_set_type iset{{42, 43}}; | |
| const auto gen = iset.UniformRandomGenerator(); | |
| for (int i = 0; i < 10; ++i) { | |
| EXPECT_EQ(gen(), 42); | |
| } | |
| } | |
| TEST(UniformRandomGeneratorTest, SingleRange) { | |
| interval_set_type iset{{42, 49}}; | |
| const auto gen = iset.UniformRandomGenerator(); | |
| for (int i = 0; i < 20; ++i) { | |
| const auto sample = gen(); | |
| EXPECT_TRUE(iset.Contains(sample)) << "got: " << sample; | |
| } | |
| } | |
| TEST(UniformRandomGeneratorTest, MultiRanges) { | |
| interval_set_type iset{{42, 49}, {99, 104}, {200, 244}}; | |
| const auto gen = iset.UniformRandomGenerator(); | |
| for (int i = 0; i < 100; ++i) { | |
| const auto sample = gen(); | |
| EXPECT_TRUE(iset.Contains(sample)) << "got: " << sample; | |
| } | |
| } | |
| // DisjointIntervalSet tests | |
| typedef DisjointIntervalSet<int> IntIntervalSet; | |
| typedef DisjointIntervalSet<std::vector<int>::const_iterator> VectorIntervalSet; | |
| // Make sure values interior to a range point back to the entire range. | |
| template <typename M> | |
| static void DisjointIntervalConsistencyCheck(const M& iset) { | |
| // works on integers and iterators | |
| for (auto iter = iset.begin(); iter != iset.end(); ++iter) { | |
| for (auto i = iter->first; i != iter->second; ++i) { | |
| EXPECT_EQ(iset.find(i), iter); | |
| } | |
| } | |
| } | |
| TEST(DisjointIntervalSetTest, DefaultCtor) { | |
| const IntIntervalSet iset; | |
| EXPECT_TRUE(iset.empty()); | |
| } | |
| TEST(DisjointIntervalSetTest, FindEmpty) { | |
| const IntIntervalSet iset; | |
| EXPECT_EQ(iset.find(3), iset.end()); | |
| } | |
| TEST(DisjointIntervalSetTest, EmplaceOne) { | |
| IntIntervalSet iset; | |
| const auto p = iset.emplace(3, 4); | |
| EXPECT_TRUE(p.second); | |
| EXPECT_EQ(p.first->first, 3); | |
| EXPECT_EQ(p.first->second, 4); | |
| EXPECT_FALSE(iset.empty()); | |
| DisjointIntervalConsistencyCheck(iset); | |
| } | |
| template <typename M> | |
| static typename M::const_iterator VerifyEmplace(M* iset, | |
| typename M::mapped_type min, | |
| typename M::mapped_type max) { | |
| const auto p = iset->emplace(min, max); | |
| EXPECT_TRUE(p.second); | |
| EXPECT_EQ(p.first->first, min); | |
| EXPECT_EQ(p.first->second, max); | |
| return p.first; | |
| } | |
| TEST(DisjointIntervalSetTest, EmplaceIterators) { | |
| VectorIntervalSet iset; | |
| std::vector<int> vec{{1, 4, 1, 5, 9, 2, 6}}; | |
| VerifyEmplace(&iset, vec.begin() + 3, vec.begin() + 5); | |
| DisjointIntervalConsistencyCheck(iset); | |
| } | |
| TEST(DisjointIntervalSetTest, EmplaceNonoverlappingAbutting) { | |
| IntIntervalSet iset; | |
| const auto iter1 = VerifyEmplace(&iset, 3, 4); | |
| // insert new leftmost range | |
| const auto iter2 = VerifyEmplace(&iset, 1, 3); | |
| // insert new rightmost range | |
| const auto iter3 = VerifyEmplace(&iset, 4, 7); | |
| EXPECT_EQ(iset.find(0), iset.end()); | |
| for (int i = 1; i < 3; ++i) { | |
| EXPECT_EQ(iset.find(i), iter2); | |
| } | |
| for (int i = 3; i < 4; ++i) { | |
| EXPECT_EQ(iset.find(i), iter1); | |
| } | |
| for (int i = 4; i < 7; ++i) { | |
| EXPECT_EQ(iset.find(i), iter3); | |
| } | |
| EXPECT_EQ(iset.find(7), iset.end()); | |
| DisjointIntervalConsistencyCheck(iset); | |
| } | |
| TEST(DisjointIntervalSetTest, EmplaceNonoverlappingWithGaps) { | |
| IntIntervalSet iset; | |
| const auto iter1 = VerifyEmplace(&iset, 20, 25); | |
| // insert new leftmost range | |
| const auto iter2 = VerifyEmplace(&iset, 30, 40); | |
| // insert new rightmost range | |
| const auto iter3 = VerifyEmplace(&iset, 10, 15); | |
| for (int i = 0; i < 10; ++i) { | |
| EXPECT_EQ(iset.find(i), iset.end()); | |
| } | |
| for (int i = 10; i < 15; ++i) { | |
| EXPECT_EQ(iset.find(i), iter3); | |
| } | |
| for (int i = 15; i < 20; ++i) { | |
| EXPECT_EQ(iset.find(i), iset.end()); | |
| } | |
| for (int i = 20; i < 25; ++i) { | |
| EXPECT_EQ(iset.find(i), iter1); | |
| } | |
| for (int i = 25; i < 30; ++i) { | |
| EXPECT_EQ(iset.find(i), iset.end()); | |
| } | |
| for (int i = 30; i < 40; ++i) { | |
| EXPECT_EQ(iset.find(i), iter2); | |
| } | |
| DisjointIntervalConsistencyCheck(iset); | |
| } | |
| TEST(DisjointIntervalSetTest, EmplaceBackwardsRange) { | |
| IntIntervalSet iset; | |
| EXPECT_DEATH(iset.emplace(4, 3), "min_key <= max_key"); | |
| } | |
| TEST(DisjointIntervalSetTest, MustEmplaceSuccess) { | |
| IntIntervalSet iset; | |
| constexpr std::pair<int, int> kTestValues[] = { | |
| {3, 4}, {1, 3}, {4, 7}, {-10, -5}, {10, 15}, | |
| }; | |
| for (const auto& t : kTestValues) { | |
| const auto iter = iset.must_emplace(t.first, t.second); | |
| // Ensure that inserted value is the expected key min and max. | |
| EXPECT_EQ(iter->first, t.first); | |
| EXPECT_EQ(iter->second, t.second); | |
| } | |
| DisjointIntervalConsistencyCheck(iset); | |
| } | |
| TEST(DisjointIntervalSetTest, MustEmplaceOverlapLeft) { | |
| IntIntervalSet iset; | |
| iset.must_emplace(30, 40); | |
| EXPECT_DEATH(iset.must_emplace(20, 31), "Failed to emplace"); | |
| } | |
| TEST(DisjointIntervalSetTest, MustEmplaceOverlapRight) { | |
| IntIntervalSet iset; | |
| iset.must_emplace(30, 40); | |
| EXPECT_DEATH(iset.must_emplace(39, 45), "Failed to emplace"); | |
| } | |
| TEST(DisjointIntervalSetTest, MustEmplaceOverlapInterior) { | |
| IntIntervalSet iset; | |
| iset.must_emplace(30, 40); | |
| EXPECT_DEATH(iset.must_emplace(31, 39), "Failed to emplace"); | |
| } | |
| TEST(DisjointIntervalSetTest, MustEmplaceOverlapEnveloped) { | |
| IntIntervalSet iset; | |
| iset.must_emplace(30, 40); | |
| EXPECT_DEATH(iset.must_emplace(29, 40), "Failed to emplace"); | |
| } | |
| TEST(DisjointIntervalSetTest, MustEmplaceSpanningTwo) { | |
| IntIntervalSet iset; | |
| iset.must_emplace(30, 40); | |
| iset.must_emplace(50, 60); | |
| EXPECT_DEATH(iset.must_emplace(35, 55), "Failed to emplace"); | |
| } | |
| TEST(DisjointIntervalSetTest, MustEmplaceOverlapsLower) { | |
| IntIntervalSet iset; | |
| iset.must_emplace(30, 40); | |
| iset.must_emplace(50, 60); | |
| EXPECT_DEATH(iset.must_emplace(35, 45), "Failed to emplace"); | |
| } | |
| TEST(DisjointIntervalSetTest, MustEmplaceOverlapsUpper) { | |
| IntIntervalSet iset; | |
| iset.must_emplace(30, 40); | |
| iset.must_emplace(50, 60); | |
| EXPECT_DEATH(iset.must_emplace(45, 55), "Failed to emplace"); | |
| } | |
| TEST(DisjointIntervalMapTest, FindInterval) { | |
| IntIntervalSet iset; | |
| iset.must_emplace(20, 25); | |
| for (int i = 19; i < 26; ++i) { | |
| for (int j = i + 1; j < 26; ++j) { | |
| const auto found = iset.find({i, j}); | |
| if (i >= 20 && j <= 25) { | |
| ASSERT_NE(found, iset.end()); | |
| EXPECT_EQ(found->first, 20); | |
| EXPECT_EQ(found->second, 25); | |
| } else { | |
| EXPECT_EQ(found, iset.end()); | |
| } | |
| } | |
| } | |
| DisjointIntervalConsistencyCheck(iset); | |
| } | |
| TEST(DisjointIntervalMapTest, FindVectorInterval) { | |
| std::vector<int> v(40, 1); // don't care about values | |
| VectorIntervalSet iset; | |
| const auto base = v.begin(); | |
| iset.must_emplace(base + 20, base + 25); | |
| for (auto i = base + 19; i < base + 26; ++i) { | |
| for (auto j = i + 1; j < base + 26; ++j) { | |
| const auto found = iset.find({i, j}); | |
| if (i >= base + 20 && j <= base + 25) { | |
| ASSERT_NE(found, iset.end()); | |
| EXPECT_EQ(found->first, base + 20); | |
| EXPECT_EQ(found->second, base + 25); | |
| } else { | |
| EXPECT_EQ(found, iset.end()); | |
| } | |
| } | |
| } | |
| DisjointIntervalConsistencyCheck(iset); | |
| } | |
| } // namespace | |
| } // namespace verible |