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