1 /* Apache License, Version 2.0 */
2
3 #include "BLI_array.hh"
4 #include "BLI_exception_safety_test_utils.hh"
5 #include "BLI_strict_flags.h"
6 #include "BLI_vector.hh"
7 #include "testing/testing.h"
8
9 namespace blender::tests {
10
TEST(array,DefaultConstructor)11 TEST(array, DefaultConstructor)
12 {
13 Array<int> array;
14 EXPECT_EQ(array.size(), 0);
15 EXPECT_TRUE(array.is_empty());
16 }
17
TEST(array,SizeConstructor)18 TEST(array, SizeConstructor)
19 {
20 Array<int> array(5);
21 EXPECT_EQ(array.size(), 5);
22 EXPECT_FALSE(array.is_empty());
23 }
24
TEST(array,FillConstructor)25 TEST(array, FillConstructor)
26 {
27 Array<int> array(5, 8);
28 EXPECT_EQ(array.size(), 5);
29 EXPECT_EQ(array[0], 8);
30 EXPECT_EQ(array[1], 8);
31 EXPECT_EQ(array[2], 8);
32 EXPECT_EQ(array[3], 8);
33 EXPECT_EQ(array[4], 8);
34 }
35
TEST(array,InitializerListConstructor)36 TEST(array, InitializerListConstructor)
37 {
38 Array<int> array = {4, 5, 6, 7};
39 EXPECT_EQ(array.size(), 4);
40 EXPECT_EQ(array[0], 4);
41 EXPECT_EQ(array[1], 5);
42 EXPECT_EQ(array[2], 6);
43 EXPECT_EQ(array[3], 7);
44 }
45
TEST(array,SpanConstructor)46 TEST(array, SpanConstructor)
47 {
48 int stackarray[4] = {6, 7, 8, 9};
49 Span<int> span(stackarray, ARRAY_SIZE(stackarray));
50 Array<int> array(span);
51 EXPECT_EQ(array.size(), 4);
52 EXPECT_EQ(array[0], 6);
53 EXPECT_EQ(array[1], 7);
54 EXPECT_EQ(array[2], 8);
55 EXPECT_EQ(array[3], 9);
56 }
57
TEST(array,CopyConstructor)58 TEST(array, CopyConstructor)
59 {
60 Array<int> array = {5, 6, 7, 8};
61 Array<int> new_array(array);
62
63 EXPECT_EQ(array.size(), 4);
64 EXPECT_EQ(new_array.size(), 4);
65 EXPECT_NE(array.data(), new_array.data());
66 EXPECT_EQ(new_array[0], 5);
67 EXPECT_EQ(new_array[1], 6);
68 EXPECT_EQ(new_array[2], 7);
69 EXPECT_EQ(new_array[3], 8);
70 }
71
TEST(array,MoveConstructor)72 TEST(array, MoveConstructor)
73 {
74 Array<int> array = {5, 6, 7, 8};
75 Array<int> new_array(std::move(array));
76
77 EXPECT_EQ(array.size(), 0); /* NOLINT: bugprone-use-after-move */
78 EXPECT_EQ(new_array.size(), 4);
79 EXPECT_EQ(new_array[0], 5);
80 EXPECT_EQ(new_array[1], 6);
81 EXPECT_EQ(new_array[2], 7);
82 EXPECT_EQ(new_array[3], 8);
83 }
84
TEST(array,CopyAssignment)85 TEST(array, CopyAssignment)
86 {
87 Array<int> array = {1, 2, 3};
88 Array<int> new_array = {4};
89 EXPECT_EQ(new_array.size(), 1);
90 new_array = array;
91 EXPECT_EQ(new_array.size(), 3);
92 EXPECT_EQ(array.size(), 3);
93 EXPECT_NE(array.data(), new_array.data());
94 EXPECT_EQ(new_array[0], 1);
95 EXPECT_EQ(new_array[1], 2);
96 EXPECT_EQ(new_array[2], 3);
97 }
98
TEST(array,MoveAssignment)99 TEST(array, MoveAssignment)
100 {
101 Array<int> array = {1, 2, 3};
102 Array<int> new_array = {4};
103 EXPECT_EQ(new_array.size(), 1);
104 new_array = std::move(array);
105 EXPECT_EQ(new_array.size(), 3);
106 EXPECT_EQ(array.size(), 0); /* NOLINT: bugprone-use-after-move */
107 EXPECT_EQ(new_array[0], 1);
108 EXPECT_EQ(new_array[1], 2);
109 EXPECT_EQ(new_array[2], 3);
110 }
111
112 /**
113 * Tests that the trivially constructible types are not zero-initialized. We do not want that for
114 * performance reasons.
115 */
TEST(array,TrivialTypeSizeConstructor)116 TEST(array, TrivialTypeSizeConstructor)
117 {
118 Array<char, 1> *array = new Array<char, 1>(1);
119 char *ptr = &(*array)[0];
120 array->~Array();
121
122 const char magic = 42;
123 *ptr = magic;
124 EXPECT_EQ(*ptr, magic);
125
126 new (array) Array<char, 1>(1);
127 EXPECT_EQ((*array)[0], magic);
128 EXPECT_EQ(*ptr, magic);
129 delete array;
130 }
131
132 struct ConstructibleType {
133 char value;
134
ConstructibleTypeblender::tests::ConstructibleType135 ConstructibleType()
136 {
137 value = 42;
138 }
139 };
140
TEST(array,NoInitializationSizeConstructor)141 TEST(array, NoInitializationSizeConstructor)
142 {
143 using MyArray = Array<ConstructibleType>;
144
145 TypedBuffer<MyArray> buffer;
146 memset((void *)&buffer, 100, sizeof(MyArray));
147
148 /* Doing this to avoid some compiler optimization. */
149 for (int64_t i : IndexRange(sizeof(MyArray))) {
150 EXPECT_EQ(((char *)buffer.ptr())[i], 100);
151 }
152
153 {
154 MyArray &array = *new (buffer) MyArray(1, NoInitialization());
155 EXPECT_EQ(array[0].value, 100);
156 array.clear_without_destruct();
157 array.~Array();
158 }
159 {
160 MyArray &array = *new (buffer) MyArray(1);
161 EXPECT_EQ(array[0].value, 42);
162 array.~Array();
163 }
164 }
165
TEST(array,Fill)166 TEST(array, Fill)
167 {
168 Array<int> array(5);
169 array.fill(3);
170 EXPECT_EQ(array.size(), 5u);
171 EXPECT_EQ(array[0], 3);
172 EXPECT_EQ(array[1], 3);
173 EXPECT_EQ(array[2], 3);
174 EXPECT_EQ(array[3], 3);
175 EXPECT_EQ(array[4], 3);
176 }
177
TEST(array,ReverseIterator)178 TEST(array, ReverseIterator)
179 {
180 Array<int> array = {3, 4, 5, 6};
181 Vector<int> reversed_vec;
182
183 for (auto it = array.rbegin(); it != array.rend(); ++it) {
184 reversed_vec.append(*it);
185 *it += 10;
186 }
187
188 EXPECT_EQ_ARRAY(reversed_vec.data(), Span({6, 5, 4, 3}).data(), 4);
189 EXPECT_EQ_ARRAY(array.data(), Span({13, 14, 15, 16}).data(), 4);
190 }
191
TEST(array,SpanConstructorExceptions)192 TEST(array, SpanConstructorExceptions)
193 {
194 std::array<ExceptionThrower, 4> values;
195 values[2].throw_during_copy = true;
196 Span<ExceptionThrower> span{values};
197 EXPECT_ANY_THROW({ Array<ExceptionThrower> array(span); });
198 }
199
TEST(array,SizeValueConstructorExceptions)200 TEST(array, SizeValueConstructorExceptions)
201 {
202 ExceptionThrower value;
203 value.throw_during_copy = true;
204 EXPECT_ANY_THROW({ Array<ExceptionThrower> array(5, value); });
205 }
206
TEST(array,MoveConstructorExceptions)207 TEST(array, MoveConstructorExceptions)
208 {
209 Array<ExceptionThrower, 4> array(3);
210 array[1].throw_during_move = true;
211 EXPECT_ANY_THROW({ Array<ExceptionThrower> array_copy(std::move(array)); });
212 }
213
TEST(array,CopyAssignmentExceptions)214 TEST(array, CopyAssignmentExceptions)
215 {
216 Array<ExceptionThrower> array(5);
217 array[3].throw_during_copy = true;
218 Array<ExceptionThrower> array_copy(10);
219 EXPECT_ANY_THROW({ array_copy = array; });
220 }
221
TEST(array,MoveAssignmentExceptions)222 TEST(array, MoveAssignmentExceptions)
223 {
224 Array<ExceptionThrower, 4> array(4);
225 array[2].throw_during_move = true;
226 Array<ExceptionThrower> array_moved(10);
227 EXPECT_ANY_THROW({ array_moved = std::move(array); });
228 }
229
TEST(array,Last)230 TEST(array, Last)
231 {
232 Array<int> array = {5, 7, 8, 9};
233 EXPECT_EQ(array.last(), 9);
234 array.last() = 1;
235 EXPECT_EQ(array[3], 1);
236 EXPECT_EQ(const_cast<const Array<int> &>(array).last(), 1);
237 }
238
TEST(array,Reinitialize)239 TEST(array, Reinitialize)
240 {
241 Array<std::string> array = {"hello", "world"};
242 EXPECT_EQ(array.size(), 2);
243 EXPECT_EQ(array[1], "world");
244 array.reinitialize(3);
245 EXPECT_EQ(array.size(), 3);
246 EXPECT_EQ(array[0], "");
247 EXPECT_EQ(array[1], "");
248 EXPECT_EQ(array[2], "");
249 array.reinitialize(0);
250 EXPECT_EQ(array.size(), 0);
251 }
252
253 } // namespace blender::tests
254