1 /* Copyright (c) 2014, 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 "inplace_vector.h"
29 #include "sql_alloc.h"
30 
31 namespace inplace_vector_unittest {
32 
33 class InplaceVectorTest : public ::testing::Test
34 {
35 public:
InplaceVectorTest()36   InplaceVectorTest()
37     : int_10(PSI_NOT_INSTRUMENTED)
38   {}
39 
40 protected:
41   Inplace_vector<int, 5> int_10;
42   int some_integer;
43 };
44 
45 
TEST_F(InplaceVectorTest,Empty)46 TEST_F(InplaceVectorTest, Empty)
47 {
48   EXPECT_TRUE(int_10.empty());
49   EXPECT_EQ(0U, int_10.size());
50 }
51 
52 #if !defined(NDEBUG)
53 // Google Test recommends DeathTest suffix for classes used in death tests.
54 typedef InplaceVectorTest InplaceVectorDeathTest;
55 
TEST_F(InplaceVectorDeathTest,OutOfBoundsRead)56 TEST_F(InplaceVectorDeathTest, OutOfBoundsRead)
57 {
58   ::testing::FLAGS_gtest_death_test_style = "threadsafe";
59   EXPECT_DEATH_IF_SUPPORTED(some_integer= int_10[5],
60                             ".*Assertion .*i < size.*");
61 }
62 
TEST_F(InplaceVectorDeathTest,OutOfBoundsWrite)63 TEST_F(InplaceVectorDeathTest, OutOfBoundsWrite)
64 {
65   ::testing::FLAGS_gtest_death_test_style = "threadsafe";
66   EXPECT_DEATH_IF_SUPPORTED(int_10[5] = some_integer,
67                             ".*Assertion .*i < size.*");
68 }
69 
TEST_F(InplaceVectorDeathTest,EmptyBackRead)70 TEST_F(InplaceVectorDeathTest, EmptyBackRead)
71 {
72   ::testing::FLAGS_gtest_death_test_style = "threadsafe";
73   EXPECT_DEATH_IF_SUPPORTED(some_integer= int_10.back(),
74                             ".*Assertion .*size.*0.*");
75 }
TEST_F(InplaceVectorDeathTest,EmptyBackWrite)76 TEST_F(InplaceVectorDeathTest, EmptyBackWrite)
77 {
78   ::testing::FLAGS_gtest_death_test_style = "threadsafe";
79   EXPECT_DEATH_IF_SUPPORTED(int_10.back() = 42,
80                             ".*Assertion .*size.*0.*");
81 }
82 
83 
84 #endif // NDEBUG
85 
TEST_F(InplaceVectorTest,Insert5)86 TEST_F(InplaceVectorTest, Insert5)
87 {
88   for (int ix= 0; ix < 5; ++ix)
89     int_10.push_back(ix);
90   for (int ix= 0; ix < 5; ++ix)
91     EXPECT_EQ(ix, int_10[ix]);
92   for (int ix= 0; ix < 5; ++ix)
93     int_10[ix]= ix;
94   EXPECT_EQ(5U, int_10.size());
95   EXPECT_EQ(5U, int_10.capacity());
96 }
97 
TEST_F(InplaceVectorTest,Insert15)98 TEST_F(InplaceVectorTest, Insert15)
99 {
100   for (int ix= 0; ix < 15; ++ix)
101     int_10.push_back(ix);
102   for (int ix= 0; ix < 15; ++ix)
103     EXPECT_EQ(ix, int_10[ix]);
104   for (int ix= 0; ix < 15; ++ix)
105     int_10[ix]= ix;
106   EXPECT_EQ(15U, int_10.size());
107   EXPECT_EQ(15U, int_10.capacity());
108   int_10.push_back(16);
109   EXPECT_EQ(20U, int_10.capacity());
110 }
111 
TEST_F(InplaceVectorTest,Back)112 TEST_F(InplaceVectorTest, Back)
113 {
114   for (int ix= 0; ix <= 15; ++ix)
115     int_10.push_back(ix);
116   EXPECT_EQ(15, int_10.back());
117   int_10.back()= 42;
118   EXPECT_EQ(42, int_10.back());
119 }
120 
TEST_F(InplaceVectorTest,ResizeSame)121 TEST_F(InplaceVectorTest, ResizeSame)
122 {
123   for (int ix= 0; ix <= 15; ++ix)
124     int_10.push_back(ix);
125   EXPECT_EQ(16U, int_10.size());
126   int_10.resize(16U);
127   EXPECT_EQ(16U, int_10.size());
128 }
129 
TEST_F(InplaceVectorTest,ResizeGrow)130 TEST_F(InplaceVectorTest, ResizeGrow)
131 {
132   int_10.push_back(1);
133   int_10.resize(20);
134   EXPECT_EQ(1, int_10[0]);
135   EXPECT_EQ(0, int_10[1]);
136   EXPECT_EQ(20U, int_10.size());
137   EXPECT_EQ(int_10.capacity(), 20U);
138 }
139 
TEST_F(InplaceVectorTest,ResizeGrowVal)140 TEST_F(InplaceVectorTest, ResizeGrowVal)
141 {
142   int_10.resize(20, 42);
143   EXPECT_EQ(42, int_10[0]);
144   EXPECT_EQ(42, int_10[19]);
145   EXPECT_EQ(20U, int_10.size());
146   EXPECT_EQ(int_10.capacity(), 20U);
147 }
148 
TEST_F(InplaceVectorTest,ResizeShrink)149 TEST_F(InplaceVectorTest, ResizeShrink)
150 {
151   for (int ix= 0; ix <= 15; ++ix)
152     int_10.push_back(ix);
153   EXPECT_EQ(16U, int_10.size());
154   EXPECT_EQ(int_10.capacity(), 20U);
155   int_10.resize(10);
156   EXPECT_EQ(10U, int_10.size());
157   EXPECT_EQ(int_10.capacity(), 15U);
158 
159   int_10.resize(3);
160   EXPECT_EQ(3U, int_10.size());
161   EXPECT_EQ(int_10.capacity(), 5U);
162 
163 }
164 
165 /*
166   A simple class for testing that object copying and destruction is done
167   properly when we have to expand the array a few times.
168  */
169 class IntWrap
170 {
171 public:
IntWrap()172   IntWrap()
173   {
174     m_int= new int(0);
175   }
IntWrap(int arg)176   explicit IntWrap(int arg)
177   {
178     m_int= new int(arg);
179   }
IntWrap(const IntWrap & other)180   IntWrap(const IntWrap &other)
181   {
182     m_int= new int(other.getval());
183   }
~IntWrap()184   ~IntWrap()
185   {
186     delete m_int;
187   }
getval() const188   int getval() const { return *m_int; }
189 private:
190   int *m_int;
191 };
192 
193 /*
194   To verify that there are no leaks, do:
195   valgrind ./inplace_vector-t --gtest_filter="-*DeathTest*"
196 */
TEST_F(InplaceVectorTest,NoMemLeaksPushing)197 TEST_F(InplaceVectorTest, NoMemLeaksPushing)
198 {
199   Inplace_vector<IntWrap, 5> array(PSI_NOT_INSTRUMENTED);
200   for (int ix= 0; ix < 42; ++ix)
201     array.push_back(IntWrap(ix));
202   for (int ix= 0; ix < 42; ++ix)
203     EXPECT_EQ(ix, array[ix].getval());
204 }
205 
206 
TEST_F(InplaceVectorTest,NoMemLeaksClearing)207 TEST_F(InplaceVectorTest, NoMemLeaksClearing)
208 {
209   Inplace_vector<IntWrap, 5> array(PSI_NOT_INSTRUMENTED);
210   for (int ix= 0; ix < 42; ++ix)
211     array.push_back(IntWrap(ix));
212   array.clear();
213   EXPECT_EQ(0U, array.size());
214   EXPECT_EQ(0U, array.capacity());
215 
216   array.push_back(IntWrap(1));
217   EXPECT_EQ(1U, array.size());
218   EXPECT_EQ(5U, array.capacity());
219 }
220 
TEST_F(InplaceVectorTest,NoMemLeaksResizing)221 TEST_F(InplaceVectorTest, NoMemLeaksResizing)
222 {
223   Inplace_vector<IntWrap, 5> array(PSI_NOT_INSTRUMENTED);
224   for (int ix= 0; ix < 42; ++ix)
225     array.push_back(IntWrap(ix));
226   array.resize(0);
227   EXPECT_EQ(0U, array.size());
228   EXPECT_EQ(5U, array.capacity());
229 
230   array.push_back(IntWrap(1));
231   EXPECT_EQ(1U, array.size());
232   EXPECT_EQ(5U, array.capacity());
233 }
234 
235 
236 /*
237   A vector consists of a list of arrays of objects. Test that all
238   elements of all arrays are destroyed when the vector is
239   destroyed. If run in valgrind, these tests will report memory leaks
240   if some objects aren't destroyed.
241  */
242 class InplaceVectorTestP : public ::testing::TestWithParam<size_t>
243 {
244 protected:
InplaceVectorTestP()245   InplaceVectorTestP() : array(PSI_NOT_INSTRUMENTED) {}
SetUp()246   virtual void SetUp()
247   {
248     n_elems= GetParam();
249   }
250   size_t n_elems;
251   Inplace_vector<IntWrap, 5> array;
252 };
253 
254 size_t test_values[]= {5, 10, 15, 20};
255 
256 INSTANTIATE_TEST_CASE_P(NoMemLeaks, InplaceVectorTestP,
257 ::testing::ValuesIn(test_values));
258 
TEST_P(InplaceVectorTestP,DestroyingFullArrays)259 TEST_P(InplaceVectorTestP, DestroyingFullArrays)
260 {
261   for (size_t ix= 0; ix < n_elems; ++ix)
262     array.push_back(IntWrap(ix));
263   EXPECT_EQ(n_elems, array.size());
264   EXPECT_EQ(n_elems, array.capacity());
265 }
266 
267 
TEST_P(InplaceVectorTestP,DestroyingAlmostFullArrays)268 TEST_P(InplaceVectorTestP, DestroyingAlmostFullArrays)
269 {
270   for (size_t ix= 0; ix < n_elems - 1; ++ix)
271     array.push_back(IntWrap(ix));
272   EXPECT_EQ(n_elems - 1, array.size());
273   EXPECT_EQ(n_elems, array.capacity());
274 }
275 
276 
TEST_P(InplaceVectorTestP,DestroyingAlmostEmptyArrays)277 TEST_P(InplaceVectorTestP, DestroyingAlmostEmptyArrays)
278 {
279   for (size_t ix= 0; ix < n_elems - 5 + 1; ++ix)
280     array.push_back(IntWrap(ix));
281   EXPECT_EQ(n_elems - 5 + 1, array.size());
282   EXPECT_EQ(n_elems, array.capacity());
283 }
284 
285 
286 /*
287   A simple class to verify that Inplace_vector also works for
288   classes which have their own operator new/delete.
289  */
290 class TestAlloc : public Sql_alloc
291 {
292 public:
TestAlloc(int val)293   explicit TestAlloc(int val)
294     : m_int(val)
295   {}
296 
getval() const297   int getval() const { return m_int; }
298 private:
299   int m_int;
300 };
301 
302 
303 /*
304   There is no THD and no mem-root available for the execution of this test.
305   This shows that the memory management of Inplace_vector works OK for
306   classes inheriting from Sql_alloc.
307  */
TEST_F(InplaceVectorTest,SqlAlloc)308 TEST_F(InplaceVectorTest, SqlAlloc)
309 {
310   Inplace_vector<TestAlloc, 5> array(PSI_NOT_INSTRUMENTED);
311   for (int ix= 0; ix < 42; ++ix)
312     array.push_back(TestAlloc(ix));
313   for (int ix= 0; ix < 42; ++ix)
314     EXPECT_EQ(ix, array[ix].getval());
315 
316   EXPECT_EQ(array.size(), 42U);
317   EXPECT_EQ(array.capacity(), 45U);
318 }
319 
320 }
321