1 /* Copyright (c) 2009, 2019, Oracle and/or its affiliates. All rights reserved.
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 /*
24 This is a simple example of how to use the google unit test framework.
25
26 For an introduction to the constructs used below, see:
27 http://code.google.com/p/googletest/wiki/GoogleTestPrimer
28 */
29
30 #include <gtest/gtest.h>
31 #include <stddef.h>
32
33 #include "my_inttypes.h"
34 #include "my_thread.h"
35 #include "sql/sql_error.h"
36 #include "sql/sql_list.h"
37 #include "sql/thr_malloc.h"
38 #include "sql_string.h"
39 #include "unittest/gunit/test_utils.h"
40
41 namespace sql_list_unittest {
42
43 // A simple helper function to insert values into a List.
44 template <class T, int size>
insert_values(T (& array)[size],List<T> * list)45 void insert_values(T (&array)[size], List<T> *list) {
46 for (int ix = 0; ix < size; ++ix) {
47 EXPECT_FALSE(list->push_back(&array[ix]));
48 }
49 }
50
51 /*
52 The fixture for testing the MySQL List and List_iterator classes.
53 A fresh instance of this class will be created for each of the
54 TEST_F functions below.
55 The functions SetUp(), TearDown(), SetUpTestCase(), TearDownTestCase() are
56 inherited from ::testing::Test (google naming style differs from MySQL).
57 */
58 class SqlListTest : public ::testing::Test {
59 protected:
SqlListTest()60 SqlListTest()
61 : m_mem_root_p(&m_mem_root), m_int_list(), m_int_list_iter(m_int_list) {}
62
SetUp()63 virtual void SetUp() {
64 init_sql_alloc(PSI_NOT_INSTRUMENTED, &m_mem_root, 1024, 0);
65 THR_MALLOC = &m_mem_root_p;
66 }
67
TearDown()68 virtual void TearDown() { free_root(&m_mem_root, MYF(0)); }
69
SetUpTestCase()70 static void SetUpTestCase() {
71 current_thd = nullptr;
72 THR_MALLOC = nullptr;
73 }
74
75 MEM_ROOT m_mem_root;
76 MEM_ROOT *m_mem_root_p;
77 List<int> m_int_list;
78 List_iterator<int> m_int_list_iter;
79
80 private:
81 // Declares (but does not define) copy constructor and assignment operator.
82 GTEST_DISALLOW_COPY_AND_ASSIGN_(SqlListTest);
83 };
84
85 // Tests that we can construct and destruct lists.
TEST_F(SqlListTest,ConstructAndDestruct)86 TEST_F(SqlListTest, ConstructAndDestruct) {
87 EXPECT_TRUE(m_int_list.is_empty());
88 List<int> *p_int_list = new (*THR_MALLOC) List<int>;
89 EXPECT_TRUE(p_int_list->is_empty());
90 destroy(p_int_list);
91 }
92
93 // Tests basic operations push and pop.
TEST_F(SqlListTest,BasicOperations)94 TEST_F(SqlListTest, BasicOperations) {
95 int i1 = 1;
96 int i2 = 2;
97 EXPECT_FALSE(m_int_list.push_front(&i1));
98 EXPECT_FALSE(m_int_list.push_back(&i2));
99 EXPECT_FALSE(m_int_list.is_empty());
100 EXPECT_EQ(2U, m_int_list.elements);
101
102 EXPECT_EQ(&i1, m_int_list.head());
103 EXPECT_EQ(&i1, m_int_list.pop());
104 EXPECT_EQ(&i2, m_int_list.head());
105 EXPECT_EQ(&i2, m_int_list.pop());
106 EXPECT_TRUE(m_int_list.is_empty()) << "The list should be empty now!";
107 }
108
109 // Tests list copying.
TEST_F(SqlListTest,DeepCopy)110 TEST_F(SqlListTest, DeepCopy) {
111 int values[] = {11, 22, 33, 42, 5};
112 insert_values(values, &m_int_list);
113 MEM_ROOT mem_root;
114 init_alloc_root(PSI_NOT_INSTRUMENTED, &mem_root, 4096, 4096);
115 List<int> list_copy(m_int_list, &mem_root);
116 EXPECT_EQ(list_copy.elements, m_int_list.elements);
117 while (!list_copy.is_empty()) {
118 EXPECT_EQ(*m_int_list.pop(), *list_copy.pop());
119 }
120 EXPECT_TRUE(m_int_list.is_empty());
121 free_root(&mem_root, MYF(0));
122 }
123
124 // Tests that we can iterate over values.
TEST_F(SqlListTest,Iterate)125 TEST_F(SqlListTest, Iterate) {
126 int values[] = {3, 2, 1};
127 insert_values(values, &m_int_list);
128 for (size_t ix = 0; ix < array_elements(values); ++ix) {
129 EXPECT_EQ(values[ix], *m_int_list_iter++);
130 }
131 m_int_list_iter.init(m_int_list);
132 int *value;
133 int value_number = 0;
134 while ((value = m_int_list_iter++)) {
135 EXPECT_EQ(values[value_number++], *value);
136 }
137 }
138
139 // A simple helper class for testing intrusive lists.
140 class Linked_node : public ilink<Linked_node> {
141 public:
Linked_node(int val)142 Linked_node(int val) : m_value(val) {}
get_value() const143 int get_value() const { return m_value; }
144
145 private:
146 int m_value;
147 };
148 const Linked_node *const null_node = nullptr;
149
150 // An example of a test without any fixture.
TEST(SqlIlistTest,ConstructAndDestruct)151 TEST(SqlIlistTest, ConstructAndDestruct) {
152 I_List<Linked_node> i_list;
153 I_List_iterator<Linked_node> i_list_iter(i_list);
154 EXPECT_TRUE(i_list.is_empty());
155 EXPECT_EQ(null_node, i_list_iter++);
156 }
157
158 // Tests iteration over intrusive lists.
TEST(SqlIlistTest,PushBackAndIterate)159 TEST(SqlIlistTest, PushBackAndIterate) {
160 I_List<Linked_node> i_list;
161 I_List_iterator<Linked_node> i_list_iter(i_list);
162 int values[] = {11, 22, 33, 42, 5};
163 EXPECT_EQ(null_node, i_list.head());
164 for (size_t ix = 0; ix < array_elements(values); ++ix) {
165 i_list.push_back(new Linked_node(values[ix]));
166 }
167
168 Linked_node *node;
169 size_t value_number = 0;
170 while ((node = i_list_iter++)) {
171 EXPECT_EQ(values[value_number++], node->get_value());
172 }
173 for (value_number = 0; (node = i_list.get()); ++value_number) {
174 EXPECT_EQ(values[value_number], node->get_value());
175 delete node;
176 }
177 EXPECT_EQ(array_elements(values), value_number);
178 }
179
180 // Another iteration test over intrusive lists.
TEST(SqlIlistTest,PushFrontAndIterate)181 TEST(SqlIlistTest, PushFrontAndIterate) {
182 I_List<Linked_node> i_list;
183 I_List_iterator<Linked_node> i_list_iter(i_list);
184 int values[] = {11, 22, 33, 42, 5};
185 for (size_t ix = 0; ix < array_elements(values); ++ix) {
186 i_list.push_front(new Linked_node(values[ix]));
187 }
188
189 Linked_node *node;
190 int value_number = array_elements(values) - 1;
191 while ((node = i_list_iter++)) {
192 EXPECT_EQ(values[value_number--], node->get_value());
193 }
194 while ((node = i_list.get())) delete node;
195 }
196
cmp_test(int * a,int * b)197 static int cmp_test(int *a, int *b) {
198 return (*(int *)a < *(int *)b) ? -1 : (*(int *)a > *(int *)b) ? 1 : 0;
199 }
200
201 // Tests list sorting.
TEST_F(SqlListTest,Sort)202 TEST_F(SqlListTest, Sort) {
203 int values[] = {1, 9, 2, 7, 3, 6, 4, 5, 8};
204 insert_values(values, &m_int_list);
205 m_int_list.sort(cmp_test);
206 for (int i = 1; i < 10; i++) {
207 EXPECT_EQ(*m_int_list.pop(), i);
208 }
209 EXPECT_TRUE(m_int_list.is_empty());
210 // Test sorting of empty string.
211 m_int_list.sort(cmp_test);
212 // Check that nothing has changed.
213 EXPECT_TRUE(m_int_list.is_empty());
214 }
215
216 // Tests prepend on empty list followed by push_back, Bug#26813454
TEST_F(SqlListTest,PrependBug)217 TEST_F(SqlListTest, PrependBug) {
218 int values1[] = {1, 2};
219 insert_values(values1, &m_int_list);
220 EXPECT_EQ(2U, m_int_list.elements);
221
222 List<int> ilist;
223 EXPECT_TRUE(ilist.is_empty());
224 ilist.prepend(&m_int_list);
225
226 int values2[] = {3, 4};
227 insert_values(values2, &ilist);
228 EXPECT_EQ(4U, ilist.elements);
229
230 for (int i = 1; i <= 4; i++) EXPECT_EQ(*ilist.pop(), i);
231 }
232
233 // Tests swap_elts
TEST_F(SqlListTest,Swap)234 TEST_F(SqlListTest, Swap) {
235 int values[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
236 insert_values(values, &m_int_list);
237 EXPECT_EQ(m_int_list.swap_elts(1, 1), false);
238 // Expect no change
239 for (int i = 0; i < 10; i++) {
240 EXPECT_EQ(*m_int_list.pop(), i);
241 }
242
243 insert_values(values, &m_int_list);
244 EXPECT_EQ(m_int_list.swap_elts(9, 10), true /* error */);
245 // Expect no change: 10 out of bounds
246 for (int i = 0; i < 10; i++) {
247 EXPECT_EQ(*m_int_list.pop(), i);
248 }
249
250 insert_values(values, &m_int_list);
251 EXPECT_EQ(m_int_list.swap_elts(10, 9), true /* error */);
252 // Expect no change: 10 out of bounds
253 for (int i = 0; i < 10; i++) {
254 EXPECT_EQ(*m_int_list.pop(), i);
255 }
256
257 insert_values(values, &m_int_list);
258 EXPECT_EQ(m_int_list.swap_elts(10, 11), true /* error */);
259 // Expect no change: 10, 11 out of bounds
260 for (int i = 0; i < 10; i++) {
261 EXPECT_EQ(*m_int_list.pop(), i);
262 }
263
264 insert_values(values, &m_int_list);
265 EXPECT_EQ(m_int_list.swap_elts(0, 1), false);
266
267 for (int i = 0; i < 10; i++) {
268 EXPECT_EQ(*m_int_list.pop(), (i == 0 ? 1 : (i == 1 ? 0 : i)));
269 }
270
271 insert_values(values, &m_int_list);
272 EXPECT_EQ(m_int_list.swap_elts(0, 9), false);
273
274 for (int i = 0; i < 10; i++) {
275 EXPECT_EQ(*m_int_list.pop(), (i == 0 ? 9 : (i == 9 ? 0 : i)));
276 }
277
278 insert_values(values, &m_int_list);
279 EXPECT_EQ(m_int_list.swap_elts(9, 0), false);
280
281 for (int i = 0; i < 10; i++) {
282 EXPECT_EQ(*m_int_list.pop(), (i == 0 ? 9 : (i == 9 ? 0 : i)));
283 }
284 }
285
286 } // namespace sql_list_unittest
287