// Copyright 2020 The Pigweed 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 // // https://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 "pw_containers/vector.h" #include #include "gtest/gtest.h" #include "pw_containers_private/test_helpers.h" namespace pw { namespace { using namespace std::literals::string_view_literals; using containers::test::CopyOnly; using containers::test::Counter; using containers::test::MoveOnly; // Since pw::Vector downcasts to a pw::Vector, ensure that the // alignment doesn't change. static_assert(alignof(Vector) == alignof(Vector)); TEST(Vector, Construct_NoArg) { Vector vector; EXPECT_TRUE(vector.empty()); } TEST(Vector, Construct_MultipleCopies) { Vector vector(3, 123); EXPECT_EQ(vector.size(), 3u); EXPECT_EQ(vector[0], 123); EXPECT_EQ(vector[1], 123); EXPECT_EQ(vector[2], 123); } TEST(Vector, Construct_DefaultSize) { Vector vector(3); EXPECT_EQ(vector.size(), 3u); EXPECT_EQ(vector[0], 0); EXPECT_EQ(vector[1], 0); EXPECT_EQ(vector[2], 0); } TEST(Vector, Construct_Iterators) { std::array array{1, 2, 3, 4, 5}; Vector vector(array.begin(), array.end()); EXPECT_EQ(vector.size(), array.size()); for (unsigned short i = 0; i < array.size(); ++i) { EXPECT_EQ(vector[i], array[i]); } } TEST(Vector, Construct_Copy) { CopyOnly origin(5); Vector origin_vector(3, origin); Vector vector(origin_vector); EXPECT_EQ(3u, vector.size()); for (unsigned short i = 0; i < vector.size(); ++i) { EXPECT_EQ(vector[i].value, origin.value); } } TEST(Vector, Construct_Move) { Vector origin_vector; for (int i = 0; i < 5; ++i) { origin_vector.emplace_back(421); } Vector vector(std::move(origin_vector)); EXPECT_EQ(5u, vector.size()); for (unsigned short i = 0; i < vector.size(); ++i) { EXPECT_EQ(vector[i].value, 421); } // NOLINTNEXTLINE(bugprone-use-after-move) for (unsigned short i = 0; i < origin_vector.size(); ++i) { EXPECT_EQ(origin_vector[i].value, MoveOnly::kDeleted); } } TEST(Vector, Construct_InitializerList) { Vector vector{100, 200}; EXPECT_EQ(vector.size(), 2u); EXPECT_EQ(vector[0], 100); EXPECT_EQ(vector[1], 200); } struct Aggregate { int integer; Vector vector; }; TEST(Vector, Construct_String) { const auto vector = Vector{"Hello"}; EXPECT_EQ(5u, vector.size()); EXPECT_EQ("Hello"sv, std::string_view(vector.data(), vector.size())); } TEST(Vector, Construct_StringTruncates) { const auto vector = Vector{"Hello from a long string"}; EXPECT_EQ(8u, vector.size()); EXPECT_EQ("Hello fr"sv, std::string_view(vector.data(), vector.size())); } TEST(Vector, Construct_AssignFromString) { Vector vector = "Hello"; EXPECT_EQ(5u, vector.size()); EXPECT_EQ("Hello"sv, std::string_view(vector.data(), vector.size())); } TEST(Vector, Construct_AggregateString) { Aggregate aggregate = {.integer = 42, .vector = "Hello"}; EXPECT_EQ(5u, aggregate.vector.size()); EXPECT_EQ("Hello"sv, std::string_view(aggregate.vector.data(), aggregate.vector.size())); } TEST(Vector, Construct_StringView) { const auto vector = Vector{"Hello"sv}; EXPECT_EQ(5u, vector.size()); EXPECT_EQ("Hello"sv, std::string_view(vector.data(), vector.size())); } TEST(Vector, Construct_StringViewTruncates) { const auto vector = Vector{"Hello from a long string"sv}; EXPECT_EQ(8u, vector.size()); EXPECT_EQ("Hello fr"sv, std::string_view(vector.data(), vector.size())); } TEST(Vector, Construct_AssignFromStringView) { Vector vector = "Hello"sv; EXPECT_EQ(5u, vector.size()); EXPECT_EQ("Hello"sv, std::string_view(vector.data(), vector.size())); } TEST(Vector, Construct_AggregateStringView) { Aggregate aggregate = {.integer = 42, .vector = "Hello"sv}; EXPECT_EQ(5u, aggregate.vector.size()); EXPECT_EQ("Hello"sv, std::string_view(aggregate.vector.data(), aggregate.vector.size())); } TEST(Vector, Destruct_ZeroLength) { Counter::Reset(); { Vector destroyed; } EXPECT_EQ(Counter::created, 0); EXPECT_EQ(Counter::destroyed, 0); } TEST(Vector, Destruct_Empty) { Counter::Reset(); { Vector destroyed; } EXPECT_EQ(Counter::created, 0); EXPECT_EQ(Counter::destroyed, 0); } TEST(Vector, Destruct_MultpileEntries) { Counter value; Counter::Reset(); { Vector destroyed(100, value); } EXPECT_EQ(Counter::created, 100); EXPECT_EQ(Counter::destroyed, 100); } TEST(Vector, Assign_Copy_SmallerToLarger) { CopyOnly origin(5); Vector origin_vector(3, origin); Vector vector; vector = origin_vector; EXPECT_EQ(2u, vector.size()); for (unsigned short i = 0; i < vector.size(); ++i) { EXPECT_EQ(vector[i].value, origin.value); } } TEST(Vector, Assign_DifferentMaxSize_Copy) { const Vector origin_vector = {1, 1, 2, 3}; Vector vector; vector = origin_vector; ASSERT_EQ(4u, vector.size()); EXPECT_EQ(1, vector[0]); EXPECT_EQ(1, vector[1]); EXPECT_EQ(2, vector[2]); EXPECT_EQ(3, vector[3]); } TEST(Vector, Assign_SameMaxSize_Copy) { const Vector origin_vector = {1, 1, 2, 3}; Vector vector; vector = origin_vector; ASSERT_EQ(4u, vector.size()); EXPECT_EQ(1, vector[0]); EXPECT_EQ(1, vector[1]); EXPECT_EQ(2, vector[2]); EXPECT_EQ(3, vector[3]); } TEST(Vector, Assign_Generic_Copy) { const Vector origin_vector = {1, 1, 2, 3}; Vector vector; Vector& ref = vector; ref = static_cast&>(origin_vector); ASSERT_EQ(4u, vector.size()); EXPECT_EQ(1, vector[0]); EXPECT_EQ(1, vector[1]); EXPECT_EQ(2, vector[2]); EXPECT_EQ(3, vector[3]); } TEST(Vector, Assign_Move) { Vector origin_vector; for (int i = 0; i < 5; ++i) { origin_vector.emplace_back(421); } Vector vector; vector = std::move(origin_vector); EXPECT_EQ(5u, vector.size()); for (unsigned short i = 0; i < vector.size(); ++i) { EXPECT_EQ(vector[i].value, 421); } // NOLINTNEXTLINE(bugprone-use-after-move) for (unsigned short i = 0; i < origin_vector.size(); ++i) { EXPECT_EQ(origin_vector[i].value, MoveOnly::kDeleted); } } TEST(Vector, Assign_InitializerList) { Vector vector; vector = {1, 3, 5, 7, 9}; EXPECT_EQ(4u, vector.size()); EXPECT_EQ(1, vector[0]); EXPECT_EQ(3, vector[1]); EXPECT_EQ(5, vector[2]); EXPECT_EQ(7, vector[3]); } TEST(Vector, Access_ZeroLength) { Vector vector; EXPECT_EQ(0u, vector.size()); EXPECT_EQ(0u, vector.max_size()); EXPECT_TRUE(vector.empty()); EXPECT_TRUE(vector.full()); for (auto& item : vector) { (void)item; FAIL(); } } TEST(Vector, Access_Data_ArrayLocationIsIndependentOfMaxSize) { Vector vector; Vector& base = static_cast&>(vector); EXPECT_EQ(vector.data(), base.data()); EXPECT_EQ(vector.data(), (static_cast&>(base).data())); EXPECT_EQ(vector.data(), (static_cast&>(base).data())); } TEST(Vector, Modify_Clear) { Counter::Reset(); Vector vector; vector.emplace_back(); vector.emplace_back(); vector.emplace_back(); vector.clear(); EXPECT_EQ(3, Counter::created); EXPECT_EQ(3, Counter::destroyed); } TEST(Vector, Modify_PushBack_Copy) { Counter value(99); Counter::Reset(); { Vector vector; vector.push_back(value); EXPECT_EQ(vector.size(), 1u); EXPECT_EQ(vector.front().value, 99); } EXPECT_EQ(Counter::created, 1); EXPECT_EQ(Counter::destroyed, 1); } TEST(Vector, Modify_PushBack_Move) { Counter::Reset(); { Counter value(99); Vector vector; vector.push_back(std::move(value)); EXPECT_EQ(vector.size(), 1u); EXPECT_EQ(vector.front().value, 99); // NOLINTNEXTLINE(bugprone-use-after-move) EXPECT_EQ(value.value, 0); } EXPECT_EQ(Counter::created, 1); EXPECT_EQ(Counter::destroyed, 2); EXPECT_EQ(Counter::moved, 1); } TEST(Vector, Modify_EmplaceBack) { Counter::Reset(); { Vector vector; vector.emplace_back(314); EXPECT_EQ(vector.size(), 1u); EXPECT_EQ(vector.front().value, 314); } EXPECT_EQ(Counter::created, 1); EXPECT_EQ(Counter::destroyed, 1); } TEST(Vector, Modify_Resize_Larger) { Vector vector(1, CopyOnly(123)); vector.resize(3, CopyOnly(123)); EXPECT_EQ(vector.size(), 3u); for (auto& i : vector) { EXPECT_EQ(i.value, 123); } } TEST(Vector, Modify_Resize_LargerThanMax) { Vector vector; vector.resize(1000, CopyOnly(123)); EXPECT_EQ(vector.size(), 10u); for (auto& i : vector) { EXPECT_EQ(i.value, 123); } } TEST(Vector, Modify_Resize_Smaller) { Vector vector(9, CopyOnly(123)); vector.resize(3, CopyOnly(123)); EXPECT_EQ(vector.size(), 3u); for (auto& i : vector) { EXPECT_EQ(i.value, 123); } } TEST(Vector, Modify_PopBack) { Vector vector({Counter(1), Counter(2), Counter(3)}); Counter::Reset(); vector.pop_back(); EXPECT_EQ(vector.size(), 2u); EXPECT_EQ(vector[0].value, 1); EXPECT_EQ(vector[1].value, 2); EXPECT_EQ(Counter::created, 0); EXPECT_EQ(Counter::destroyed, 1); } TEST(Vector, Modify_Resize_Zero) { Vector vector(10, CopyOnly(123)); vector.resize(0, CopyOnly(123)); EXPECT_EQ(vector.size(), 0u); } TEST(Vector, Modify_Erase_TrivialRangeBegin) { Vector vector; for (size_t i = 0; i < vector.max_size(); ++i) { vector.emplace_back(i); } vector.erase(vector.begin() + 2, vector.end()); EXPECT_EQ(vector.size(), 2u); for (unsigned short i = 0; i < vector.size(); ++i) { EXPECT_EQ(vector[i], i); } } TEST(Vector, Modify_Erase_TrivialRangeEnd) { Vector vector; for (size_t i = 0; i < vector.max_size(); ++i) { vector.emplace_back(i); } vector.erase(vector.begin(), vector.end() - 2); EXPECT_EQ(vector.size(), 2u); for (unsigned short i = 0; i < vector.size(); ++i) { EXPECT_EQ(vector[i], 8u + i); } } TEST(Vector, Modify_Erase_TrivialSingleItem) { Vector vector; for (size_t i = 0; i < vector.max_size(); ++i) { vector.emplace_back(i); } vector.erase(vector.begin() + 9); EXPECT_EQ(vector.size(), 9u); EXPECT_EQ(vector.at(8), 8u); EXPECT_EQ(vector.at(0), 0u); vector.erase(vector.begin()); EXPECT_EQ(vector.size(), 8u); EXPECT_EQ(vector.at(0), 1u); } TEST(Vector, Modify_Erase_NonTrivialRangeBegin) { Counter::Reset(); Vector vector; for (size_t i = 0; i < vector.max_size(); ++i) { vector.emplace_back(static_cast(i)); } for (unsigned short i = 0; i < vector.size(); ++i) { EXPECT_EQ(vector[i].value, static_cast(i)); } vector.erase(vector.begin() + 2, vector.end()); EXPECT_EQ(vector.size(), 2u); for (unsigned short i = 0; i < vector.size(); ++i) { EXPECT_EQ(vector[i].value, static_cast(i)); } EXPECT_EQ(Counter::destroyed, 8); EXPECT_EQ(Counter::moved, 0); } TEST(Vector, Modify_Erase_NonTrivialRangeEnd) { Counter::Reset(); Vector vector; for (size_t i = 0; i < vector.max_size(); ++i) { vector.emplace_back(static_cast(i)); } vector.erase(vector.begin(), vector.end() - 2); EXPECT_EQ(vector.size(), 2u); for (unsigned short i = 0; i < vector.size(); ++i) { EXPECT_EQ(vector[i].value, static_cast(8u + i)); } EXPECT_EQ(Counter::destroyed, 8); EXPECT_EQ(Counter::moved, 2); } TEST(Vector, Modify_Erase_None) { Counter::Reset(); Vector vector; for (size_t i = 0; i < vector.max_size(); ++i) { vector.emplace_back(static_cast(i)); } vector.erase(vector.begin() + 2, vector.begin() + 2); EXPECT_EQ(vector.size(), 10u); EXPECT_EQ(Counter::destroyed, 0); EXPECT_EQ(Counter::moved, 0); EXPECT_EQ(Counter::created, 10); } TEST(Vector, Modify_Insert_End) { Counter::Reset(); Vector vector; for (int i = 0; i < 8; ++i) { vector.emplace_back(i); } EXPECT_EQ(vector.size(), 8u); EXPECT_EQ(Counter::created, 8); decltype(vector)::iterator it = vector.insert(vector.cend(), 8); EXPECT_EQ(it->value, 8); EXPECT_EQ(vector.at(8).value, 8); EXPECT_EQ(Counter::destroyed, 1); EXPECT_EQ(Counter::moved, 1); EXPECT_EQ(Counter::created, 9); } TEST(Vector, Modify_Insert_Begin) { Counter::Reset(); Vector vector; for (int i = 0; i < 8; ++i) { vector.emplace_back(i); } EXPECT_EQ(vector.size(), 8u); decltype(vector)::iterator it = vector.insert(vector.cbegin(), 123); EXPECT_EQ(it->value, 123); EXPECT_EQ(vector.at(0).value, 123); EXPECT_EQ(vector.at(8).value, 7); EXPECT_EQ(Counter::moved, 9); } TEST(Vector, Modify_Insert_CountCopies) { Counter::Reset(); Vector vector; vector.emplace_back(123); vector.insert(vector.cbegin() + 1, 8, Counter{421}); EXPECT_EQ(vector.at(0).value, 123); EXPECT_EQ(vector.size(), 9u); for (unsigned short i = 1; i < vector.size(); ++i) { EXPECT_EQ(vector[i].value, 421); } EXPECT_EQ(Counter::moved, 0); EXPECT_EQ(Counter::created, 10); } TEST(Vector, Modify_Insert_IteratorRange) { std::array array_to_insert_first{0, 1, 2, 8, 9}; std::array array_to_insert_middle{3, 4, 5, 6, 7}; Vector vector(array_to_insert_first.begin(), array_to_insert_first.end()); decltype(vector)::iterator it = vector.insert(vector.cbegin() + 3, array_to_insert_middle.begin(), array_to_insert_middle.end()); EXPECT_EQ(*it, array_to_insert_middle.front()); for (unsigned short i = 0; i < vector.max_size(); ++i) { EXPECT_EQ(vector[i], static_cast(i)); } } TEST(Vector, Modify_Insert_IteratorEmptyRange) { Vector src; Vector dst(10, 1); dst.insert(dst.end(), src.begin(), src.end()); EXPECT_EQ(dst.size(), 10U); EXPECT_EQ(dst.back(), 1); } TEST(Vector, Modify_Insert_InitializerListRange) { std::array array_to_insert_first{0, 1, 2, 8, 9}; Vector vector(array_to_insert_first.begin(), array_to_insert_first.end()); decltype(vector)::iterator it = vector.insert(vector.cbegin() + 3, {3, 4, 5, 6, 7}); EXPECT_EQ(*it, 3); for (unsigned short i = 0; i < vector.max_size(); ++i) { EXPECT_EQ(vector[i], static_cast(i)); } } TEST(Vector, Modify_Insert_NonTrivial_InitializerListRange) { std::array array_to_insert_first{0, 1, 2, 8, 9}; Vector vector(array_to_insert_first.begin(), array_to_insert_first.end()); decltype(vector)::iterator it = vector.insert( vector.cbegin() + 3, std::initializer_list{3, 4, 5, 6, 7}); EXPECT_EQ(it->value, 3); for (unsigned short i = 0; i < vector.max_size(); ++i) { EXPECT_EQ(vector[i].value, static_cast(i)); } } TEST(Vector, Generic) { Vector vector{1, 2, 3, 4, 5}; Vector& generic_vector(vector); EXPECT_EQ(generic_vector.size(), vector.size()); EXPECT_EQ(generic_vector.max_size(), vector.max_size()); unsigned short i = 0; for (int value : vector) { EXPECT_EQ(value, generic_vector[i]); i += 1; } i = 0; for (int value : generic_vector) { EXPECT_EQ(vector[i], value); i += 1; } } TEST(Vector, ConstexprMaxSize) { Vector vector; Vector vector2; EXPECT_EQ(vector.max_size(), vector2.max_size()); // The following code would fail with the following compiler error: // "non-type template argument is not a constant expression" // Reason: the generic_vector doesn't return a constexpr max_size value. // Vector& generic_vector(vector); // Vector vector3; } // Test that Vector is trivially destructible when its type is. static_assert(std::is_trivially_destructible_v>); static_assert(std::is_trivially_destructible_v>); static_assert(std::is_trivially_destructible_v); static_assert(std::is_trivially_destructible_v>); static_assert(std::is_trivially_destructible_v>); static_assert(std::is_trivially_destructible_v); static_assert(std::is_trivially_destructible_v>); static_assert(std::is_trivially_destructible_v>); static_assert(!std::is_trivially_destructible_v); static_assert(!std::is_trivially_destructible_v>); static_assert(!std::is_trivially_destructible_v>); } // namespace } // namespace pw