1 // Copyright (c) 2017 Google Inc.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include <utility>
16 #include <vector>
17
18 #include "gmock/gmock.h"
19 #include "source/util/ilist.h"
20
21 namespace spvtools {
22 namespace utils {
23 namespace {
24
25 using ::testing::ElementsAre;
26 using IListTest = ::testing::Test;
27
28 class TestNode : public IntrusiveNodeBase<TestNode> {
29 public:
TestNode()30 TestNode() : IntrusiveNodeBase<TestNode>() {}
31 int data_;
32 };
33
34 class TestList : public IntrusiveList<TestNode> {
35 public:
36 TestList() = default;
TestList(TestList && that)37 TestList(TestList&& that) : IntrusiveList<TestNode>(std::move(that)) {}
operator =(TestList && that)38 TestList& operator=(TestList&& that) {
39 static_cast<IntrusiveList<TestNode>&>(*this) =
40 static_cast<IntrusiveList<TestNode>&&>(that);
41 return *this;
42 }
43 };
44
45 // This test checks the push_back method, as well as using an iterator to
46 // traverse the list from begin() to end(). This implicitly test the
47 // PreviousNode and NextNode functions.
TEST(IListTest,PushBack)48 TEST(IListTest, PushBack) {
49 TestNode nodes[10];
50 TestList list;
51 for (int i = 0; i < 10; i++) {
52 nodes[i].data_ = i;
53 list.push_back(&nodes[i]);
54 }
55
56 std::vector<int> output;
57 for (auto& i : list) output.push_back(i.data_);
58
59 EXPECT_THAT(output, ElementsAre(0, 1, 2, 3, 4, 5, 6, 7, 8, 9));
60 }
61
62 // Returns a list containing the values 0 to n-1 using the first n elements of
63 // nodes to build the list.
BuildList(TestNode nodes[],int n)64 TestList BuildList(TestNode nodes[], int n) {
65 TestList list;
66 for (int i = 0; i < n; i++) {
67 nodes[i].data_ = i;
68 list.push_back(&nodes[i]);
69 }
70 return list;
71 }
72
73 // Test decrementing begin()
TEST(IListTest,DecrementingBegin)74 TEST(IListTest, DecrementingBegin) {
75 TestNode nodes[10];
76 TestList list = BuildList(nodes, 10);
77 EXPECT_EQ(--list.begin(), list.end());
78 }
79
80 // Test incrementing end()
TEST(IListTest,IncrementingEnd1)81 TEST(IListTest, IncrementingEnd1) {
82 TestNode nodes[10];
83 TestList list = BuildList(nodes, 10);
84 EXPECT_EQ((++list.end())->data_, 0);
85 }
86
87 // Test incrementing end() should equal begin()
TEST(IListTest,IncrementingEnd2)88 TEST(IListTest, IncrementingEnd2) {
89 TestNode nodes[10];
90 TestList list = BuildList(nodes, 10);
91 EXPECT_EQ(++list.end(), list.begin());
92 }
93
94 // Test decrementing end()
TEST(IListTest,DecrementingEnd)95 TEST(IListTest, DecrementingEnd) {
96 TestNode nodes[10];
97 TestList list = BuildList(nodes, 10);
98 EXPECT_EQ((--list.end())->data_, 9);
99 }
100
101 // Test the move constructor for the list class.
TEST(IListTest,MoveConstructor)102 TEST(IListTest, MoveConstructor) {
103 TestNode nodes[10];
104 TestList list = BuildList(nodes, 10);
105 std::vector<int> output;
106 for (auto& i : list) output.push_back(i.data_);
107
108 EXPECT_THAT(output, ElementsAre(0, 1, 2, 3, 4, 5, 6, 7, 8, 9));
109 }
110
111 // Using a const list so we can test the const_iterator.
TEST(IListTest,ConstIterator)112 TEST(IListTest, ConstIterator) {
113 TestNode nodes[10];
114 const TestList list = BuildList(nodes, 10);
115 std::vector<int> output;
116 for (auto& i : list) output.push_back(i.data_);
117
118 EXPECT_THAT(output, ElementsAre(0, 1, 2, 3, 4, 5, 6, 7, 8, 9));
119 }
120
121 // Uses the move assignement instead of the move constructor.
TEST(IListTest,MoveAssignment)122 TEST(IListTest, MoveAssignment) {
123 TestNode nodes[10];
124 TestList list;
125 list = BuildList(nodes, 10);
126 std::vector<int> output;
127 for (auto& i : list) output.push_back(i.data_);
128
129 EXPECT_THAT(output, ElementsAre(0, 1, 2, 3, 4, 5, 6, 7, 8, 9));
130 }
131
132 // Test inserting a new element at the end of a list using the IntrusiveNodeBase
133 // "InsertAfter" function.
TEST(IListTest,InsertAfter1)134 TEST(IListTest, InsertAfter1) {
135 TestNode nodes[10];
136 TestList list = BuildList(nodes, 5);
137
138 nodes[5].data_ = 5;
139 nodes[5].InsertAfter(&nodes[4]);
140
141 std::vector<int> output;
142 for (auto& i : list) output.push_back(i.data_);
143
144 EXPECT_THAT(output, ElementsAre(0, 1, 2, 3, 4, 5));
145 }
146
147 // Test inserting a new element in the middle of a list using the
148 // IntrusiveNodeBase "InsertAfter" function.
TEST(IListTest,InsertAfter2)149 TEST(IListTest, InsertAfter2) {
150 TestNode nodes[10];
151 TestList list = BuildList(nodes, 5);
152
153 nodes[5].data_ = 5;
154 nodes[5].InsertAfter(&nodes[2]);
155
156 std::vector<int> output;
157 for (auto& i : list) output.push_back(i.data_);
158
159 EXPECT_THAT(output, ElementsAre(0, 1, 2, 5, 3, 4));
160 }
161
162 // Test moving an element already in the list in the middle of a list using the
163 // IntrusiveNodeBase "InsertAfter" function.
TEST(IListTest,MoveUsingInsertAfter1)164 TEST(IListTest, MoveUsingInsertAfter1) {
165 TestNode nodes[10];
166 TestList list = BuildList(nodes, 6);
167
168 nodes[5].InsertAfter(&nodes[2]);
169
170 std::vector<int> output;
171 for (auto& i : list) output.push_back(i.data_);
172
173 EXPECT_THAT(output, ElementsAre(0, 1, 2, 5, 3, 4));
174 }
175
176 // Move the element at the start of the list into the middle.
TEST(IListTest,MoveUsingInsertAfter2)177 TEST(IListTest, MoveUsingInsertAfter2) {
178 TestNode nodes[10];
179 TestList list = BuildList(nodes, 6);
180
181 nodes[0].InsertAfter(&nodes[2]);
182
183 std::vector<int> output;
184 for (auto& i : list) output.push_back(i.data_);
185
186 EXPECT_THAT(output, ElementsAre(1, 2, 0, 3, 4, 5));
187 }
188
189 // Move an element in the middle of the list to the end.
TEST(IListTest,MoveUsingInsertAfter3)190 TEST(IListTest, MoveUsingInsertAfter3) {
191 TestNode nodes[10];
192 TestList list = BuildList(nodes, 6);
193
194 nodes[2].InsertAfter(&nodes[5]);
195
196 std::vector<int> output;
197 for (auto& i : list) output.push_back(i.data_);
198
199 EXPECT_THAT(output, ElementsAre(0, 1, 3, 4, 5, 2));
200 }
201
202 // Removing an element from the middle of a list.
TEST(IListTest,Remove1)203 TEST(IListTest, Remove1) {
204 TestNode nodes[10];
205 TestList list = BuildList(nodes, 6);
206
207 nodes[2].RemoveFromList();
208
209 std::vector<int> output;
210 for (auto& i : list) output.push_back(i.data_);
211
212 EXPECT_THAT(output, ElementsAre(0, 1, 3, 4, 5));
213 }
214
215 // Removing an element from the beginning of the list.
TEST(IListTest,Remove2)216 TEST(IListTest, Remove2) {
217 TestNode nodes[10];
218 TestList list = BuildList(nodes, 6);
219
220 nodes[0].RemoveFromList();
221
222 std::vector<int> output;
223 for (auto& i : list) output.push_back(i.data_);
224
225 EXPECT_THAT(output, ElementsAre(1, 2, 3, 4, 5));
226 }
227
228 // Removing the last element of a list.
TEST(IListTest,Remove3)229 TEST(IListTest, Remove3) {
230 TestNode nodes[10];
231 TestList list = BuildList(nodes, 6);
232
233 nodes[5].RemoveFromList();
234
235 std::vector<int> output;
236 for (auto& i : list) output.push_back(i.data_);
237
238 EXPECT_THAT(output, ElementsAre(0, 1, 2, 3, 4));
239 }
240
241 // Test that operator== and operator!= work properly for the iterator class.
TEST(IListTest,IteratorEqual)242 TEST(IListTest, IteratorEqual) {
243 TestNode nodes[10];
244 TestList list = BuildList(nodes, 6);
245
246 std::vector<int> output;
247 for (auto i = list.begin(); i != list.end(); ++i)
248 for (auto j = list.begin(); j != list.end(); ++j)
249 if (i == j) output.push_back(i->data_);
250
251 EXPECT_THAT(output, ElementsAre(0, 1, 2, 3, 4, 5));
252 }
253
254 // Test MoveBefore. Moving into middle of a list.
TEST(IListTest,MoveBefore1)255 TEST(IListTest, MoveBefore1) {
256 TestNode nodes[10];
257 TestList list1 = BuildList(nodes, 6);
258 TestList list2 = BuildList(nodes + 6, 3);
259
260 TestList::iterator insertion_point = list1.begin();
261 ++insertion_point;
262 insertion_point.MoveBefore(&list2);
263
264 std::vector<int> output;
265 for (auto i = list1.begin(); i != list1.end(); ++i) {
266 output.push_back(i->data_);
267 }
268
269 EXPECT_THAT(output, ElementsAre(0, 0, 1, 2, 1, 2, 3, 4, 5));
270 }
271
272 // Test MoveBefore. Moving to the start of a list.
TEST(IListTest,MoveBefore2)273 TEST(IListTest, MoveBefore2) {
274 TestNode nodes[10];
275 TestList list1 = BuildList(nodes, 6);
276 TestList list2 = BuildList(nodes + 6, 3);
277
278 TestList::iterator insertion_point = list1.begin();
279 insertion_point.MoveBefore(&list2);
280
281 std::vector<int> output;
282 for (auto i = list1.begin(); i != list1.end(); ++i) {
283 output.push_back(i->data_);
284 }
285
286 EXPECT_THAT(output, ElementsAre(0, 1, 2, 0, 1, 2, 3, 4, 5));
287 }
288
289 // Test MoveBefore. Moving to the end of a list.
TEST(IListTest,MoveBefore3)290 TEST(IListTest, MoveBefore3) {
291 TestNode nodes[10];
292 TestList list1 = BuildList(nodes, 6);
293 TestList list2 = BuildList(nodes + 6, 3);
294
295 TestList::iterator insertion_point = list1.end();
296 insertion_point.MoveBefore(&list2);
297
298 std::vector<int> output;
299 for (auto i = list1.begin(); i != list1.end(); ++i) {
300 output.push_back(i->data_);
301 }
302
303 EXPECT_THAT(output, ElementsAre(0, 1, 2, 3, 4, 5, 0, 1, 2));
304 }
305
306 // Test MoveBefore. Moving an empty list.
TEST(IListTest,MoveBefore4)307 TEST(IListTest, MoveBefore4) {
308 TestNode nodes[10];
309 TestList list1 = BuildList(nodes, 6);
310 TestList list2;
311
312 TestList::iterator insertion_point = list1.end();
313 insertion_point.MoveBefore(&list2);
314
315 std::vector<int> output;
316 for (auto i = list1.begin(); i != list1.end(); ++i) {
317 output.push_back(i->data_);
318 }
319
320 EXPECT_THAT(output, ElementsAre(0, 1, 2, 3, 4, 5));
321 }
322
323 } // namespace
324 } // namespace utils
325 } // namespace spvtools
326