1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7 #include "mozilla/Queue.h"
8 #include "gtest/gtest.h"
9 #include <array>
10
11 using namespace mozilla;
12
13 namespace TestQueue {
14
15 struct Movable {
MovableTestQueue::Movable16 Movable() : mDestructionCounter(nullptr) {}
MovableTestQueue::Movable17 explicit Movable(uint32_t* aDestructionCounter)
18 : mDestructionCounter(aDestructionCounter) {}
19
~MovableTestQueue::Movable20 ~Movable() {
21 if (mDestructionCounter) {
22 (*mDestructionCounter)++;
23 }
24 }
25
MovableTestQueue::Movable26 Movable(Movable&& aOther) : mDestructionCounter(aOther.mDestructionCounter) {
27 aOther.mDestructionCounter = nullptr;
28 }
29
30 uint32_t* mDestructionCounter;
31 };
32
33 template <size_t N, size_t ItemsPerPage>
PushMovables(Queue<Movable,ItemsPerPage> & aQueue,std::array<uint32_t,N> & aDestructionCounters)34 void PushMovables(Queue<Movable, ItemsPerPage>& aQueue,
35 std::array<uint32_t, N>& aDestructionCounters) {
36 auto oldDestructionCounters = aDestructionCounters;
37 auto oldCount = aQueue.Count();
38 for (uint32_t i = 0; i < N; ++i) {
39 aQueue.Push(Movable(&aDestructionCounters[i]));
40 }
41 for (uint32_t i = 0; i < N; ++i) {
42 EXPECT_EQ(aDestructionCounters[i], oldDestructionCounters[i]);
43 }
44 EXPECT_EQ(aQueue.Count(), oldCount + N);
45 EXPECT_FALSE(aQueue.IsEmpty());
46 }
47
48 template <size_t N>
ExpectCounts(const std::array<uint32_t,N> & aDestructionCounters,uint32_t aExpected)49 void ExpectCounts(const std::array<uint32_t, N>& aDestructionCounters,
50 uint32_t aExpected) {
51 for (const auto& counters : aDestructionCounters) {
52 EXPECT_EQ(counters, aExpected);
53 }
54 }
55
TEST(Queue,Clear)56 TEST(Queue, Clear)
57 {
58 std::array<uint32_t, 32> counts{0};
59
60 Queue<Movable, 8> queue;
61 PushMovables(queue, counts);
62 queue.Clear();
63 ExpectCounts(counts, 1);
64 EXPECT_EQ(queue.Count(), 0u);
65 EXPECT_TRUE(queue.IsEmpty());
66 }
67
TEST(Queue,Destroy)68 TEST(Queue, Destroy)
69 {
70 std::array<uint32_t, 32> counts{0};
71
72 {
73 Queue<Movable, 8> queue;
74 PushMovables(queue, counts);
75 }
76 ExpectCounts(counts, 1u);
77 }
78
TEST(Queue,MoveConstruct)79 TEST(Queue, MoveConstruct)
80 {
81 std::array<uint32_t, 32> counts{0};
82
83 {
84 Queue<Movable, 8> queue;
85 PushMovables(queue, counts);
86
87 Queue<Movable, 8> queue2(std::move(queue));
88 EXPECT_EQ(queue2.Count(), 32u);
89 EXPECT_FALSE(queue2.IsEmpty());
90 // NOLINTNEXTLINE(bugprone-use-after-move, clang-analyzer-cplusplus.Move)
91 EXPECT_EQ(queue.Count(), 0u);
92 // NOLINTNEXTLINE(bugprone-use-after-move, clang-analyzer-cplusplus.Move)
93 EXPECT_TRUE(queue.IsEmpty());
94 ExpectCounts(counts, 0u);
95 }
96 ExpectCounts(counts, 1u);
97 }
98
TEST(Queue,MoveAssign)99 TEST(Queue, MoveAssign)
100 {
101 std::array<uint32_t, 32> counts{0};
102 std::array<uint32_t, 32> counts2{0};
103
104 {
105 Queue<Movable, 8> queue;
106 PushMovables(queue, counts);
107
108 {
109 Queue<Movable, 8> queue2;
110 PushMovables(queue2, counts2);
111
112 queue = std::move(queue2);
113 ExpectCounts(counts, 1);
114 ExpectCounts(counts2, 0);
115 EXPECT_EQ(queue.Count(), 32u);
116 EXPECT_FALSE(queue.IsEmpty());
117 // NOLINTNEXTLINE(bugprone-use-after-move, clang-analyzer-cplusplus.Move)
118 EXPECT_EQ(queue2.Count(), 0u);
119 // NOLINTNEXTLINE(bugprone-use-after-move, clang-analyzer-cplusplus.Move)
120 EXPECT_TRUE(queue2.IsEmpty());
121 }
122 ExpectCounts(counts, 1);
123 ExpectCounts(counts2, 0);
124 EXPECT_EQ(queue.Count(), 32u);
125 EXPECT_FALSE(queue.IsEmpty());
126 }
127 ExpectCounts(counts, 1);
128 ExpectCounts(counts2, 1);
129 }
130
TEST(Queue,PopOrder)131 TEST(Queue, PopOrder)
132 {
133 std::array<uint32_t, 32> counts{0};
134 Queue<Movable, 8> queue;
135 PushMovables(queue, counts);
136
137 for (auto& count : counts) {
138 EXPECT_EQ(count, 0u);
139 {
140 Movable popped = queue.Pop();
141 EXPECT_EQ(popped.mDestructionCounter, &count);
142 EXPECT_EQ(count, 0u);
143 }
144 EXPECT_EQ(count, 1u);
145 }
146 EXPECT_TRUE(queue.IsEmpty());
147 EXPECT_EQ(queue.Count(), 0u);
148 }
149
DoPushPopSequence(Queue<uint32_t,8> & aQueue,uint32_t & aInSerial,uint32_t & aOutSerial,uint32_t aPush,uint32_t aPop)150 void DoPushPopSequence(Queue<uint32_t, 8>& aQueue, uint32_t& aInSerial,
151 uint32_t& aOutSerial, uint32_t aPush, uint32_t aPop) {
152 auto initialCount = aQueue.Count();
153 for (uint32_t i = 0; i < aPush; ++i) {
154 aQueue.Push(aInSerial++);
155 }
156 EXPECT_EQ(aQueue.Count(), initialCount + aPush);
157 for (uint32_t i = 0; i < aPop; ++i) {
158 uint32_t popped = aQueue.Pop();
159 EXPECT_EQ(popped, aOutSerial++);
160 }
161 EXPECT_EQ(aQueue.Count(), initialCount + aPush - aPop);
162 }
163
PushPopPushPop(uint32_t aPush1,uint32_t aPop1,uint32_t aPush2,uint32_t aPop2)164 void PushPopPushPop(uint32_t aPush1, uint32_t aPop1, uint32_t aPush2,
165 uint32_t aPop2) {
166 Queue<uint32_t, 8> queue;
167 uint32_t inSerial = 0;
168 uint32_t outSerial = 0;
169 DoPushPopSequence(queue, inSerial, outSerial, aPush1, aPop1);
170 DoPushPopSequence(queue, inSerial, outSerial, aPush2, aPop2);
171 }
172
TEST(Queue,PushPopSequence)173 TEST(Queue, PushPopSequence)
174 {
175 for (uint32_t push1 = 0; push1 < 16; ++push1) {
176 for (uint32_t pop1 = 0; pop1 < push1; ++pop1) {
177 for (uint32_t push2 = 0; push2 < 16; ++push2) {
178 for (uint32_t pop2 = 0; pop2 < push1 - pop1 + push2; ++pop2) {
179 PushPopPushPop(push1, pop1, push2, pop2);
180 }
181 }
182 }
183 }
184 }
185
186 } // namespace TestQueue
187