blob: d04a4e65717af6f17c62ccff94c5c7e91ff14ab7 [file]
// Copyright 2026 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 <array>
#include <cstddef>
#include "pw_containers/deque.h"
#include "pw_containers/pod_deque.h"
#include "pw_unit_test/framework.h"
namespace pw::containers {
namespace {
TEST(PodDeque, PushBack) {
FixedDeque<int, 3> deque;
EXPECT_TRUE(deque.empty());
EXPECT_FALSE(deque.full());
EXPECT_EQ(deque.size(), 0u);
deque.push_back(5);
EXPECT_EQ(deque.size(), 1u);
EXPECT_EQ(deque.front(), 5);
EXPECT_EQ(deque.back(), 5);
deque.push_back(2);
EXPECT_EQ(deque.size(), 2u);
EXPECT_EQ(deque.back(), 2);
}
TEST(PodDeque, PopBack) {
FixedDeque<int, 3> deque;
deque.push_back(45);
deque.push_back(2);
deque.pop_back();
EXPECT_EQ(deque.size(), 1u);
EXPECT_EQ(deque.front(), 45);
}
TEST(PodDeque, PushFront) {
FixedDeque<int, 3> deque;
deque.push_front(3);
EXPECT_EQ(deque.size(), 1u);
EXPECT_EQ(deque.front(), 3);
EXPECT_EQ(deque.back(), 3);
deque.push_front(2);
EXPECT_EQ(deque.size(), 2u);
EXPECT_EQ(deque.front(), 2);
}
TEST(PodDeque, PopFront) {
FixedDeque<int, 3> deque;
deque.push_back(1);
deque.push_back(2);
deque.pop_front();
EXPECT_EQ(deque.size(), 1u);
EXPECT_EQ(deque.front(), 2);
}
TEST(PodDeque, InheritanceBehavior) {
// For POD types, FixedDeque should inherit from PodDeque
using PodFixedDeque = FixedDeque<int, 10>;
using ExpectedPodBase = PodDeque<int, uint16_t>;
static_assert(std::is_base_of_v<ExpectedPodBase, PodFixedDeque>,
"FixedDeque with POD type should inherit from PodDeque");
// For Non-POD types, FixedDeque should inherit from Deque
struct NonPod {
int id_;
int value_;
NonPod(int id, int value) : id_(id), value_(value) {}
~NonPod() {}
};
using NonPodFixedDeque = FixedDeque<NonPod, 10>;
using ExpectedNonPodBase = Deque<NonPod, uint16_t>;
static_assert(std::is_base_of_v<ExpectedNonPodBase, NonPodFixedDeque>,
"FixedDeque with Non-POD type should inherit from Deque");
}
TEST(PodDeque, ComplexPod) {
struct ComplexPod {
int id;
int value;
};
using PodFixedDeque = FixedDeque<ComplexPod, 3>;
using ExpectedPodBase = PodDeque<ComplexPod, uint16_t>;
static_assert(std::is_base_of_v<ExpectedPodBase, PodFixedDeque>,
"FixedDeque with ComplexPod should inherit from PodDeque");
FixedDeque<ComplexPod, 3> deque;
deque.push_back({1, 10});
deque.push_back({2, 20});
EXPECT_EQ(deque.size(), 2u);
EXPECT_EQ(deque.front().id, 1);
EXPECT_EQ(deque.front().value, 10);
EXPECT_EQ(deque.back().id, 2);
EXPECT_EQ(deque.back().value, 20);
deque.pop_front();
EXPECT_EQ(deque.size(), 1u);
EXPECT_EQ(deque.front().id, 2);
EXPECT_EQ(deque.front().value, 20);
}
TEST(PodDeque, MaxSize) {
FixedDeque<int, 7> deque;
EXPECT_EQ(deque.max_size(), 7u);
EXPECT_EQ(deque.capacity(), 7u);
}
TEST(PodDeque, Assign) {
FixedDeque<int, 5> deque;
deque.push_back(99);
deque.push_back(100);
std::array<int, 3> new_data = {5, 10, 15};
deque.assign(new_data.begin(), new_data.end());
EXPECT_EQ(deque.size(), 3u);
EXPECT_EQ(deque.front(), 5);
EXPECT_EQ(deque.back(), 15);
}
TEST(PodDeque, Clear) {
FixedDeque<int, 4> deque;
deque.push_back(1);
deque.push_back(2);
EXPECT_FALSE(deque.empty());
deque.clear();
EXPECT_TRUE(deque.empty());
EXPECT_EQ(deque.size(), 0u);
}
TEST(PodDeque, Resize) {
FixedDeque<int, 5> deque;
deque.push_back(42);
deque.resize(3);
EXPECT_EQ(deque.size(), 3u);
EXPECT_EQ(deque.front(), 42);
EXPECT_EQ(deque.back(), 0);
deque.resize(1);
EXPECT_EQ(deque.size(), 1u);
EXPECT_EQ(deque.front(), 42);
}
TEST(PodDeque, NonPodAssignAndResize) {
struct TestNonPod {
int val_;
TestNonPod() : val_(0) {}
TestNonPod(int v) : val_(v) {}
~TestNonPod() {}
};
FixedDeque<TestNonPod, 5> deque;
deque.push_back(10);
deque.push_back(20);
std::array<TestNonPod, 2> source = {5, 15};
deque.assign(source.begin(), source.end());
EXPECT_EQ(deque.size(), 2u);
EXPECT_EQ(deque.front().val_, 5);
EXPECT_EQ(deque.back().val_, 15);
deque.resize(4, TestNonPod(99));
EXPECT_EQ(deque.size(), 4u);
EXPECT_EQ(deque.back().val_, 99);
}
TEST(PodDeque, MoveConstructorSameCapacity) {
FixedDeque<int, 5> deque1;
for (int i = 1; i <= 5; ++i)
deque1.push_back(i);
deque1.pop_front();
deque1.pop_front();
deque1.push_back(6); // [6, (empty), 3, 4, 5] (head=2, tail=1, count=4)
FixedDeque<int, 5> dest(std::move(deque1));
EXPECT_EQ(dest.size(), 4u);
EXPECT_EQ(dest.front(), 3);
EXPECT_EQ(dest.back(), 6);
EXPECT_TRUE(deque1.empty()); // NOLINT(bugprone-use-after-move)
}
TEST(PodDeque, MoveConstructorDifferentCapacity) {
FixedDeque<int, 5> deque1;
for (int i = 1; i <= 5; ++i)
deque1.push_back(i);
deque1.pop_front();
deque1.pop_front();
deque1.push_back(6); // wrapped!
FixedDeque<int, 10> dest(std::move(deque1));
EXPECT_EQ(dest.size(), 4u);
EXPECT_EQ(dest.front(), 3);
EXPECT_EQ(dest.back(), 6);
EXPECT_TRUE(deque1.empty()); // NOLINT(bugprone-use-after-move)
}
TEST(PodDeque, MoveAssignmentSameCapacity) {
FixedDeque<int, 5> deque1;
for (int i = 1; i <= 5; ++i)
deque1.push_back(i);
deque1.pop_front();
deque1.pop_front();
deque1.push_back(6); // wrapped!
FixedDeque<int, 5> dest;
dest.push_back(99);
dest = std::move(deque1);
EXPECT_EQ(dest.size(), 4u);
EXPECT_EQ(dest.front(), 3);
EXPECT_EQ(dest.back(), 6);
EXPECT_TRUE(deque1.empty()); // NOLINT(bugprone-use-after-move)
}
TEST(PodDeque, MoveAssignmentDifferentCapacity) {
FixedDeque<int, 5> deque1;
for (int i = 1; i <= 5; ++i)
deque1.push_back(i);
deque1.pop_front();
deque1.pop_front();
deque1.push_back(6); // wrapped!
FixedDeque<int, 10> dest;
dest.push_back(99);
dest = std::move(deque1);
EXPECT_EQ(dest.size(), 4u);
EXPECT_EQ(dest.front(), 3);
EXPECT_EQ(dest.back(), 6);
EXPECT_TRUE(deque1.empty()); // NOLINT(bugprone-use-after-move)
}
TEST(PodDeque, SwapSameCapacity) {
FixedDeque<int, 5> deque1;
deque1.push_back(1);
deque1.push_back(2);
FixedDeque<int, 5> deque2;
deque2.push_back(10);
deque2.push_back(20);
deque2.push_back(30);
deque1.swap(deque2);
EXPECT_EQ(deque1.size(), 3u);
EXPECT_EQ(deque1.front(), 10);
EXPECT_EQ(deque1.back(), 30);
EXPECT_EQ(deque2.size(), 2u);
EXPECT_EQ(deque2.front(), 1);
EXPECT_EQ(deque2.back(), 2);
}
TEST(PodDeque, SwapDifferentCapacity) {
FixedDeque<int, 15> deque1;
deque1.push_back(1);
deque1.push_back(2);
FixedDeque<int, 10> deque2;
deque2.push_back(10);
deque2.push_back(20);
deque2.push_back(30);
EXPECT_EQ(deque1.capacity(), 15u);
EXPECT_EQ(deque2.capacity(), 10u);
deque1.swap(deque2);
EXPECT_EQ(deque1.capacity(), 15u);
EXPECT_EQ(deque2.capacity(), 10u);
EXPECT_EQ(deque1.size(), 3u);
EXPECT_EQ(deque1.front(), 10);
EXPECT_EQ(deque1.back(), 30);
EXPECT_EQ(deque2.size(), 2u);
EXPECT_EQ(deque2.front(), 1);
EXPECT_EQ(deque2.back(), 2);
}
TEST(PodDeque, UnalignedBuffer) {
alignas(uint64_t) std::array<std::byte, sizeof(uint64_t) * 8> buffer = {};
for (size_t i = 0; i <= sizeof(uint64_t); ++i) {
PodDeque<uint64_t> deque(pw::span<std::byte>(buffer).subspan(i));
EXPECT_EQ(deque.capacity(), (i == 0) ? 8u : 7u);
deque.push_back(600613u);
void* first_item = &deque.front();
EXPECT_EQ(reinterpret_cast<uintptr_t>(first_item) % alignof(uint64_t), 0u)
<< "Deque items should be correctly aligned";
EXPECT_EQ(deque.front(), 600613u);
}
}
TEST(PodDeque, UnalignedBuffer_EmptyDueToAlignment) {
alignas(uint64_t) std::array<std::byte, sizeof(uint64_t) + 1> buffer = {};
auto unaligned = pw::span(buffer).subspan(1);
ASSERT_EQ(unaligned.size(), sizeof(uint64_t));
PodDeque<uint64_t> deque(unaligned);
EXPECT_EQ(deque.capacity(), 0u);
}
} // namespace
} // namespace pw::containers