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