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