
Change-Id: I8a94fff10d321e8bb002435ce4d5393cd99da9fe Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3958474 Owners-Override: Lei Zhang <thestig@chromium.org> Reviewed-by: Lei Zhang <thestig@chromium.org> Commit-Queue: Daniel Cheng <dcheng@chromium.org> Cr-Commit-Position: refs/heads/main@{#1059666}
283 lines
7.1 KiB
C++
283 lines
7.1 KiB
C++
// Copyright 2012 The Chromium Authors
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
|
|
#include "base/stl_util.h"
|
|
|
|
#include <array>
|
|
#include <deque>
|
|
#include <forward_list>
|
|
#include <functional>
|
|
#include <initializer_list>
|
|
#include <iterator>
|
|
#include <list>
|
|
#include <queue>
|
|
#include <set>
|
|
#include <stack>
|
|
#include <string>
|
|
#include <type_traits>
|
|
#include <unordered_set>
|
|
#include <vector>
|
|
|
|
#include "base/containers/cxx20_erase_vector.h"
|
|
#include "base/containers/queue.h"
|
|
#include "testing/gmock/include/gmock/gmock.h"
|
|
#include "testing/gtest/include/gtest/gtest.h"
|
|
#include "third_party/abseil-cpp/absl/types/optional.h"
|
|
|
|
namespace {
|
|
|
|
using ::testing::IsNull;
|
|
using ::testing::Pair;
|
|
|
|
template <typename Container>
|
|
void RunConstCastIteratorTest() {
|
|
using std::begin;
|
|
using std::cbegin;
|
|
|
|
Container c = {1, 2, 3, 4, 5};
|
|
auto c_it = std::next(cbegin(c), 3);
|
|
auto it = base::ConstCastIterator(c, c_it);
|
|
static_assert(std::is_same<decltype(cbegin(std::declval<Container&>())),
|
|
decltype(c_it)>::value,
|
|
"c_it is not a constant iterator.");
|
|
static_assert(std::is_same<decltype(begin(std::declval<Container&>())),
|
|
decltype(it)>::value,
|
|
"it is not a iterator.");
|
|
EXPECT_EQ(c_it, it);
|
|
// Const casting the iterator should not modify the underlying container.
|
|
Container other = {1, 2, 3, 4, 5};
|
|
EXPECT_THAT(c, testing::ContainerEq(other));
|
|
}
|
|
|
|
} // namespace
|
|
|
|
namespace base {
|
|
namespace {
|
|
|
|
TEST(STLUtilTest, GetUnderlyingContainer) {
|
|
{
|
|
std::queue<int> queue({1, 2, 3, 4, 5});
|
|
static_assert(std::is_same<decltype(GetUnderlyingContainer(queue)),
|
|
const std::deque<int>&>::value,
|
|
"GetUnderlyingContainer(queue) should be of type deque");
|
|
EXPECT_THAT(GetUnderlyingContainer(queue),
|
|
testing::ElementsAre(1, 2, 3, 4, 5));
|
|
}
|
|
|
|
{
|
|
std::queue<int> queue;
|
|
EXPECT_THAT(GetUnderlyingContainer(queue), testing::ElementsAre());
|
|
}
|
|
|
|
{
|
|
base::queue<int> queue({1, 2, 3, 4, 5});
|
|
static_assert(
|
|
std::is_same<decltype(GetUnderlyingContainer(queue)),
|
|
const base::circular_deque<int>&>::value,
|
|
"GetUnderlyingContainer(queue) should be of type circular_deque");
|
|
EXPECT_THAT(GetUnderlyingContainer(queue),
|
|
testing::ElementsAre(1, 2, 3, 4, 5));
|
|
}
|
|
|
|
{
|
|
std::vector<int> values = {1, 2, 3, 4, 5};
|
|
std::priority_queue<int> queue(values.begin(), values.end());
|
|
static_assert(std::is_same<decltype(GetUnderlyingContainer(queue)),
|
|
const std::vector<int>&>::value,
|
|
"GetUnderlyingContainer(queue) should be of type vector");
|
|
EXPECT_THAT(GetUnderlyingContainer(queue),
|
|
testing::UnorderedElementsAre(1, 2, 3, 4, 5));
|
|
}
|
|
|
|
{
|
|
std::stack<int> stack({1, 2, 3, 4, 5});
|
|
static_assert(std::is_same<decltype(GetUnderlyingContainer(stack)),
|
|
const std::deque<int>&>::value,
|
|
"GetUnderlyingContainer(stack) should be of type deque");
|
|
EXPECT_THAT(GetUnderlyingContainer(stack),
|
|
testing::ElementsAre(1, 2, 3, 4, 5));
|
|
}
|
|
}
|
|
|
|
TEST(STLUtilTest, ConstCastIterator) {
|
|
// Sequence Containers
|
|
RunConstCastIteratorTest<std::forward_list<int>>();
|
|
RunConstCastIteratorTest<std::list<int>>();
|
|
RunConstCastIteratorTest<std::deque<int>>();
|
|
RunConstCastIteratorTest<std::vector<int>>();
|
|
RunConstCastIteratorTest<std::array<int, 5>>();
|
|
RunConstCastIteratorTest<int[5]>();
|
|
|
|
// Associative Containers
|
|
RunConstCastIteratorTest<std::set<int>>();
|
|
RunConstCastIteratorTest<std::multiset<int>>();
|
|
|
|
// Unordered Associative Containers
|
|
RunConstCastIteratorTest<std::unordered_set<int>>();
|
|
RunConstCastIteratorTest<std::unordered_multiset<int>>();
|
|
}
|
|
|
|
TEST(STLUtilTest, STLSetDifference) {
|
|
std::set<int> a1;
|
|
a1.insert(1);
|
|
a1.insert(2);
|
|
a1.insert(3);
|
|
a1.insert(4);
|
|
|
|
std::set<int> a2;
|
|
a2.insert(3);
|
|
a2.insert(4);
|
|
a2.insert(5);
|
|
a2.insert(6);
|
|
a2.insert(7);
|
|
|
|
{
|
|
std::set<int> difference;
|
|
difference.insert(1);
|
|
difference.insert(2);
|
|
EXPECT_EQ(difference, STLSetDifference<std::set<int> >(a1, a2));
|
|
}
|
|
|
|
{
|
|
std::set<int> difference;
|
|
difference.insert(5);
|
|
difference.insert(6);
|
|
difference.insert(7);
|
|
EXPECT_EQ(difference, STLSetDifference<std::set<int> >(a2, a1));
|
|
}
|
|
|
|
{
|
|
std::vector<int> difference;
|
|
difference.push_back(1);
|
|
difference.push_back(2);
|
|
EXPECT_EQ(difference, STLSetDifference<std::vector<int> >(a1, a2));
|
|
}
|
|
|
|
{
|
|
std::vector<int> difference;
|
|
difference.push_back(5);
|
|
difference.push_back(6);
|
|
difference.push_back(7);
|
|
EXPECT_EQ(difference, STLSetDifference<std::vector<int> >(a2, a1));
|
|
}
|
|
}
|
|
|
|
TEST(STLUtilTest, STLSetUnion) {
|
|
std::set<int> a1;
|
|
a1.insert(1);
|
|
a1.insert(2);
|
|
a1.insert(3);
|
|
a1.insert(4);
|
|
|
|
std::set<int> a2;
|
|
a2.insert(3);
|
|
a2.insert(4);
|
|
a2.insert(5);
|
|
a2.insert(6);
|
|
a2.insert(7);
|
|
|
|
{
|
|
std::set<int> result;
|
|
result.insert(1);
|
|
result.insert(2);
|
|
result.insert(3);
|
|
result.insert(4);
|
|
result.insert(5);
|
|
result.insert(6);
|
|
result.insert(7);
|
|
EXPECT_EQ(result, STLSetUnion<std::set<int> >(a1, a2));
|
|
}
|
|
|
|
{
|
|
std::set<int> result;
|
|
result.insert(1);
|
|
result.insert(2);
|
|
result.insert(3);
|
|
result.insert(4);
|
|
result.insert(5);
|
|
result.insert(6);
|
|
result.insert(7);
|
|
EXPECT_EQ(result, STLSetUnion<std::set<int> >(a2, a1));
|
|
}
|
|
|
|
{
|
|
std::vector<int> result;
|
|
result.push_back(1);
|
|
result.push_back(2);
|
|
result.push_back(3);
|
|
result.push_back(4);
|
|
result.push_back(5);
|
|
result.push_back(6);
|
|
result.push_back(7);
|
|
EXPECT_EQ(result, STLSetUnion<std::vector<int> >(a1, a2));
|
|
}
|
|
|
|
{
|
|
std::vector<int> result;
|
|
result.push_back(1);
|
|
result.push_back(2);
|
|
result.push_back(3);
|
|
result.push_back(4);
|
|
result.push_back(5);
|
|
result.push_back(6);
|
|
result.push_back(7);
|
|
EXPECT_EQ(result, STLSetUnion<std::vector<int> >(a2, a1));
|
|
}
|
|
}
|
|
|
|
TEST(STLUtilTest, STLSetIntersection) {
|
|
std::set<int> a1;
|
|
a1.insert(1);
|
|
a1.insert(2);
|
|
a1.insert(3);
|
|
a1.insert(4);
|
|
|
|
std::set<int> a2;
|
|
a2.insert(3);
|
|
a2.insert(4);
|
|
a2.insert(5);
|
|
a2.insert(6);
|
|
a2.insert(7);
|
|
|
|
{
|
|
std::set<int> result;
|
|
result.insert(3);
|
|
result.insert(4);
|
|
EXPECT_EQ(result, STLSetIntersection<std::set<int> >(a1, a2));
|
|
}
|
|
|
|
{
|
|
std::set<int> result;
|
|
result.insert(3);
|
|
result.insert(4);
|
|
EXPECT_EQ(result, STLSetIntersection<std::set<int> >(a2, a1));
|
|
}
|
|
|
|
{
|
|
std::vector<int> result;
|
|
result.push_back(3);
|
|
result.push_back(4);
|
|
EXPECT_EQ(result, STLSetIntersection<std::vector<int> >(a1, a2));
|
|
}
|
|
|
|
{
|
|
std::vector<int> result;
|
|
result.push_back(3);
|
|
result.push_back(4);
|
|
EXPECT_EQ(result, STLSetIntersection<std::vector<int> >(a2, a1));
|
|
}
|
|
}
|
|
|
|
TEST(Erase, IsNotIn) {
|
|
// Should keep both '2' but only one '4', like std::set_intersection.
|
|
std::vector<int> lhs = {0, 2, 2, 4, 4, 4, 6, 8, 10};
|
|
std::vector<int> rhs = {1, 2, 2, 4, 5, 6, 7};
|
|
std::vector<int> expected = {2, 2, 4, 6};
|
|
EXPECT_EQ(5u, EraseIf(lhs, IsNotIn<std::vector<int>>(rhs)));
|
|
EXPECT_EQ(expected, lhs);
|
|
}
|
|
|
|
} // namespace
|
|
} // namespace base
|