1 /*
2 * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11 #include "gtest/gtest.h"
12
13 #include "system_wrappers/interface/list_wrapper.h"
14 #include "system_wrappers/interface/scoped_ptr.h"
15
16 using ::webrtc::ListWrapper;
17 using ::webrtc::ListItem;
18 using ::webrtc::scoped_ptr;
19
20 // Note: kNumberOfElements needs to be even.
21 const unsigned int kNumberOfElements = 10;
22
23 // An opaque implementation of dynamic or statically allocated unsigned ints.
24 // This class makes it possible to use the exact same code for testing of both
25 // the dynamic and static implementation of ListWrapper.
26 // Clarification: ListWrapper has two versions of PushBack(..). It takes an
27 // unsigned integer or a void pointer. The integer implementation takes care
28 // of memory management. The void pointer version expect the caller to manage
29 // the memory associated with the void pointer.
30 // This class works like the integer version but can be implemented on top of
31 // either the integer version or void pointer version of ListWrapper.
32 // Note: the non-virtual fuctions behave the same for both versions.
33 class ListWrapperSimple {
34 public:
35 static ListWrapperSimple* Create(bool static_allocation);
~ListWrapperSimple()36 virtual ~ListWrapperSimple() {}
37
38 // These three functions should be used for manipulating ListItems so that
39 // they are the type corresponding to the underlying implementation.
40 virtual unsigned int GetUnsignedItem(
41 const ListItem* item) const = 0;
42 virtual ListItem* CreateListItem(unsigned int item_id) = 0;
GetSize() const43 unsigned int GetSize() const {
44 return list_.GetSize();
45 }
46 virtual int PushBack(const unsigned int item_id) = 0;
47 virtual int PushFront(const unsigned int item_id) = 0;
48 virtual int PopFront() = 0;
49 virtual int PopBack() = 0;
Empty() const50 bool Empty() const {
51 return list_.Empty();
52 }
First() const53 ListItem* First() const {
54 return list_.First();
55 }
Last() const56 ListItem* Last() const {
57 return list_.Last();
58 }
Next(ListItem * item) const59 ListItem* Next(ListItem* item) const {
60 return list_.Next(item);
61 }
Previous(ListItem * item) const62 ListItem* Previous(ListItem* item) const {
63 return list_.Previous(item);
64 }
65 virtual int Erase(ListItem* item) = 0;
Insert(ListItem * existing_previous_item,ListItem * new_item)66 int Insert(ListItem* existing_previous_item,
67 ListItem* new_item) {
68 const int retval = list_.Insert(existing_previous_item, new_item);
69 if (retval != 0) {
70 EXPECT_TRUE(DestroyListItem(new_item));
71 }
72 return retval;
73 }
74
InsertBefore(ListItem * existing_next_item,ListItem * new_item)75 int InsertBefore(ListItem* existing_next_item,
76 ListItem* new_item) {
77 const int retval = list_.InsertBefore(existing_next_item, new_item);
78 if (retval != 0) {
79 EXPECT_TRUE(DestroyListItem(new_item));
80 }
81 return retval;
82 }
83 protected:
ListWrapperSimple()84 ListWrapperSimple() {}
85
86 virtual bool DestroyListItemContent(ListItem* item) = 0;
DestroyListItem(ListItem * item)87 bool DestroyListItem(ListItem* item) {
88 const bool retval = DestroyListItemContent(item);
89 delete item;
90 return retval;
91 }
92
93 ListWrapper list_;
94 };
95
ClearList(ListWrapperSimple * list_wrapper)96 void ClearList(ListWrapperSimple* list_wrapper) {
97 if (list_wrapper == NULL) {
98 return;
99 }
100 ListItem* list_item = list_wrapper->First();
101 while (list_item != NULL) {
102 EXPECT_EQ(list_wrapper->Erase(list_item), 0);
103 list_item = list_wrapper->First();
104 }
105 }
106
107 class ListWrapperStatic : public ListWrapperSimple {
108 public:
ListWrapperStatic()109 ListWrapperStatic() {}
~ListWrapperStatic()110 virtual ~ListWrapperStatic() {
111 ClearList(this);
112 }
113
GetUnsignedItem(const ListItem * item) const114 virtual unsigned int GetUnsignedItem(const ListItem* item) const {
115 return item->GetUnsignedItem();
116 }
CreateListItem(unsigned int item_id)117 virtual ListItem* CreateListItem(unsigned int item_id) {
118 return new ListItem(item_id);
119 }
DestroyListItemContent(ListItem * item)120 virtual bool DestroyListItemContent(ListItem* item) {
121 return true;
122 }
PushBack(const unsigned int item_id)123 virtual int PushBack(const unsigned int item_id) {
124 return list_.PushBack(item_id);
125 }
PushFront(const unsigned int item_id)126 virtual int PushFront(const unsigned int item_id) {
127 return list_.PushFront(item_id);
128 }
PopFront()129 virtual int PopFront() {
130 return list_.PopFront();
131 }
PopBack()132 virtual int PopBack() {
133 return list_.PopBack();
134 }
Erase(ListItem * item)135 virtual int Erase(ListItem* item) {
136 return list_.Erase(item);
137 }
138 };
139
140 class ListWrapperDynamic : public ListWrapperSimple {
141 public:
ListWrapperDynamic()142 ListWrapperDynamic() {}
~ListWrapperDynamic()143 virtual ~ListWrapperDynamic() {
144 ClearList(this);
145 }
146
GetUnsignedItem(const ListItem * item) const147 virtual unsigned int GetUnsignedItem(const ListItem* item) const {
148 const unsigned int* return_value_pointer =
149 reinterpret_cast<unsigned int*> (item->GetItem());
150 if (return_value_pointer == NULL) {
151 return -1;
152 }
153 return *return_value_pointer;
154 }
CreateListItem(unsigned int item_id)155 virtual ListItem* CreateListItem(unsigned int item_id) {
156 unsigned int* item_id_pointer = new unsigned int;
157 if (item_id_pointer == NULL) {
158 return NULL;
159 }
160 *item_id_pointer = item_id;
161 ListItem* return_value = new ListItem(
162 reinterpret_cast<void*>(item_id_pointer));
163 if (return_value == NULL) {
164 delete item_id_pointer;
165 return NULL;
166 }
167 return return_value;
168 }
DestroyListItemContent(ListItem * item)169 virtual bool DestroyListItemContent(ListItem* item) {
170 if (item == NULL) {
171 return false;
172 }
173 bool return_value = false;
174 unsigned int* item_id_ptr = reinterpret_cast<unsigned int*>(
175 item->GetItem());
176 if (item_id_ptr != NULL) {
177 return_value = true;
178 delete item_id_ptr;
179 }
180 return return_value;
181 }
PushBack(const unsigned int item_id)182 virtual int PushBack(const unsigned int item_id) {
183 unsigned int* item_id_ptr = new unsigned int;
184 if (item_id_ptr == NULL) {
185 return -1;
186 }
187 *item_id_ptr = item_id;
188 const int return_value = list_.PushBack(
189 reinterpret_cast<void*>(item_id_ptr));
190 if (return_value != 0) {
191 delete item_id_ptr;
192 }
193 return return_value;
194 }
PushFront(const unsigned int item_id)195 virtual int PushFront(const unsigned int item_id) {
196 unsigned int* item_id_ptr = new unsigned int;
197 if (item_id_ptr == NULL) {
198 return -1;
199 }
200 *item_id_ptr = item_id;
201 const int return_value = list_.PushFront(
202 reinterpret_cast<void*>(item_id_ptr));
203 if (return_value != 0) {
204 delete item_id_ptr;
205 }
206 return return_value;
207 }
PopFront()208 virtual int PopFront() {
209 return Erase(list_.First());
210 }
PopBack()211 virtual int PopBack() {
212 return Erase(list_.Last());
213 }
Erase(ListItem * item)214 virtual int Erase(ListItem* item) {
215 if (item == NULL) {
216 return -1;
217 }
218 int retval = 0;
219 if (!DestroyListItemContent(item)) {
220 retval = -1;
221 ADD_FAILURE();
222 }
223 if (list_.Erase(item) != 0) {
224 retval = -1;
225 }
226 return retval;
227 }
228 };
229
Create(bool static_allocation)230 ListWrapperSimple* ListWrapperSimple::Create(bool static_allocation) {
231 if(static_allocation)
232 {
233 return new ListWrapperStatic();
234 }
235 return new ListWrapperDynamic();
236 }
237
CreateAscendingList(bool static_allocation)238 ListWrapperSimple* CreateAscendingList(bool static_allocation) {
239 ListWrapperSimple* return_value = ListWrapperSimple::Create(
240 static_allocation);
241 if (return_value == NULL) {
242 return NULL;
243 }
244 for (unsigned int i = 0; i < kNumberOfElements; ++i) {
245 if (return_value->PushBack(i) == -1) {
246 ClearList(return_value);
247 delete return_value;
248 return NULL;
249 }
250 }
251 return return_value;
252 }
253
CreateDescendingList(bool static_allocation)254 ListWrapperSimple* CreateDescendingList(bool static_allocation) {
255 ListWrapperSimple* return_value = ListWrapperSimple::Create(
256 static_allocation);
257 if (return_value == NULL) {
258 return NULL;
259 }
260 for (unsigned int i = 0; i < kNumberOfElements; ++i) {
261 if (return_value->PushBack(kNumberOfElements - i - 1) == -1) {
262 ClearList(return_value);
263 delete return_value;
264 return NULL;
265 }
266 }
267 return return_value;
268 }
269
270 // [0,kNumberOfElements - 1,1,kNumberOfElements - 2,...] (this is why
271 // kNumberOfElements need to be even)
CreateInterleavedList(bool static_allocation)272 ListWrapperSimple* CreateInterleavedList(bool static_allocation) {
273 ListWrapperSimple* return_value = ListWrapperSimple::Create(
274 static_allocation);
275 if (return_value == NULL) {
276 return NULL;
277 }
278 unsigned int uneven_count = 0;
279 unsigned int even_count = 0;
280 for (unsigned int i = 0; i < kNumberOfElements; i++) {
281 unsigned int push_value = 0;
282 if ((i % 2) == 0) {
283 push_value = even_count;
284 even_count++;
285 } else {
286 push_value = kNumberOfElements - uneven_count - 1;
287 uneven_count++;
288 }
289 if (return_value->PushBack(push_value) == -1) {
290 ClearList(return_value);
291 delete return_value;
292 return NULL;
293 }
294 }
295 return return_value;
296 }
297
PrintList(const ListWrapperSimple * list)298 void PrintList(const ListWrapperSimple* list) {
299 ListItem* list_item = list->First();
300 printf("[");
301 while (list_item != NULL)
302 {
303 printf("%3u", list->GetUnsignedItem(list_item));
304 list_item = list->Next(list_item);
305 }
306 printf("]\n");
307 }
308
CompareLists(const ListWrapperSimple * lhs,const ListWrapperSimple * rhs)309 bool CompareLists(const ListWrapperSimple* lhs, const ListWrapperSimple* rhs) {
310 const unsigned int list_size = lhs->GetSize();
311 if (lhs->GetSize() != rhs->GetSize()) {
312 return false;
313 }
314 if (lhs->Empty()) {
315 return rhs->Empty();
316 }
317 unsigned int i = 0;
318 ListItem* lhs_item = lhs->First();
319 ListItem* rhs_item = rhs->First();
320 while (i < list_size) {
321 if (lhs_item == NULL) {
322 return false;
323 }
324 if (rhs_item == NULL) {
325 return false;
326 }
327 if (lhs->GetUnsignedItem(lhs_item) != rhs->GetUnsignedItem(rhs_item)) {
328 return false;
329 }
330 i++;
331 lhs_item = lhs->Next(lhs_item);
332 rhs_item = rhs->Next(rhs_item);
333 }
334 return true;
335 }
336
TEST(ListWrapperTest,ReverseNewIntList)337 TEST(ListWrapperTest,ReverseNewIntList) {
338 // Create a new temporary list with elements reversed those of
339 // new_int_list_
340 const scoped_ptr<ListWrapperSimple> descending_list(
341 CreateDescendingList(rand()%2));
342 ASSERT_FALSE(descending_list.get() == NULL);
343 ASSERT_FALSE(descending_list->Empty());
344 ASSERT_EQ(kNumberOfElements,descending_list->GetSize());
345
346 const scoped_ptr<ListWrapperSimple> ascending_list(
347 CreateAscendingList(rand()%2));
348 ASSERT_FALSE(ascending_list.get() == NULL);
349 ASSERT_FALSE(ascending_list->Empty());
350 ASSERT_EQ(kNumberOfElements,ascending_list->GetSize());
351
352 scoped_ptr<ListWrapperSimple> list_to_reverse(
353 ListWrapperSimple::Create(rand()%2));
354
355 // Reverse the list using PushBack and Previous.
356 for (ListItem* item = ascending_list->Last(); item != NULL;
357 item = ascending_list->Previous(item)) {
358 list_to_reverse->PushBack(ascending_list->GetUnsignedItem(item));
359 }
360
361 ASSERT_TRUE(CompareLists(descending_list.get(), list_to_reverse.get()));
362
363 scoped_ptr<ListWrapperSimple> list_to_un_reverse(
364 ListWrapperSimple::Create(rand()%2));
365 ASSERT_FALSE(list_to_un_reverse.get() == NULL);
366 // Reverse the reversed list using PushFront and Next.
367 for (ListItem* item = list_to_reverse->First(); item != NULL;
368 item = list_to_reverse->Next(item)) {
369 list_to_un_reverse->PushFront(list_to_reverse->GetUnsignedItem(item));
370 }
371 ASSERT_TRUE(CompareLists(ascending_list.get(), list_to_un_reverse.get()));
372 }
373
TEST(ListWrapperTest,PopTest)374 TEST(ListWrapperTest,PopTest) {
375 scoped_ptr<ListWrapperSimple> ascending_list(CreateAscendingList(rand()%2));
376 ASSERT_FALSE(ascending_list.get() == NULL);
377 ASSERT_FALSE(ascending_list->Empty());
378 EXPECT_EQ(0, ascending_list->PopFront());
379 EXPECT_EQ(1U, ascending_list->GetUnsignedItem(ascending_list->First()));
380
381 EXPECT_EQ(0, ascending_list->PopBack());
382 EXPECT_EQ(kNumberOfElements - 2, ascending_list->GetUnsignedItem(
383 ascending_list->Last()));
384 EXPECT_EQ(kNumberOfElements - 2, ascending_list->GetSize());
385 }
386
387 // Use Insert to interleave two lists.
TEST(ListWrapperTest,InterLeaveTest)388 TEST(ListWrapperTest,InterLeaveTest) {
389 scoped_ptr<ListWrapperSimple> interleave_list(
390 CreateAscendingList(rand()%2));
391 ASSERT_FALSE(interleave_list.get() == NULL);
392 ASSERT_FALSE(interleave_list->Empty());
393
394 scoped_ptr<ListWrapperSimple> descending_list(
395 CreateDescendingList(rand()%2));
396 ASSERT_FALSE(descending_list.get() == NULL);
397
398 for (unsigned int i = 0; i < kNumberOfElements/2; ++i) {
399 ASSERT_EQ(0, interleave_list->PopBack());
400 ASSERT_EQ(0, descending_list->PopBack());
401 }
402 ASSERT_EQ(kNumberOfElements/2, interleave_list->GetSize());
403 ASSERT_EQ(kNumberOfElements/2, descending_list->GetSize());
404
405 unsigned int insert_position = kNumberOfElements/2;
406 ASSERT_EQ(insert_position * 2, kNumberOfElements);
407 while (!descending_list->Empty())
408 {
409 ListItem* item = descending_list->Last();
410 ASSERT_FALSE(item == NULL);
411
412 const unsigned int item_id = descending_list->GetUnsignedItem(item);
413 ASSERT_EQ(0, descending_list->Erase(item));
414
415 ListItem* insert_item = interleave_list->CreateListItem(item_id);
416 ASSERT_FALSE(insert_item == NULL);
417 item = interleave_list->First();
418 ASSERT_FALSE(item == NULL);
419 for (unsigned int j = 0; j < insert_position - 1; ++j) {
420 item = interleave_list->Next(item);
421 ASSERT_FALSE(item == NULL);
422 }
423 EXPECT_EQ(0, interleave_list->Insert(item, insert_item));
424 --insert_position;
425 }
426
427 scoped_ptr<ListWrapperSimple> interleaved_list(
428 CreateInterleavedList(rand()%2));
429 ASSERT_FALSE(interleaved_list.get() == NULL);
430 ASSERT_FALSE(interleaved_list->Empty());
431 ASSERT_TRUE(CompareLists(interleaved_list.get(), interleave_list.get()));
432 }
433
434 // Use InsertBefore to interleave two lists.
TEST(ListWrapperTest,InterLeaveTestII)435 TEST(ListWrapperTest,InterLeaveTestII) {
436 scoped_ptr<ListWrapperSimple> interleave_list(
437 CreateDescendingList(rand()%2));
438 ASSERT_FALSE(interleave_list.get() == NULL);
439 ASSERT_FALSE(interleave_list->Empty());
440
441 scoped_ptr<ListWrapperSimple> ascending_list(CreateAscendingList(rand()%2));
442 ASSERT_FALSE(ascending_list.get() == NULL);
443
444 for (unsigned int i = 0; i < kNumberOfElements/2; ++i) {
445 ASSERT_EQ(0, interleave_list->PopBack());
446 ASSERT_EQ(0, ascending_list->PopBack());
447 }
448 ASSERT_EQ(kNumberOfElements/2, interleave_list->GetSize());
449 ASSERT_EQ(kNumberOfElements/2, ascending_list->GetSize());
450
451 unsigned int insert_position = kNumberOfElements/2;
452 ASSERT_EQ(insert_position * 2, kNumberOfElements);
453 while (!ascending_list->Empty())
454 {
455 ListItem* item = ascending_list->Last();
456 ASSERT_FALSE(item == NULL);
457
458 const unsigned int item_id = ascending_list->GetUnsignedItem(item);
459 ASSERT_EQ(0,ascending_list->Erase(item));
460
461 ListItem* insert_item = interleave_list->CreateListItem(item_id);
462 ASSERT_FALSE(insert_item == NULL);
463 item = interleave_list->First();
464 ASSERT_FALSE(item == NULL);
465 for (unsigned int j = 0; j < insert_position - 1; ++j) {
466 item = interleave_list->Next(item);
467 ASSERT_FALSE(item == NULL);
468 }
469 EXPECT_EQ(interleave_list->InsertBefore(item, insert_item), 0);
470 --insert_position;
471 }
472
473 scoped_ptr<ListWrapperSimple> interleaved_list(
474 CreateInterleavedList(rand()%2));
475 ASSERT_FALSE(interleaved_list.get() == NULL);
476 ASSERT_FALSE(interleaved_list->Empty());
477
478 ASSERT_TRUE(CompareLists(interleaved_list.get(), interleave_list.get()));
479 }
480