1 /* Apache License, Version 2.0 */
2 
3 #include "BLI_exception_safety_test_utils.hh"
4 #include "BLI_stack.hh"
5 #include "BLI_strict_flags.h"
6 #include "BLI_vector.hh"
7 #include "testing/testing.h"
8 
9 namespace blender::tests {
10 
TEST(stack,DefaultConstructor)11 TEST(stack, DefaultConstructor)
12 {
13   Stack<int> stack;
14   EXPECT_EQ(stack.size(), 0);
15   EXPECT_TRUE(stack.is_empty());
16 }
17 
TEST(stack,SpanConstructor)18 TEST(stack, SpanConstructor)
19 {
20   std::array<int, 3> array = {4, 7, 2};
21   Stack<int> stack(array);
22   EXPECT_EQ(stack.size(), 3);
23   EXPECT_EQ(stack.pop(), 2);
24   EXPECT_EQ(stack.pop(), 7);
25   EXPECT_EQ(stack.pop(), 4);
26   EXPECT_TRUE(stack.is_empty());
27 }
28 
TEST(stack,CopyConstructor)29 TEST(stack, CopyConstructor)
30 {
31   Stack<int> stack1 = {1, 2, 3, 4, 5, 6, 7};
32   Stack<int> stack2 = stack1;
33   EXPECT_EQ(stack1.size(), 7);
34   EXPECT_EQ(stack2.size(), 7);
35   for (int i = 7; i >= 1; i--) {
36     EXPECT_FALSE(stack1.is_empty());
37     EXPECT_FALSE(stack2.is_empty());
38     EXPECT_EQ(stack1.pop(), i);
39     EXPECT_EQ(stack2.pop(), i);
40   }
41   EXPECT_TRUE(stack1.is_empty());
42   EXPECT_TRUE(stack2.is_empty());
43 }
44 
TEST(stack,MoveConstructor)45 TEST(stack, MoveConstructor)
46 {
47   Stack<int> stack1 = {1, 2, 3, 4, 5, 6, 7};
48   Stack<int> stack2 = std::move(stack1);
49   EXPECT_EQ(stack1.size(), 0); /* NOLINT: bugprone-use-after-move */
50   EXPECT_EQ(stack2.size(), 7);
51   for (int i = 7; i >= 1; i--) {
52     EXPECT_EQ(stack2.pop(), i);
53   }
54 }
55 
TEST(stack,CopyAssignment)56 TEST(stack, CopyAssignment)
57 {
58   Stack<int> stack1 = {1, 2, 3, 4, 5, 6, 7};
59   Stack<int> stack2 = {2, 3, 4, 5, 6, 7};
60   stack2 = stack1;
61 
62   EXPECT_EQ(stack1.size(), 7);
63   EXPECT_EQ(stack2.size(), 7);
64   for (int i = 7; i >= 1; i--) {
65     EXPECT_FALSE(stack1.is_empty());
66     EXPECT_FALSE(stack2.is_empty());
67     EXPECT_EQ(stack1.pop(), i);
68     EXPECT_EQ(stack2.pop(), i);
69   }
70   EXPECT_TRUE(stack1.is_empty());
71   EXPECT_TRUE(stack2.is_empty());
72 }
73 
TEST(stack,MoveAssignment)74 TEST(stack, MoveAssignment)
75 {
76   Stack<int> stack1 = {1, 2, 3, 4, 5, 6, 7};
77   Stack<int> stack2 = {5, 3, 7, 2, 2};
78   stack2 = std::move(stack1);
79   EXPECT_EQ(stack1.size(), 0); /* NOLINT: bugprone-use-after-move */
80   EXPECT_EQ(stack2.size(), 7);
81   for (int i = 7; i >= 1; i--) {
82     EXPECT_EQ(stack2.pop(), i);
83   }
84 }
85 
TEST(stack,Push)86 TEST(stack, Push)
87 {
88   Stack<int> stack;
89   EXPECT_EQ(stack.size(), 0);
90   stack.push(3);
91   EXPECT_EQ(stack.size(), 1);
92   stack.push(5);
93   EXPECT_EQ(stack.size(), 2);
94 }
95 
TEST(stack,PushMultiple)96 TEST(stack, PushMultiple)
97 {
98   Stack<int> stack;
99   EXPECT_EQ(stack.size(), 0);
100   stack.push_multiple({1, 2, 3});
101   EXPECT_EQ(stack.size(), 3);
102   EXPECT_EQ(stack.pop(), 3);
103   EXPECT_EQ(stack.pop(), 2);
104   EXPECT_EQ(stack.pop(), 1);
105 }
106 
TEST(stack,PushPopMany)107 TEST(stack, PushPopMany)
108 {
109   Stack<int> stack;
110   for (int i = 0; i < 1000; i++) {
111     stack.push(i);
112     EXPECT_EQ(stack.size(), static_cast<unsigned int>(i + 1));
113   }
114   for (int i = 999; i > 50; i--) {
115     EXPECT_EQ(stack.pop(), i);
116     EXPECT_EQ(stack.size(), static_cast<unsigned int>(i));
117   }
118   for (int i = 51; i < 5000; i++) {
119     stack.push(i);
120     EXPECT_EQ(stack.size(), static_cast<unsigned int>(i + 1));
121   }
122   for (int i = 4999; i >= 0; i--) {
123     EXPECT_EQ(stack.pop(), i);
124     EXPECT_EQ(stack.size(), static_cast<unsigned int>(i));
125   }
126 }
127 
TEST(stack,PushMultipleAfterPop)128 TEST(stack, PushMultipleAfterPop)
129 {
130   Stack<int> stack;
131   for (int i = 0; i < 1000; i++) {
132     stack.push(i);
133   }
134   for (int i = 999; i >= 0; i--) {
135     EXPECT_EQ(stack.pop(), i);
136   }
137 
138   Vector<int> values;
139   for (int i = 0; i < 5000; i++) {
140     values.append(i);
141   }
142   stack.push_multiple(values);
143   EXPECT_EQ(stack.size(), 5000);
144 
145   for (int i = 4999; i >= 0; i--) {
146     EXPECT_EQ(stack.pop(), i);
147   }
148 }
149 
TEST(stack,Pop)150 TEST(stack, Pop)
151 {
152   Stack<int> stack;
153   stack.push(4);
154   stack.push(6);
155   EXPECT_EQ(stack.pop(), 6);
156   EXPECT_EQ(stack.pop(), 4);
157 }
158 
TEST(stack,Peek)159 TEST(stack, Peek)
160 {
161   Stack<int> stack;
162   stack.push(3);
163   stack.push(4);
164   EXPECT_EQ(stack.peek(), 4);
165   EXPECT_EQ(stack.peek(), 4);
166   stack.pop();
167   EXPECT_EQ(stack.peek(), 3);
168 }
169 
TEST(stack,UniquePtrValues)170 TEST(stack, UniquePtrValues)
171 {
172   Stack<std::unique_ptr<int>> stack;
173   stack.push(std::unique_ptr<int>(new int()));
174   stack.push(std::unique_ptr<int>(new int()));
175   std::unique_ptr<int> a = stack.pop();
176   std::unique_ptr<int> &b = stack.peek();
177   UNUSED_VARS(a, b);
178 }
179 
TEST(stack,OveralignedValues)180 TEST(stack, OveralignedValues)
181 {
182   Stack<AlignedBuffer<1, 512>, 2> stack;
183   for (int i = 0; i < 100; i++) {
184     stack.push({});
185     EXPECT_EQ((uintptr_t)&stack.peek() % 512, 0);
186   }
187 }
188 
TEST(stack,SpanConstructorExceptions)189 TEST(stack, SpanConstructorExceptions)
190 {
191   std::array<ExceptionThrower, 5> values;
192   values[3].throw_during_copy = true;
193   EXPECT_ANY_THROW({ Stack<ExceptionThrower> stack(values); });
194 }
195 
TEST(stack,MoveConstructorExceptions)196 TEST(stack, MoveConstructorExceptions)
197 {
198   Stack<ExceptionThrower, 4> stack;
199   stack.push({});
200   stack.push({});
201   stack.peek().throw_during_move = true;
202   EXPECT_ANY_THROW({ Stack<ExceptionThrower> moved_stack{std::move(stack)}; });
203 }
204 
TEST(stack,PushExceptions)205 TEST(stack, PushExceptions)
206 {
207   Stack<ExceptionThrower, 2> stack;
208   stack.push({});
209   stack.push({});
210   ExceptionThrower *ptr1 = &stack.peek();
211   ExceptionThrower value;
212   value.throw_during_copy = true;
213   EXPECT_ANY_THROW({ stack.push(value); });
214   EXPECT_EQ(stack.size(), 2);
215   ExceptionThrower *ptr2 = &stack.peek();
216   EXPECT_EQ(ptr1, ptr2);
217   EXPECT_TRUE(stack.is_invariant_maintained());
218 }
219 
TEST(stack,PopExceptions)220 TEST(stack, PopExceptions)
221 {
222   Stack<ExceptionThrower> stack;
223   stack.push({});
224   stack.peek().throw_during_move = true;
225   stack.push({});
226   stack.pop();                        /* NOLINT: bugprone-throw-keyword-missing */
227   EXPECT_ANY_THROW({ stack.pop(); }); /* NOLINT: bugprone-throw-keyword-missing */
228   EXPECT_EQ(stack.size(), 1);
229   EXPECT_TRUE(stack.is_invariant_maintained());
230 }
231 
TEST(stack,PushMultipleExceptions)232 TEST(stack, PushMultipleExceptions)
233 {
234   Stack<ExceptionThrower> stack;
235   stack.push({});
236   std::array<ExceptionThrower, 100> values;
237   values[6].throw_during_copy = true;
238   EXPECT_ANY_THROW({ stack.push_multiple(values); });
239   EXPECT_TRUE(stack.is_invariant_maintained());
240   EXPECT_ANY_THROW({ stack.push_multiple(values); });
241   EXPECT_TRUE(stack.is_invariant_maintained());
242 }
243 
244 }  // namespace blender::tests
245