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