blob: 8ecea563e4e0e96d3b2951e0167c1012252600fb [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/algorithm.h"
#include <iterator> // for std::back_inserter
#include <list>
#include <string>
#include <vector>
#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "absl/strings/string_view.h"
#include "common/util/iterator_range.h"
namespace verible {
namespace {
using ::testing::ElementsAre;
using ::testing::ElementsAreArray;
// Heterogeneous compare function for testing.
// Returns < 0 if i is considered "less than" c,
// > 0 if i is considered "greater than" c,
// otherwise 0 if they are considered equal.
int CharCompare(int i, char c) {
return i - (c - 'a' + 1); // Let 'a' correspond to 1, etc.
}
TEST(SetSymmetricDifferenceSplitTest, EmptyInputs) {
std::vector<int> seq1, diff1;
absl::string_view seq2;
std::string diff2;
set_symmetric_difference_split(seq1.begin(), seq1.end(), seq2.begin(),
seq2.end(), std::back_inserter(diff1),
std::back_inserter(diff2), &CharCompare);
EXPECT_TRUE(diff1.empty());
EXPECT_TRUE(diff2.empty());
}
TEST(SetSymmetricDifferenceSplitTest, EmptyInputsPreallocatedOutput) {
std::vector<int> seq1, diff1(3);
absl::string_view seq2;
std::string diff2(3, 'x');
auto p = set_symmetric_difference_split(
seq1.begin(), seq1.end(), seq2.begin(), seq2.end(), diff1.begin(),
diff2.begin(), &CharCompare);
EXPECT_TRUE(p.first == diff1.begin());
EXPECT_TRUE(p.second == diff2.begin());
}
TEST(SetSymmetricDifferenceSplitTest, FirstSequenceEmpty) {
std::vector<int> seq1, diff1;
absl::string_view seq2("ace");
std::string diff2;
set_symmetric_difference_split(seq1.begin(), seq1.end(), seq2.begin(),
seq2.end(), std::back_inserter(diff1),
std::back_inserter(diff2), &CharCompare);
EXPECT_TRUE(diff1.empty());
EXPECT_EQ(diff2, seq2);
}
TEST(SetSymmetricDifferenceSplitTest, FirstSequenceEmptyPreallocatedOutput) {
std::vector<int> seq1, diff1(3);
absl::string_view seq2("ace");
std::string diff2(4, 'x');
auto p = set_symmetric_difference_split(
seq1.begin(), seq1.end(), seq2.begin(), seq2.end(), diff1.begin(),
diff2.begin(), &CharCompare);
EXPECT_TRUE(p.first == diff1.begin());
EXPECT_TRUE(p.second == diff2.begin() + 3);
EXPECT_THAT(make_range(diff2.begin(), p.second), ElementsAreArray(seq2));
}
TEST(SetSymmetricDifferenceSplitTest, SecondSequenceEmpty) {
std::vector<int> seq1({2, 4, 6}), diff1;
absl::string_view seq2;
std::string diff2;
set_symmetric_difference_split(seq1.begin(), seq1.end(), seq2.begin(),
seq2.end(), std::back_inserter(diff1),
std::back_inserter(diff2), &CharCompare);
EXPECT_THAT(diff1, ElementsAreArray(seq1));
EXPECT_TRUE(diff2.empty());
}
TEST(SetSymmetricDifferenceSplitTest, SecondSequenceEmptyPreallocatedOutput) {
std::vector<int> seq1({2, 4, 6}), diff1(3);
absl::string_view seq2;
std::string diff2(3, 'x');
auto p = set_symmetric_difference_split(
seq1.begin(), seq1.end(), seq2.begin(), seq2.end(), diff1.begin(),
diff2.begin(), &CharCompare);
EXPECT_TRUE(p.first == diff1.begin() + 3);
EXPECT_TRUE(p.second == diff2.begin());
EXPECT_THAT(make_range(diff1.begin(), p.first), ElementsAreArray(seq1));
}
TEST(SetSymmetricDifferenceSplitTest, CompleteMatch) {
std::vector<int> seq1({2, 4, 6}), diff1;
absl::string_view seq2("bdf");
std::string diff2;
set_symmetric_difference_split(seq1.begin(), seq1.end(), seq2.begin(),
seq2.end(), std::back_inserter(diff1),
std::back_inserter(diff2), &CharCompare);
EXPECT_TRUE(diff1.empty());
EXPECT_TRUE(diff2.empty());
}
TEST(SetSymmetricDifferenceSplitTest, CompleteMatchPreallocatedOutput) {
std::vector<int> seq1({2, 4, 6}), diff1(3);
absl::string_view seq2("bdf");
std::string diff2(3, 'x');
auto p = set_symmetric_difference_split(
seq1.begin(), seq1.end(), seq2.begin(), seq2.end(), diff1.begin(),
diff2.begin(), &CharCompare);
EXPECT_TRUE(p.first == diff1.begin());
EXPECT_TRUE(p.second == diff2.begin());
}
TEST(SetSymmetricDifferenceSplitTest, CompleteMismatchInterleaved) {
std::vector<int> seq1({3, 5, 7}), diff1;
absl::string_view seq2("bdf");
std::string diff2;
set_symmetric_difference_split(seq1.begin(), seq1.end(), seq2.begin(),
seq2.end(), std::back_inserter(diff1),
std::back_inserter(diff2), &CharCompare);
EXPECT_THAT(diff1, ElementsAreArray(seq1));
EXPECT_EQ(diff2, seq2);
}
TEST(SetSymmetricDifferenceSplitTest, CompleteMismatchNonoverlapping1) {
std::vector<int> seq1({7, 8, 9}), diff1;
absl::string_view seq2("bdf");
std::string diff2;
set_symmetric_difference_split(seq1.begin(), seq1.end(), seq2.begin(),
seq2.end(), std::back_inserter(diff1),
std::back_inserter(diff2), &CharCompare);
EXPECT_THAT(diff1, ElementsAreArray(seq1));
EXPECT_EQ(diff2, seq2);
}
TEST(SetSymmetricDifferenceSplitTest, CompleteMismatchNonoverlapping2) {
std::vector<int> seq1({1, 2, 4}), diff1;
absl::string_view seq2("xyz");
std::string diff2;
set_symmetric_difference_split(seq1.begin(), seq1.end(), seq2.begin(),
seq2.end(), std::back_inserter(diff1),
std::back_inserter(diff2), &CharCompare);
EXPECT_THAT(diff1, ElementsAreArray(seq1));
EXPECT_EQ(diff2, seq2);
}
TEST(SetSymmetricDifferenceSplitTest, PartialMatch1) {
std::vector<int> seq1({2, 3, 6}), diff1;
absl::string_view seq2("bdf");
std::string diff2;
set_symmetric_difference_split(seq1.begin(), seq1.end(), seq2.begin(),
seq2.end(), std::back_inserter(diff1),
std::back_inserter(diff2), &CharCompare);
EXPECT_THAT(diff1, ElementsAre(3));
EXPECT_THAT(diff2, ElementsAre('d'));
}
TEST(SetSymmetricDifferenceSplitTest, PartialMatch1PreallocatedOutput) {
std::vector<int> seq1({2, 3, 6}), diff1(3);
absl::string_view seq2("bdf");
std::string diff2(3, 'x');
auto p = set_symmetric_difference_split(
seq1.begin(), seq1.end(), seq2.begin(), seq2.end(), diff1.begin(),
diff2.begin(), &CharCompare);
EXPECT_TRUE(p.first == diff1.begin() + 1);
EXPECT_TRUE(p.second == diff2.begin() + 1);
EXPECT_THAT(make_range(diff1.begin(), p.first), ElementsAre(3));
EXPECT_THAT(make_range(diff2.begin(), p.second), ElementsAre('d'));
}
TEST(SetSymmetricDifferenceSplitTest, PartialMatch2) {
std::vector<int> seq1({1, 4, 5}), diff1;
absl::string_view seq2("bdf");
std::string diff2;
set_symmetric_difference_split(seq1.begin(), seq1.end(), seq2.begin(),
seq2.end(), std::back_inserter(diff1),
std::back_inserter(diff2), &CharCompare);
EXPECT_THAT(diff1, ElementsAre(1, 5));
EXPECT_THAT(diff2, ElementsAre('b', 'f'));
}
TEST(SetSymmetricDifferenceSplitTest, CompleteSubset) {
std::vector<int> seq1({2, 4, 6}), diff1;
absl::string_view seq2("bcdf");
std::string diff2;
set_symmetric_difference_split(seq1.begin(), seq1.end(), seq2.begin(),
seq2.end(), std::back_inserter(diff1),
std::back_inserter(diff2), &CharCompare);
EXPECT_TRUE(diff1.empty());
EXPECT_THAT(diff2, ElementsAre('c'));
}
TEST(SetSymmetricDifferenceSplitTest, CompleteSubset2) {
std::vector<int> seq1({2, 4, 5, 6}), diff1;
absl::string_view seq2("bdf");
std::string diff2;
set_symmetric_difference_split(seq1.begin(), seq1.end(), seq2.begin(),
seq2.end(), std::back_inserter(diff1),
std::back_inserter(diff2), &CharCompare);
EXPECT_THAT(diff1, ElementsAre(5));
EXPECT_TRUE(diff2.empty());
}
TEST(FindAllTest, EmptyRangeTruePredicate) {
const std::vector<int> seq; // empty
std::vector<std::vector<int>::const_iterator> bounds;
find_all(seq.begin(), seq.end(), std::back_inserter(bounds),
[](int) { return true; });
EXPECT_TRUE(bounds.empty());
}
TEST(FindAllTest, EmptyRangeFalsePredicate) {
const std::vector<int> seq; // empty
std::vector<std::vector<int>::const_iterator> bounds;
find_all(seq.begin(), seq.end(), std::back_inserter(bounds),
[](int) { return false; });
EXPECT_TRUE(bounds.empty());
}
TEST(FindAllTest, PartitionEveryElement) {
const std::vector<int> seq({6, 5, 4, 3, 2});
std::vector<std::vector<int>::const_iterator> bounds;
find_all(seq.begin(), seq.end(), std::back_inserter(bounds),
[](int) { return true; });
const auto b = seq.begin();
EXPECT_THAT(bounds, ElementsAre(b, b + 1, b + 2, b + 3, b + 4));
}
TEST(FindAllTest, PartitionNoElements) {
const std::vector<int> seq({6, 5, 4, 3, 2});
std::vector<std::vector<int>::const_iterator> bounds;
find_all(seq.begin(), seq.end(), std::back_inserter(bounds),
[](int) { return false; });
EXPECT_TRUE(bounds.empty());
}
TEST(FindAllTest, PartitionAtEveryZero) {
const std::vector<int> seq({0, 6, 5, 0, 4, 3, 2, 0});
std::vector<std::vector<int>::const_iterator> bounds;
find_all(seq.begin(), seq.end(), std::back_inserter(bounds),
[](int i) { return i == 0; });
const auto b = seq.begin();
EXPECT_THAT(bounds, ElementsAre(b, b + 3, b + 7));
}
TEST(FindAllTest, PartitionAfterEveryZero) {
const std::vector<int> seq({0, 6, 5, 0, 4, 3, 2, 0});
std::vector<std::vector<int>::const_iterator> bounds;
// This demonstrates using a stateful predicate.
int prev = -1;
find_all(seq.begin(), seq.end(), std::back_inserter(bounds), [&](int i) {
// Split *after* each zero.
const bool p = prev == 0;
prev = i;
return p;
});
const auto b = seq.begin();
EXPECT_THAT(bounds, ElementsAre(b + 1, b + 4));
// Last 0 is not evaluated because it is right before the end().
EXPECT_EQ(prev, 0); // the last value seen
}
TEST(FindAllTest, PartitionAfterEveryZero2) {
const std::vector<int> seq({6, 0, 5, 0, 4, 3, 2, 0, 1});
std::vector<std::vector<int>::const_iterator> bounds;
// This demonstrates using a stateful predicate.
int prev = -1;
find_all(seq.begin(), seq.end(), std::back_inserter(bounds), [&](int i) {
// Split *after* each zero.
const bool p = prev == 0;
prev = i;
return p;
});
const auto b = seq.begin();
EXPECT_THAT(bounds, ElementsAre(b + 2, b + 4, b + 8));
EXPECT_EQ(prev, 1); // the last value seen
}
TEST(FindAllTest, StrSplitAtEqual) {
const absl::string_view seq("aa=b=cc");
std::vector<absl::string_view::const_iterator> bounds;
find_all(seq.begin(), seq.end(), std::back_inserter(bounds),
[](char i) { return i == '='; });
const auto b = seq.begin();
EXPECT_THAT(bounds, ElementsAre(b + 2, b + 4));
}
TEST(FindAllTest, StrSplitAfterEqual) {
const absl::string_view seq("aa=b=cd");
std::vector<absl::string_view::const_iterator> bounds;
int prev = -1;
find_all(seq.begin(), seq.end(), std::back_inserter(bounds), [&](char i) {
// Split *after* each '='.
const bool p = prev == '=';
prev = i;
return p;
});
const auto b = seq.begin();
EXPECT_THAT(bounds, ElementsAre(b + 3, b + 5));
EXPECT_EQ(prev, 'd'); // the last value seen
}
// generator that returns infinite sequence: {[false]*(N-1), true}*
class EveryN {
public:
explicit EveryN(int n, int init = 0) : i(init), n(n) {}
template <class T>
bool operator()(const T&) {
const bool ret = i == n;
if (ret) i = 0;
++i;
return ret;
}
private:
int i;
const int n;
};
TEST(FindAllTest, StrSplitEveryN) {
const absl::string_view seq("xxxxyyyyaaaabbb");
std::vector<absl::string_view::const_iterator> bounds;
find_all(seq.begin(), seq.end(), std::back_inserter(bounds), EveryN(4));
const auto b = seq.begin();
EXPECT_THAT(bounds, ElementsAre(b + 4, b + 8, b + 12));
}
TEST(LexicographicalLessTest, Containers) {
LexicographicalLess comp;
using List = std::list<int>;
using Vector = std::vector<int>;
EXPECT_FALSE(comp(List{}, List{}));
EXPECT_FALSE(comp(Vector{}, Vector{}));
EXPECT_FALSE(comp(Vector{}, List{}));
EXPECT_FALSE(comp(List{}, Vector{}));
EXPECT_TRUE(comp(Vector{}, List{1}));
EXPECT_FALSE(comp(Vector{0}, List{}));
EXPECT_FALSE(comp(Vector{0}, List{0}));
EXPECT_FALSE(comp(Vector{4}, List{4}));
EXPECT_TRUE(comp(List{1}, Vector{2}));
EXPECT_TRUE(comp(List{1}, Vector{1, -1}));
EXPECT_TRUE(comp(List{1}, List{1, -1}));
EXPECT_FALSE(comp(List{1, 0}, List{1, -1}));
EXPECT_TRUE(comp(List{1, -2}, List{1, -1}));
}
// like substr()
template <class T>
iterator_range<typename T::const_iterator> make_subrange(const T& t, size_t b,
size_t e) {
return make_range(t.begin() + b, t.begin() + e);
}
TEST(LexicographicalLessTest, Ranges) {
LexicographicalLess comp;
const std::vector<int> v{1, 0, 2, 1, 3};
EXPECT_FALSE(comp(make_subrange(v, 0, 0), make_subrange(v, 0, 0)));
EXPECT_FALSE(comp(make_subrange(v, 1, 1), make_subrange(v, 1, 1)));
EXPECT_FALSE(comp(v, v));
EXPECT_FALSE(comp(v, make_subrange(v, 0, 1)));
EXPECT_TRUE(comp(make_subrange(v, 0, 1), v));
EXPECT_FALSE(comp(v, make_subrange(v, 0, 5))); // whole vector
EXPECT_FALSE(comp(make_subrange(v, 0, 5), v)); // whole vector
EXPECT_FALSE(comp(v, make_subrange(v, 1, 2)));
EXPECT_TRUE(comp(v, make_subrange(v, 2, 3)));
EXPECT_FALSE(comp(v, make_subrange(v, 3, 4)));
EXPECT_TRUE(comp(v, make_subrange(v, 3, 5)));
EXPECT_FALSE(comp(make_subrange(v, 0, 1), make_subrange(v, 0, 1)));
EXPECT_FALSE(comp(make_subrange(v, 0, 5), make_subrange(v, 0, 5))); // whole
EXPECT_TRUE(comp(make_subrange(v, 1, 5), make_subrange(v, 0, 5)));
EXPECT_FALSE(comp(make_subrange(v, 0, 5), make_subrange(v, 1, 5)));
EXPECT_TRUE(comp(make_subrange(v, 0, 5), make_subrange(v, 2, 5)));
EXPECT_FALSE(comp(make_subrange(v, 2, 5), make_subrange(v, 0, 5)));
EXPECT_FALSE(comp(make_subrange(v, 0, 1), make_subrange(v, 3, 4)));
EXPECT_FALSE(comp(make_subrange(v, 3, 4), make_subrange(v, 0, 1)));
}
} // namespace
} // namespace verible