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