1 /* Copyright (c) 2013, 2021, Oracle and/or its affiliates.
2
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License, version 2.0,
5 as published by the Free Software Foundation.
6
7 This program is also distributed with certain software (including
8 but not limited to OpenSSL) that is licensed under separate terms,
9 as designated in a particular file or component or in included license
10 documentation. The authors of MySQL hereby grant you an additional
11 permission to link the program and your derivative works with the
12 separately licensed software that they have included with MySQL.
13
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License, version 2.0, for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
22
23 // First include (the generated) my_config.h, to get correct platform defines.
24 #include "my_config.h"
25 #include <gtest/gtest.h>
26 #include <algorithm>
27
28 #include "prealloced_array.h"
29 #include "sql_alloc.h"
30
31 namespace prealloced_array_unittest {
32
33 class PreallocedArrayTest : public ::testing::Test
34 {
35 public:
PreallocedArrayTest()36 PreallocedArrayTest()
37 : int_10(PSI_NOT_INSTRUMENTED)
38 {}
39
40 protected:
41 Prealloced_array<int, 10> int_10;
42 int some_integer;
43 };
44
45
TEST_F(PreallocedArrayTest,Empty)46 TEST_F(PreallocedArrayTest, Empty)
47 {
48 EXPECT_EQ(10U, int_10.capacity());
49 EXPECT_EQ(sizeof(int), int_10.element_size());
50 EXPECT_TRUE(int_10.empty());
51 EXPECT_EQ(0U, int_10.size());
52 }
53
54 #if !defined(NDEBUG)
55 // Google Test recommends DeathTest suffix for classes used in death tests.
56 typedef PreallocedArrayTest PreallocedArrayDeathTest;
57
TEST_F(PreallocedArrayDeathTest,OutOfBoundsRead)58 TEST_F(PreallocedArrayDeathTest, OutOfBoundsRead)
59 {
60 ::testing::FLAGS_gtest_death_test_style = "threadsafe";
61 EXPECT_DEATH_IF_SUPPORTED(some_integer= int_10[5],
62 ".*Assertion .*n < size.*");
63 }
64
TEST_F(PreallocedArrayDeathTest,OutOfBoundsWrite)65 TEST_F(PreallocedArrayDeathTest, OutOfBoundsWrite)
66 {
67 ::testing::FLAGS_gtest_death_test_style = "threadsafe";
68 EXPECT_DEATH_IF_SUPPORTED(int_10[5] = some_integer,
69 ".*Assertion .*n < size.*");
70 }
71
TEST_F(PreallocedArrayDeathTest,EmptyBack)72 TEST_F(PreallocedArrayDeathTest, EmptyBack)
73 {
74 ::testing::FLAGS_gtest_death_test_style = "threadsafe";
75 EXPECT_DEATH_IF_SUPPORTED(int_10.back() = 42,
76 ".*Assertion .*n < size.*");
77 }
78
TEST_F(PreallocedArrayDeathTest,EmptyPopBack)79 TEST_F(PreallocedArrayDeathTest, EmptyPopBack)
80 {
81 ::testing::FLAGS_gtest_death_test_style = "threadsafe";
82 EXPECT_DEATH_IF_SUPPORTED(int_10.pop_back(),
83 ".*Assertion .*!empty.*");
84 }
85
TEST_F(PreallocedArrayDeathTest,EmptyErase)86 TEST_F(PreallocedArrayDeathTest, EmptyErase)
87 {
88 ::testing::FLAGS_gtest_death_test_style = "threadsafe";
89 size_t ix= 0;
90 EXPECT_DEATH_IF_SUPPORTED(int_10.erase(ix),
91 ".*Assertion .*ix < size.*");
92 }
93
94 #endif // NDEBUG
95
TEST_F(PreallocedArrayTest,Insert5)96 TEST_F(PreallocedArrayTest, Insert5)
97 {
98 for (int ix= 0; ix < 5; ++ix)
99 int_10.push_back(ix);
100 for (int ix= 0; ix < 5; ++ix)
101 EXPECT_EQ(ix, int_10[ix]);
102 for (int ix= 0; ix < 5; ++ix)
103 int_10[ix]= ix;
104 EXPECT_EQ(5U, int_10.size());
105 EXPECT_EQ(10U, int_10.capacity());
106 }
107
TEST_F(PreallocedArrayTest,Insert15)108 TEST_F(PreallocedArrayTest, Insert15)
109 {
110 for (int ix= 0; ix < 15; ++ix)
111 int_10.push_back(ix);
112 for (int ix= 0; ix < 15; ++ix)
113 EXPECT_EQ(ix, int_10[ix]);
114 for (int ix= 0; ix < 15; ++ix)
115 int_10[ix]= ix;
116 EXPECT_EQ(15U, int_10.size());
117 EXPECT_LE(15U, int_10.capacity());
118 }
119
TEST_F(PreallocedArrayTest,Sort)120 TEST_F(PreallocedArrayTest, Sort)
121 {
122 for (int ix= 20; ix >= 0; --ix)
123 int_10.push_back(ix);
124 std::sort(int_10.begin(), int_10.end());
125 for (int ix= 0; ix <= 20; ++ix)
126 EXPECT_EQ(ix, int_10[ix]);
127 }
128
TEST_F(PreallocedArrayTest,Back)129 TEST_F(PreallocedArrayTest, Back)
130 {
131 for (int ix= 0; ix <= 15; ++ix)
132 int_10.push_back(ix);
133 EXPECT_EQ(15, int_10.back());
134 int_10.back()= 42;
135 EXPECT_EQ(42, int_10.back());
136 }
137
TEST_F(PreallocedArrayTest,PopBack)138 TEST_F(PreallocedArrayTest, PopBack)
139 {
140 for (int ix= 0; ix <= 15; ++ix)
141 int_10.push_back(ix);
142 for (int ix= 15; ix >= 0; --ix)
143 {
144 EXPECT_EQ(ix, int_10.back());
145 int_10.pop_back();
146 }
147 }
148
TEST_F(PreallocedArrayTest,EraseFirst)149 TEST_F(PreallocedArrayTest, EraseFirst)
150 {
151 for (int ix= 0; ix <= 15; ++ix)
152 int_10.push_back(ix);
153 EXPECT_EQ(0, int_10[0]);
154 EXPECT_EQ(16U, int_10.size());
155 int_10.erase(int_10.begin());
156 EXPECT_EQ(15U, int_10.size());
157 for (int ix= 0; ix < static_cast<int>(int_10.size()); ++ix)
158 {
159 EXPECT_EQ(ix + 1, int_10[ix]);
160 }
161 }
162
TEST_F(PreallocedArrayTest,EraseLast)163 TEST_F(PreallocedArrayTest, EraseLast)
164 {
165 for (int ix= 0; ix <= 15; ++ix)
166 int_10.push_back(ix);
167 EXPECT_EQ(15, int_10.back());
168 EXPECT_EQ(15, int_10.at(15));
169 int_10.erase(15);
170 EXPECT_EQ(14, int_10.back());
171 EXPECT_EQ(14, int_10.at(14));
172 }
173
TEST_F(PreallocedArrayTest,EraseMiddle)174 TEST_F(PreallocedArrayTest, EraseMiddle)
175 {
176 for (int ix= 0; ix <= 15; ++ix)
177 int_10.push_back(ix);
178 EXPECT_EQ(6, int_10[6]);
179 EXPECT_EQ(7, int_10[7]);
180 EXPECT_EQ(16U, int_10.size());
181 int_10.erase(7);
182 EXPECT_EQ(6, int_10[6]);
183 EXPECT_EQ(8, int_10[7]);
184 EXPECT_EQ(9, int_10[8]);
185 EXPECT_EQ(15U, int_10.size());
186 }
187
TEST_F(PreallocedArrayTest,ResizeSame)188 TEST_F(PreallocedArrayTest, ResizeSame)
189 {
190 for (int ix= 0; ix <= 15; ++ix)
191 int_10.push_back(ix);
192 EXPECT_EQ(16U, int_10.size());
193 int_10.resize(16U);
194 EXPECT_EQ(16U, int_10.size());
195 }
196
TEST_F(PreallocedArrayTest,ResizeGrow)197 TEST_F(PreallocedArrayTest, ResizeGrow)
198 {
199 int_10.push_back(1);
200 int_10.resize(20);
201 EXPECT_EQ(1, int_10[0]);
202 EXPECT_EQ(0, int_10[1]);
203 EXPECT_EQ(20U, int_10.size());
204 EXPECT_GE(int_10.capacity(), 20U);
205 }
206
TEST_F(PreallocedArrayTest,ResizeGrowVal)207 TEST_F(PreallocedArrayTest, ResizeGrowVal)
208 {
209 int_10.resize(20, 42);
210 EXPECT_EQ(42, int_10[0]);
211 EXPECT_EQ(42, int_10[19]);
212 EXPECT_EQ(20U, int_10.size());
213 EXPECT_GE(int_10.capacity(), 20U);
214 }
215
TEST_F(PreallocedArrayTest,ResizeShrink)216 TEST_F(PreallocedArrayTest, ResizeShrink)
217 {
218 for (int ix= 0; ix <= 15; ++ix)
219 int_10.push_back(ix);
220 EXPECT_EQ(16U, int_10.size());
221 int_10.resize(10);
222 EXPECT_EQ(10U, int_10.size());
223 }
224
TEST_F(PreallocedArrayTest,InsertUnique)225 TEST_F(PreallocedArrayTest, InsertUnique)
226 {
227 for (int ix= 0; ix < 10; ++ix)
228 {
229 int_10.push_back(ix);
230 int_10.push_back(ix);
231 }
232 std::random_shuffle(int_10.begin(), int_10.end());
233 Prealloced_array<int, 1> unique_arr(PSI_NOT_INSTRUMENTED);
234 for (int *pi= int_10.begin(); pi != int_10.end(); ++pi)
235 {
236 unique_arr.insert_unique(*pi);
237 EXPECT_EQ(1U, unique_arr.count_unique(*pi));
238 }
239 EXPECT_EQ(10U, unique_arr.size());
240 // Duplicates should have been ignored, and the result should be sorted.
241 for (int ix= 0; ix < static_cast<int>(unique_arr.size()); ++ix)
242 {
243 EXPECT_EQ(ix, unique_arr[ix]);
244 }
245 }
246
TEST_F(PreallocedArrayTest,EraseUnique)247 TEST_F(PreallocedArrayTest, EraseUnique)
248 {
249 for (int ix= 0; ix < 20; ++ix)
250 int_10.push_back(ix);
251
252 // The array should be sorted by default.
253 for (int ix= 0; ix < 20; ++ix)
254 EXPECT_EQ(ix, int_10[ix]);
255
256 // Now remove all even numbers.
257 for (int ix= 0; ix < 10; ++ix)
258 EXPECT_EQ(1U, int_10.erase_unique(2 * ix));
259
260 // 10 numbers should remain.
261 EXPECT_EQ(10U, int_10.size());
262
263 // Removing non-existing numbers should return 0.
264 for (int ix= 0; ix < 10; ++ix)
265 {
266 EXPECT_EQ(0U, int_10.count_unique(2 * ix));
267 EXPECT_EQ(0U, int_10.erase_unique(2 * ix));
268 }
269
270 // 10 numbers should still remain.
271 EXPECT_EQ(10U, int_10.size());
272
273 // The array should still be sorted and contain odd numbers.
274 for (int ix= 0; ix < 10; ++ix)
275 EXPECT_EQ(2 * ix + 1, int_10[ix]);
276 }
277
278 /*
279 A simple class for testing that object copying and destruction is done
280 properly when we have to expand the array a few times,
281 and has_trivial_destructor == false.
282 */
283 class IntWrap
284 {
285 public:
IntWrap()286 IntWrap()
287 {
288 m_int= new int(0);
289 }
IntWrap(int arg)290 explicit IntWrap(int arg)
291 {
292 m_int= new int(arg);
293 }
IntWrap(const IntWrap & other)294 IntWrap(const IntWrap &other)
295 {
296 m_int= new int(other.getval());
297 }
~IntWrap()298 ~IntWrap()
299 {
300 delete m_int;
301 }
operator =(const IntWrap & rhs)302 IntWrap &operator=(const IntWrap &rhs)
303 {
304 *m_int= rhs.getval();
305 return *this;
306 }
307
getval() const308 int getval() const { return *m_int; }
309 private:
310 int *m_int;
311 };
312
313 /*
314 To verify that there are no leaks, do:
315 valgrind ./prealloced_array-t --gtest_filter="-*DeathTest*"
316 */
TEST_F(PreallocedArrayTest,NoMemLeaksPushing)317 TEST_F(PreallocedArrayTest, NoMemLeaksPushing)
318 {
319 Prealloced_array<IntWrap, 1, false> array(PSI_NOT_INSTRUMENTED);
320 for (int ix= 0; ix < 42; ++ix)
321 array.push_back(IntWrap(ix));
322 for (int ix= 0; ix < 42; ++ix)
323 EXPECT_EQ(ix, array[ix].getval());
324 }
325
TEST_F(PreallocedArrayTest,NoMemLeaksPopping)326 TEST_F(PreallocedArrayTest, NoMemLeaksPopping)
327 {
328 Prealloced_array<IntWrap, 1, false> array(PSI_NOT_INSTRUMENTED);
329 for (int ix= 0; ix < 42; ++ix)
330 array.push_back(IntWrap(ix));
331 while (!array.empty())
332 array.pop_back();
333 }
334
TEST_F(PreallocedArrayTest,NoMemLeaksErasing)335 TEST_F(PreallocedArrayTest, NoMemLeaksErasing)
336 {
337 Prealloced_array<IntWrap, 1, false> array(PSI_NOT_INSTRUMENTED);
338 for (int ix= 0; ix < 42; ++ix)
339 array.push_back(IntWrap(ix));
340 for (int ix= 0; !array.empty(); ++ix)
341 {
342 EXPECT_EQ(ix, array[0].getval());
343 array.erase(array.begin());
344 }
345 }
346
TEST_F(PreallocedArrayTest,NoMemLeaksClearing)347 TEST_F(PreallocedArrayTest, NoMemLeaksClearing)
348 {
349 Prealloced_array<IntWrap, 1, false> array(PSI_NOT_INSTRUMENTED);
350 for (int ix= 0; ix < 42; ++ix)
351 array.push_back(IntWrap(ix));
352 array.clear();
353 EXPECT_EQ(0U, array.size());
354 }
355
TEST_F(PreallocedArrayTest,NoMemLeaksResizing)356 TEST_F(PreallocedArrayTest, NoMemLeaksResizing)
357 {
358 Prealloced_array<IntWrap, 1, false> array(PSI_NOT_INSTRUMENTED);
359 for (int ix= 0; ix < 42; ++ix)
360 array.push_back(IntWrap(ix));
361 array.resize(0);
362 EXPECT_EQ(0U, array.size());
363 }
364
TEST_F(PreallocedArrayTest,NoMemLeaksAssigning)365 TEST_F(PreallocedArrayTest, NoMemLeaksAssigning)
366 {
367 Prealloced_array<IntWrap, 1, false> array1(PSI_NOT_INSTRUMENTED);
368 for (int ix= 0; ix < 42; ++ix)
369 array1.push_back(IntWrap(ix));
370 Prealloced_array<IntWrap, 1, false> array2(PSI_NOT_INSTRUMENTED);
371 for (int ix= 0; ix < 10; ++ix)
372 array2.push_back(IntWrap(ix + 100));
373 array2= array1;
374 EXPECT_EQ(array1.size(), array2.size());
375 for (size_t ix= 0; ix < array1.size(); ++ix)
376 EXPECT_EQ(array1[ix].getval(), array2[ix].getval());
377 }
378
TEST_F(PreallocedArrayTest,NoMemLeaksEraseAll)379 TEST_F(PreallocedArrayTest, NoMemLeaksEraseAll)
380 {
381 Prealloced_array<IntWrap, 1, false> array(PSI_NOT_INSTRUMENTED);
382 for (int ix= 0; ix < 42; ++ix)
383 array.push_back(IntWrap(ix));
384 array.erase(array.begin(), array.end());
385 EXPECT_EQ(0U, array.size());
386 }
387
TEST_F(PreallocedArrayTest,NoMemLeaksEraseMiddle)388 TEST_F(PreallocedArrayTest, NoMemLeaksEraseMiddle)
389 {
390 Prealloced_array<IntWrap, 1, false> array(PSI_NOT_INSTRUMENTED);
391 for (int ix= 0; ix < 42; ++ix)
392 array.push_back(IntWrap(ix));
393 array.erase(array.begin() + 1, array.end() - 1);
394 EXPECT_EQ(2U, array.size());
395 EXPECT_EQ(0, array[0].getval());
396 EXPECT_EQ(41, array[1].getval());
397 }
398
TEST_F(PreallocedArrayTest,NoMemLeaksEraseSwap)399 TEST_F(PreallocedArrayTest, NoMemLeaksEraseSwap)
400 {
401 Prealloced_array<IntWrap, 1, false> array1(PSI_NOT_INSTRUMENTED);
402 for (int ix= 0; ix < 42; ++ix)
403 array1.push_back(IntWrap(ix));
404 Prealloced_array<IntWrap, 1, false> array2(PSI_NOT_INSTRUMENTED);
405 for (int ix= 0; ix < 10; ++ix)
406 array2.push_back(IntWrap(ix + 100));
407 array1.swap(array2);
408 EXPECT_EQ(10U, array1.size());
409 EXPECT_EQ(42U, array2.size());
410 Prealloced_array<IntWrap, 1, false>(PSI_NOT_INSTRUMENTED).swap(array1);
411 EXPECT_EQ(0U, array1.size());
412 }
413
TEST_F(PreallocedArrayTest,NoMemLeaksMySwap)414 TEST_F(PreallocedArrayTest, NoMemLeaksMySwap)
415 {
416 Prealloced_array<IntWrap, 2, false> array1(PSI_NOT_INSTRUMENTED);
417 Prealloced_array<IntWrap, 2, false> array2(PSI_NOT_INSTRUMENTED);
418 array1.push_back(IntWrap(1));
419 array2.push_back(IntWrap(2));
420 array2.push_back(IntWrap(22));
421 array1.swap(array2);
422 EXPECT_EQ(2U, array1.size());
423 EXPECT_EQ(1U, array2.size());
424 EXPECT_EQ(2, array1[0].getval());
425 EXPECT_EQ(22, array1[1].getval());
426 EXPECT_EQ(1, array2[0].getval());
427 }
428
TEST_F(PreallocedArrayTest,NoMemLeaksStdSwap)429 TEST_F(PreallocedArrayTest, NoMemLeaksStdSwap)
430 {
431 Prealloced_array<IntWrap, 1, false> array1(PSI_NOT_INSTRUMENTED);
432 for (int ix= 0; ix < 42; ++ix)
433 array1.push_back(IntWrap(ix));
434 Prealloced_array<IntWrap, 1, false>
435 array2(PSI_NOT_INSTRUMENTED, array1.begin(), array1.begin() + 10);
436 EXPECT_EQ(10U, array2.size());
437 IntWrap *p1= array1.begin();
438 IntWrap *p2= array2.begin();
439 array1.swap(array2);
440 EXPECT_EQ(10U, array1.size());
441 EXPECT_EQ(42U, array2.size());
442 // We expect a buffer swap here.
443 EXPECT_EQ(p1, array2.begin());
444 EXPECT_EQ(p2, array1.begin());
445 }
446
TEST_F(PreallocedArrayTest,NoMemLeaksShrinkToFitMalloc)447 TEST_F(PreallocedArrayTest, NoMemLeaksShrinkToFitMalloc)
448 {
449 Prealloced_array<IntWrap, 1, false> array1(PSI_NOT_INSTRUMENTED);
450 for (int ix= 0; ix < 42; ++ix)
451 array1.push_back(IntWrap(ix));
452 IntWrap *p1= array1.begin();
453 array1.shrink_to_fit();
454 EXPECT_EQ(42U, array1.size());
455 EXPECT_EQ(42U, array1.capacity());
456 EXPECT_NE(p1, array1.begin());
457 }
458
TEST_F(PreallocedArrayTest,NoMemLeaksShrinkToFitSameSize)459 TEST_F(PreallocedArrayTest, NoMemLeaksShrinkToFitSameSize)
460 {
461 Prealloced_array<IntWrap, 10, false> array1(PSI_NOT_INSTRUMENTED);
462 for (int ix= 0; ix < 42; ++ix)
463 array1.push_back(IntWrap(ix));
464 for (int ix= 0; array1.size() != array1.capacity(); ++ix)
465 array1.push_back(IntWrap(ix));
466 IntWrap *p1= array1.begin();
467 array1.shrink_to_fit();
468 EXPECT_EQ(p1, array1.begin());
469 }
470
TEST_F(PreallocedArrayTest,NoMemLeaksShrinkToFitPrealloc)471 TEST_F(PreallocedArrayTest, NoMemLeaksShrinkToFitPrealloc)
472 {
473 Prealloced_array<IntWrap, 100, false> array1(PSI_NOT_INSTRUMENTED);
474 for (int ix= 0; ix < 42; ++ix)
475 array1.push_back(IntWrap(ix));
476 IntWrap *p1= array1.begin();
477 array1.shrink_to_fit();
478 EXPECT_EQ(42U, array1.size());
479 EXPECT_EQ(100U, array1.capacity());
480 EXPECT_EQ(p1, array1.begin());
481 }
482
483 /*
484 A simple class to verify that Prealloced_array also works for
485 classes which have their own operator new/delete.
486 */
487 class TestAlloc : public Sql_alloc
488 {
489 public:
TestAlloc(int val)490 explicit TestAlloc(int val)
491 : m_int(val)
492 {}
493
getval() const494 int getval() const { return m_int; }
495 private:
496 int m_int;
497 };
498
499
500 /*
501 There is no THD and no mem-root available for the execution of this test.
502 This shows that the memory management of Prealloced_array works OK for
503 classes inheriting from Sql_alloc.
504 */
TEST_F(PreallocedArrayTest,SqlAlloc)505 TEST_F(PreallocedArrayTest, SqlAlloc)
506 {
507 Prealloced_array<TestAlloc, 1, false> array(PSI_NOT_INSTRUMENTED);
508 for (int ix= 0; ix < 42; ++ix)
509 array.push_back(TestAlloc(ix));
510 for (int ix= 0; ix < 42; ++ix)
511 EXPECT_EQ(ix, array[ix].getval());
512 }
513
514 }
515