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
27 #include "malloc_allocator.h"
28 #include "memroot_allocator.h"
29
30 #include <vector>
31 #include <list>
32 #include <deque>
33 #include <algorithm>
34
35 using std::vector;
36 using std::list;
37 using std::deque;
38
39 /*
40 Tests of custom STL memory allocators.
41 */
42
43
44 #if defined(GTEST_HAS_TYPED_TEST)
45
46 namespace stlalloc_unittest {
47
48 /*
49 Wrappers to overcome the issue that we need allocators with
50 default constructors for TYPED_TEST_CASE, which neither
51 Malloc_allocator nor Memroot_allocator have.
52
53 These wrappers need to inherit so that they are allocators themselves.
54 Otherwise TypeParam in the tests below will be wrong.
55 */
56 template<typename T>
57 class Malloc_allocator_wrapper : public Malloc_allocator<T>
58 {
59 public:
Malloc_allocator_wrapper()60 Malloc_allocator_wrapper()
61 : Malloc_allocator<T>(PSI_NOT_INSTRUMENTED)
62 { }
63 };
64
65 template<typename T>
66 class Memroot_allocator_wrapper : public Memroot_allocator<T>
67 {
68 MEM_ROOT m_mem_root;
69
70 public:
Memroot_allocator_wrapper()71 Memroot_allocator_wrapper()
72 : Memroot_allocator<T>(&m_mem_root)
73 {
74 init_sql_alloc(PSI_NOT_INSTRUMENTED, &m_mem_root, 1024, 0);
75 // memory allocation error is expected, don't abort unit test.
76 m_mem_root.error_handler= NULL;
77 }
78
~Memroot_allocator_wrapper()79 ~Memroot_allocator_wrapper()
80 {
81 free_root(&m_mem_root, MYF(0));
82 }
83 };
84
85
86 //
87 // Test of container with simple objects
88 //
89
90 template<typename T>
91 class STLAllocTestInt : public ::testing::Test
92 {
93 protected:
94 T allocator;
95 };
96
97 typedef ::testing::Types<Malloc_allocator_wrapper<int>,
98 Memroot_allocator_wrapper<int> > AllocatorTypesInt;
99
100 TYPED_TEST_CASE(STLAllocTestInt, AllocatorTypesInt);
101
102
TYPED_TEST(STLAllocTestInt,SimpleVector)103 TYPED_TEST(STLAllocTestInt, SimpleVector)
104 {
105 vector<int, TypeParam> v1(this->allocator);
106 vector<int, TypeParam> v2(this->allocator);
107 for (int i= 0; i < 100; i++)
108 {
109 v1.push_back(i);
110 v2.push_back(100 - i);
111 }
112
113 EXPECT_EQ(100U, v1.size());
114 EXPECT_EQ(100U, v2.size());
115
116 v1.swap(v2);
117
118 EXPECT_EQ(100U, v1.size());
119 EXPECT_EQ(100U, v2.size());
120
121 for (int i= 0; i < 100; i++)
122 {
123 EXPECT_EQ(i, v2[i]);
124 EXPECT_EQ((100 - i), v1[i]);
125 }
126 }
127
128
TYPED_TEST(STLAllocTestInt,SimpleList)129 TYPED_TEST(STLAllocTestInt, SimpleList)
130 {
131 list<int, TypeParam> l1(this->allocator);
132 list<int, TypeParam> l2(this->allocator);
133
134 for (int i= 0; i < 100; i++)
135 l1.push_back(i);
136
137 EXPECT_EQ(100U, l1.size());
138 EXPECT_EQ(0U, l2.size());
139
140 l2.splice(l2.begin(), l1);
141
142 EXPECT_EQ(0U, l1.size());
143 EXPECT_EQ(100U, l2.size());
144
145 std::reverse(l2.begin(), l2.end());
146
147 for (int i= 0; i < 100; i++)
148 {
149 EXPECT_EQ((99 - i), l2.front());
150 l2.pop_front();
151 }
152
153 EXPECT_EQ(0U, l2.size());
154 }
155
156
157 #ifndef NDEBUG
TYPED_TEST(STLAllocTestInt,OutOfMemory)158 TYPED_TEST(STLAllocTestInt, OutOfMemory)
159 {
160 vector<int, TypeParam> v1(this->allocator);
161 v1.reserve(10);
162 EXPECT_EQ(10U, v1.capacity());
163
164 DBUG_SET("+d,simulate_out_of_memory");
165 ASSERT_THROW(v1.reserve(1000), std::bad_alloc);
166 }
167 #endif
168
169
170 //
171 // Test of container with non-trival objects
172 //
173
174 class Container_object;
175
176 template<typename T>
177 class STLAllocTestObject : public STLAllocTestInt<T>
178 { };
179
180 typedef ::testing::Types<Malloc_allocator_wrapper<Container_object>,
181 Memroot_allocator_wrapper<Container_object> >
182 AllocatorTypesObject;
183
184 TYPED_TEST_CASE(STLAllocTestObject, AllocatorTypesObject);
185
186 class Container_object
187 {
188 char *buffer;
189
190 public:
Container_object()191 Container_object()
192 {
193 buffer= new char[20];
194 }
195
Container_object(const Container_object & other)196 Container_object(const Container_object &other)
197 {
198 buffer= new char[20]; // Don't care about contents
199 }
200
~Container_object()201 ~Container_object()
202 {
203 delete[] buffer;
204 }
205 };
206
TYPED_TEST(STLAllocTestObject,ContainerObject)207 TYPED_TEST(STLAllocTestObject, ContainerObject)
208 {
209 vector<Container_object, TypeParam> v1(this->allocator);
210 v1.push_back(Container_object());
211 v1.push_back(Container_object());
212 v1.push_back(Container_object());
213 }
214
215
216 //
217 // Test of container with containers
218 //
219
220 class Container_container;
221
222 template<typename T>
223 class STLAllocTestNested : public STLAllocTestInt<T>
224 { };
225
226 typedef ::testing::Types<Malloc_allocator_wrapper<Container_container>,
227 Memroot_allocator_wrapper<Container_container> >
228 AllocatorTypesNested;
229
230 TYPED_TEST_CASE(STLAllocTestNested, AllocatorTypesNested);
231
232 class Container_container
233 {
234 deque<Container_object> d;
235
236 public:
Container_container()237 Container_container()
238 {
239 d.push_back(Container_object());
240 d.push_back(Container_object());
241 }
242 };
243
TYPED_TEST(STLAllocTestNested,NestedContainers)244 TYPED_TEST(STLAllocTestNested, NestedContainers)
245 {
246 Container_container cc1;
247 Container_container cc2;
248 list<Container_container, TypeParam> l1(this->allocator);
249 l1.push_back(cc1);
250 l1.push_back(cc2);
251 }
252
253 } // namespace stlalloc_unittest
254
255 #endif // GTEST_HAS_TYPED_TEST)
256