blob: 09fd6356b1cd5fa930d9eef07035e907ee7d6641 [file] [log] [blame]
// 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