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