// Copyright 2012 The Chromium Authors. All rights reserved. // 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #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 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(c_it)>::value, "c_it is not a constant iterator."); static_assert(std::is_same())), 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, ToUnderlying) { enum Enum : int { kOne = 1, kTwo = 2, }; enum class ScopedEnum : char { kOne = 1, kTwo = 2, }; static_assert(std::is_same::value, ""); static_assert(std::is_same::value, ""); static_assert(to_underlying(kOne) == 1, ""); static_assert(to_underlying(kTwo) == 2, ""); static_assert( std::is_same::value, ""); static_assert( std::is_same::value, ""); static_assert(to_underlying(ScopedEnum::kOne) == 1, ""); static_assert(to_underlying(ScopedEnum::kTwo) == 2, ""); } TEST(STLUtilTest, GetUnderlyingContainer) { { std::queue queue({1, 2, 3, 4, 5}); static_assert(std::is_same&>::value, "GetUnderlyingContainer(queue) should be of type deque"); EXPECT_THAT(GetUnderlyingContainer(queue), testing::ElementsAre(1, 2, 3, 4, 5)); } { std::queue queue; EXPECT_THAT(GetUnderlyingContainer(queue), testing::ElementsAre()); } { base::queue queue({1, 2, 3, 4, 5}); static_assert( std::is_same&>::value, "GetUnderlyingContainer(queue) should be of type circular_deque"); EXPECT_THAT(GetUnderlyingContainer(queue), testing::ElementsAre(1, 2, 3, 4, 5)); } { std::vector values = {1, 2, 3, 4, 5}; std::priority_queue queue(values.begin(), values.end()); static_assert(std::is_same&>::value, "GetUnderlyingContainer(queue) should be of type vector"); EXPECT_THAT(GetUnderlyingContainer(queue), testing::UnorderedElementsAre(1, 2, 3, 4, 5)); } { std::stack stack({1, 2, 3, 4, 5}); static_assert(std::is_same&>::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>(); RunConstCastIteratorTest>(); RunConstCastIteratorTest>(); RunConstCastIteratorTest>(); RunConstCastIteratorTest>(); RunConstCastIteratorTest(); // Associative Containers RunConstCastIteratorTest>(); RunConstCastIteratorTest>(); // Unordered Associative Containers RunConstCastIteratorTest>(); RunConstCastIteratorTest>(); } TEST(STLUtilTest, STLSetDifference) { std::set a1; a1.insert(1); a1.insert(2); a1.insert(3); a1.insert(4); std::set a2; a2.insert(3); a2.insert(4); a2.insert(5); a2.insert(6); a2.insert(7); { std::set difference; difference.insert(1); difference.insert(2); EXPECT_EQ(difference, STLSetDifference >(a1, a2)); } { std::set difference; difference.insert(5); difference.insert(6); difference.insert(7); EXPECT_EQ(difference, STLSetDifference >(a2, a1)); } { std::vector difference; difference.push_back(1); difference.push_back(2); EXPECT_EQ(difference, STLSetDifference >(a1, a2)); } { std::vector difference; difference.push_back(5); difference.push_back(6); difference.push_back(7); EXPECT_EQ(difference, STLSetDifference >(a2, a1)); } } TEST(STLUtilTest, STLSetUnion) { std::set a1; a1.insert(1); a1.insert(2); a1.insert(3); a1.insert(4); std::set a2; a2.insert(3); a2.insert(4); a2.insert(5); a2.insert(6); a2.insert(7); { std::set 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 >(a1, a2)); } { std::set 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 >(a2, a1)); } { std::vector 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 >(a1, a2)); } { std::vector 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 >(a2, a1)); } } TEST(STLUtilTest, STLSetIntersection) { std::set a1; a1.insert(1); a1.insert(2); a1.insert(3); a1.insert(4); std::set a2; a2.insert(3); a2.insert(4); a2.insert(5); a2.insert(6); a2.insert(7); { std::set result; result.insert(3); result.insert(4); EXPECT_EQ(result, STLSetIntersection >(a1, a2)); } { std::set result; result.insert(3); result.insert(4); EXPECT_EQ(result, STLSetIntersection >(a2, a1)); } { std::vector result; result.push_back(3); result.push_back(4); EXPECT_EQ(result, STLSetIntersection >(a1, a2)); } { std::vector result; result.push_back(3); result.push_back(4); EXPECT_EQ(result, STLSetIntersection >(a2, a1)); } } TEST(Erase, IsNotIn) { // Should keep both '2' but only one '4', like std::set_intersection. std::vector lhs = {0, 2, 2, 4, 4, 4, 6, 8, 10}; std::vector rhs = {1, 2, 2, 4, 5, 6, 7}; std::vector expected = {2, 2, 4, 6}; EXPECT_EQ(5u, EraseIf(lhs, IsNotIn>(rhs))); EXPECT_EQ(expected, lhs); } TEST(STLUtilTest, OptionalOrNullptr) { absl::optional optional; EXPECT_EQ(nullptr, base::OptionalOrNullptr(optional)); optional = 0.1f; EXPECT_EQ(&optional.value(), base::OptionalOrNullptr(optional)); EXPECT_NE(nullptr, base::OptionalOrNullptr(optional)); } } // namespace } // namespace base