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