From 8dcd789d2b2bd250d6d07429257b61e9821f8df8 Mon Sep 17 00:00:00 2001 From: "hellner@google.com" Date: Tue, 7 Jun 2011 11:41:15 +0000 Subject: [PATCH] Unit test for list wrapper under system_wrappers Review URL: http://webrtc-codereview.appspot.com/32005 git-svn-id: http://webrtc.googlecode.com/svn/trunk@47 4adac7df-926f-26a2-2b94-8c16560cd09d --- system_wrappers/OWNERS | 3 +- system_wrappers/source/list_unittest.cc | 475 ++++++++++++++++++ .../source/system_wrappers_tests.gyp | 36 ++ 3 files changed, 513 insertions(+), 1 deletion(-) create mode 100644 system_wrappers/source/list_unittest.cc create mode 100644 system_wrappers/source/system_wrappers_tests.gyp diff --git a/system_wrappers/OWNERS b/system_wrappers/OWNERS index 55ce6f820f..32dcbbc501 100644 --- a/system_wrappers/OWNERS +++ b/system_wrappers/OWNERS @@ -3,4 +3,5 @@ pwestin@google.com perkj@google.com henrika@google.com grunell@google.com -mflodman@google.com \ No newline at end of file +mflodman@google.com +niklase@google.com \ No newline at end of file diff --git a/system_wrappers/source/list_unittest.cc b/system_wrappers/source/list_unittest.cc new file mode 100644 index 0000000000..3f3c88ffb7 --- /dev/null +++ b/system_wrappers/source/list_unittest.cc @@ -0,0 +1,475 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "gtest/gtest.h" + +#include "list_wrapper.h" + +using ::webrtc::ListWrapper; +using ::webrtc::ListItem; + +// Note: kNumberOfElements needs to be even. +const unsigned int kNumberOfElements = 10; + +// An opaque implementation of dynamic or statically allocated unsigned ints. +// This class makes it possible to use the exact same code for testing of both +// the dynamic and static implementation of ListWrapper. +// Clarification: ListWrapper has two versions of PushBack(..). It takes an +// unsigned integer or a void pointer. The integer implementation takes care +// of memory management. The void pointer version expect the caller to manage +// the memory associated with the void pointer. +// This class works like the integer version but can be implemented on top of +// either the integer version or void pointer version of ListWrapper. +// Note: the non-virtual fuctions behave the same for both versions. +class ListWrapperSimple { +public: + static ListWrapperSimple* Create(bool static_allocation); + virtual ~ListWrapperSimple() {} + + // These three functions should be used for manipulating ListItems so that + // they are the type corresponding to the underlying implementation. + virtual unsigned int GetUnsignedItem( + const ListItem* item) const = 0; + virtual ListItem* CreateListItem(unsigned int item_id) = 0; + virtual bool DestroyListItem(ListItem* item) = 0; + + unsigned int GetSize() const { + return list_.GetSize(); + } + virtual int PushBack(const unsigned int item_id) = 0; + virtual int PushFront(const unsigned int item_id) = 0; + virtual int PopFront() = 0; + virtual int PopBack() = 0; + bool Empty() const { + return list_.Empty(); + } + ListItem* First() const { + return list_.First(); + } + ListItem* Last() const { + return list_.Last(); + } + ListItem* Next(ListItem* item) const { + return list_.Next(item); + } + ListItem* Previous(ListItem* item) const { + return list_.Previous(item); + } + virtual int Erase(ListItem* item) = 0; + int Insert(ListItem* existing_previous_item, + ListItem* new_item) { + return list_.Insert(existing_previous_item, new_item); + } + + int InsertBefore(ListItem* existing_next_item, + ListItem* new_item) { + return list_.InsertBefore(existing_next_item, new_item); + } +protected: + ListWrapperSimple() {} + + ListWrapper list_; +}; + +class ListWrapperStatic : public ListWrapperSimple { +public: + ListWrapperStatic() {} + virtual ~ListWrapperStatic() {} + + virtual unsigned int GetUnsignedItem(const ListItem* item) const { + return item->GetUnsignedItem(); + } + virtual ListItem* CreateListItem(unsigned int item_id) { + return new ListItem(item_id); + } + virtual bool DestroyListItem(ListItem* item) { + if (item == NULL) { + return false; + } + delete item; + return true; + } + virtual int PushBack(const unsigned int item_id) { + return list_.PushBack(item_id); + } + virtual int PushFront(const unsigned int item_id) { + return list_.PushFront(item_id); + } + virtual int PopFront() { + return list_.PopFront(); + } + virtual int PopBack() { + return list_.PopBack(); + } + virtual int Erase(ListItem* item) { + return list_.Erase(item); + } +}; + +class ListWrapperDynamic : public ListWrapperSimple { +public: + ListWrapperDynamic() {} + virtual ~ListWrapperDynamic() {} + + virtual unsigned int GetUnsignedItem(const ListItem* item) const { + const unsigned int* return_value_pointer = + reinterpret_cast (item->GetItem()); + if (return_value_pointer == NULL) { + return -1; + } + return *return_value_pointer; + } + virtual ListItem* CreateListItem(unsigned int item_id) { + unsigned int* item_id_pointer = new unsigned int; + if (item_id_pointer == NULL) { + return NULL; + } + *item_id_pointer = item_id; + ListItem* return_value = new ListItem( + reinterpret_cast(item_id_pointer)); + if (return_value == NULL) { + delete item_id_pointer; + return NULL; + } + return return_value; + } + virtual bool DestroyListItem(ListItem* item) { + if (item == NULL) { + return false; + } + bool return_value = false; + unsigned int* item_id_ptr = reinterpret_cast( + item->GetItem()); + if (item_id_ptr != NULL) { + return_value = true; + delete item_id_ptr; + } + delete item; + return return_value; + } + virtual int PushBack(const unsigned int item_id) { + unsigned int* item_id_ptr = new unsigned int; + if (item_id_ptr == NULL) { + return -1; + } + *item_id_ptr = item_id; + const int return_value = list_.PushBack( + reinterpret_cast(item_id_ptr)); + if (return_value != 0) { + delete item_id_ptr; + } + return return_value; + } + virtual int PushFront(const unsigned int item_id) { + unsigned int* item_id_ptr = new unsigned int; + if (item_id_ptr == NULL) { + return -1; + } + *item_id_ptr = item_id; + const int return_value = list_.PushFront( + reinterpret_cast(item_id_ptr)); + if (return_value != 0) { + delete item_id_ptr; + } + return return_value; + } + virtual int PopFront() { + return Erase(list_.First()); + } + virtual int PopBack() { + return Erase(list_.Last()); + } + virtual int Erase(ListItem* item) { + if (item == NULL) { + return -1; + } + unsigned int* item_id_ptr = reinterpret_cast ( + item->GetItem()); + int return_value = -1; + if (item_id_ptr != NULL) { + delete item_id_ptr; + return_value = 0; + } + if (list_.Erase(item) != 0) { + return -1; + } + return return_value; + } +}; + +ListWrapperSimple* ListWrapperSimple::Create(bool static_allocation) { + if(static_allocation) + { + return new ListWrapperStatic(); + } + return new ListWrapperDynamic(); +} + +void ClearList(ListWrapperSimple* list) { + if (list == NULL) + { + return; + } + while (list->Erase(list->First()) == 0) { + } +} + +ListWrapperSimple* CreateAscendingList(bool static_allocation) { + ListWrapperSimple* return_value = ListWrapperSimple::Create( + static_allocation); + if (return_value == NULL) { + return NULL; + } + for (unsigned int i = 0; i < kNumberOfElements; ++i) { + if (return_value->PushBack(i) == -1) { + ClearList(return_value); + delete return_value; + return NULL; + } + } + return return_value; +} + +ListWrapperSimple* CreateDecendingList(bool static_allocation) { + ListWrapperSimple* return_value = ListWrapperSimple::Create( + static_allocation); + if (return_value == NULL) { + return NULL; + } + for (unsigned int i = 0; i < kNumberOfElements; ++i) { + if (return_value->PushBack(kNumberOfElements - i - 1) == -1) { + ClearList(return_value); + delete return_value; + return NULL; + } + } + return return_value; +} + +// [0,kNumberOfElements - 1,1,kNumberOfElements - 2,...] (this is why +// kNumberOfElements need to be even) +ListWrapperSimple* CreateInterleavedList(bool static_allocation) { + ListWrapperSimple* return_value = ListWrapperSimple::Create( + static_allocation); + if (return_value == NULL) { + return NULL; + } + unsigned int uneven_count = 0; + unsigned int even_count = 0; + for (unsigned int i = 0; i < kNumberOfElements; i++) { + unsigned int push_value = 0; + if ((i % 2) == 0) { + push_value = even_count; + even_count++; + } else { + push_value = kNumberOfElements - uneven_count - 1; + uneven_count++; + } + if (return_value->PushBack(push_value) == -1) { + ClearList(return_value); + delete return_value; + return NULL; + } + } + return return_value; +} + +void PrintList(const ListWrapperSimple* list) { + ListItem* list_item = list->First(); + printf("["); + while (list_item != NULL) + { + printf("%3u", list->GetUnsignedItem(list_item)); + list_item = list->Next(list_item); + } + printf("]\n"); +} + +bool CompareLists(const ListWrapperSimple* lhs, const ListWrapperSimple* rhs) { + const unsigned int list_size = lhs->GetSize(); + if (lhs->GetSize() != rhs->GetSize()) { + return false; + } + if (lhs->Empty()) { + return rhs->Empty(); + } + unsigned int i = 0; + ListItem* lhs_item = lhs->First(); + ListItem* rhs_item = rhs->First(); + while (i < list_size) { + if (lhs_item == NULL) { + return false; + } + if (rhs_item == NULL) { + return false; + } + if (lhs->GetUnsignedItem(lhs_item) != rhs->GetUnsignedItem(rhs_item)) { + return false; + } + i++; + lhs_item = lhs->Next(lhs_item); + rhs_item = rhs->Next(rhs_item); + } + return true; +} + +TEST(ListWrapperTest,ReverseNewIntList) { + // Create a new temporary list with elements reversed those of + // new_int_list_ + const ListWrapperSimple* decending_list = CreateDecendingList(rand()%2); + ASSERT_FALSE(decending_list == NULL); + ASSERT_FALSE(decending_list->Empty()); + ASSERT_EQ(kNumberOfElements,decending_list->GetSize()); + + const ListWrapperSimple* ascending_list = CreateAscendingList(rand()%2); + ASSERT_FALSE(ascending_list == NULL); + ASSERT_FALSE(ascending_list->Empty()); + ASSERT_EQ(kNumberOfElements,ascending_list->GetSize()); + + ListWrapperSimple* list_to_reverse = ListWrapperSimple::Create(rand()%2); + + // Reverse the list using PushBack and Previous. + for (ListItem* item = ascending_list->Last(); item != NULL; + item = ascending_list->Previous(item)) { + list_to_reverse->PushBack(ascending_list->GetUnsignedItem(item)); + } + + ASSERT_TRUE(CompareLists(decending_list,list_to_reverse)); + + ListWrapperSimple* list_to_un_reverse = + ListWrapperSimple::Create(rand()%2); + ASSERT_FALSE(list_to_un_reverse == NULL); + // Reverse the reversed list using PushFront and Next. + for (ListItem* item = list_to_reverse->First(); item != NULL; + item = list_to_reverse->Next(item)) { + list_to_un_reverse->PushFront(list_to_reverse->GetUnsignedItem(item)); + } + + ASSERT_TRUE(CompareLists(ascending_list,list_to_un_reverse)); +} + +TEST(ListWrapperTest,PopTest) { + ListWrapperSimple* ascending_list = CreateAscendingList(rand()%2); + ASSERT_FALSE(ascending_list == NULL); + ASSERT_FALSE(ascending_list->Empty()); + EXPECT_EQ(0,ascending_list->PopFront()); + EXPECT_EQ(1,ascending_list->GetUnsignedItem(ascending_list->First())); + + EXPECT_EQ(0,ascending_list->PopBack()); + EXPECT_EQ(kNumberOfElements - 2,ascending_list->GetUnsignedItem( + ascending_list->Last())); + EXPECT_EQ(kNumberOfElements - 2, ascending_list->GetSize()); +} + +// Use Insert to interleave two lists. +TEST(ListWrapperTest,InterLeaveTest) { + ListWrapperSimple* interleave_list = CreateAscendingList(rand()%2); + ASSERT_FALSE(interleave_list == NULL); + ASSERT_FALSE(interleave_list->Empty()); + + ListWrapperSimple* decending_list = CreateDecendingList(rand()%2); + ASSERT_FALSE(decending_list == NULL); + + for (int i = 0; i < kNumberOfElements/2; ++i) { + ASSERT_EQ(0,interleave_list->PopBack()); + ASSERT_EQ(0,decending_list->PopBack()); + } + ASSERT_EQ(kNumberOfElements/2,interleave_list->GetSize()); + ASSERT_EQ(kNumberOfElements/2,decending_list->GetSize()); + + int insert_position = kNumberOfElements/2; + ASSERT_EQ(insert_position * 2, kNumberOfElements); + while (!decending_list->Empty()) + { + ListItem* item = decending_list->Last(); + ASSERT_FALSE(item == NULL); + + const unsigned int item_id = decending_list->GetUnsignedItem(item); + ASSERT_EQ(0,decending_list->Erase(item)); + + ListItem* insert_item = interleave_list->CreateListItem(item_id); + ASSERT_FALSE(insert_item == NULL); + item = interleave_list->First(); + ASSERT_FALSE(item == NULL); + for (int j = 0; j < insert_position - 1; ++j) { + item = interleave_list->Next(item); + ASSERT_FALSE(item == NULL); + } + if (0 != interleave_list->Insert(item,insert_item)) { + interleave_list->DestroyListItem(insert_item); + FAIL(); + } + --insert_position; + } + + ListWrapperSimple* interleaved_list = CreateInterleavedList(rand()%2); + ASSERT_FALSE(interleaved_list == NULL); + ASSERT_FALSE(interleaved_list->Empty()); + + ASSERT_TRUE(CompareLists(interleaved_list,interleave_list)); +} + +// Use InsertBefore to interleave two lists. +TEST(ListWrapperTest,InterLeaveTestII) { + ListWrapperSimple* interleave_list = CreateDecendingList(rand()%2); + ASSERT_FALSE(interleave_list == NULL); + ASSERT_FALSE(interleave_list->Empty()); + + ListWrapperSimple* ascending_list = CreateAscendingList(rand()%2); + ASSERT_FALSE(ascending_list == NULL); + + for (int i = 0; i < kNumberOfElements/2; ++i) { + ASSERT_EQ(0,interleave_list->PopBack()); + ASSERT_EQ(0,ascending_list->PopBack()); + } + ASSERT_EQ(kNumberOfElements/2,interleave_list->GetSize()); + ASSERT_EQ(kNumberOfElements/2,ascending_list->GetSize()); + + int insert_position = kNumberOfElements/2; + ASSERT_EQ(insert_position * 2, kNumberOfElements); + while (!ascending_list->Empty()) + { + ListItem* item = ascending_list->Last(); + ASSERT_FALSE(item == NULL); + + const unsigned int item_id = ascending_list->GetUnsignedItem(item); + ASSERT_EQ(0,ascending_list->Erase(item)); + + ListItem* insert_item = interleave_list->CreateListItem(item_id); + ASSERT_FALSE(insert_item == NULL); + item = interleave_list->First(); + ASSERT_FALSE(item == NULL); + for (int j = 0; j < insert_position - 1; ++j) { + item = interleave_list->Next(item); + ASSERT_FALSE(item == NULL); + } + if (0 != interleave_list->InsertBefore(item,insert_item)) { + interleave_list->DestroyListItem(insert_item); + FAIL(); + } + --insert_position; + } + + ListWrapperSimple* interleaved_list = CreateInterleavedList(rand()%2); + ASSERT_FALSE(interleaved_list == NULL); + ASSERT_FALSE(interleaved_list->Empty()); + + ASSERT_TRUE(CompareLists(interleaved_list,interleave_list)); +} + +int main(int argc, char **argv) +{ + ::testing::InitGoogleTest(&argc, argv); + // Added return_value so that it's convenient to put a breakpoint before + // exiting please note that the return value from RUN_ALL_TESTS() must + // be returned by the main function. + const int return_value = RUN_ALL_TESTS(); + return return_value; +} diff --git a/system_wrappers/source/system_wrappers_tests.gyp b/system_wrappers/source/system_wrappers_tests.gyp new file mode 100644 index 0000000000..9d56645bf5 --- /dev/null +++ b/system_wrappers/source/system_wrappers_tests.gyp @@ -0,0 +1,36 @@ +# Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. +# +# Use of this source code is governed by a BSD-style license +# that can be found in the LICENSE file in the root of the source +# tree. An additional intellectual property rights grant can be found +# in the file PATENTS. All contributing project authors may +# be found in the AUTHORS file in the root of the source tree. + +{ + 'includes': [ + '../../common_settings.gypi', + ], + 'targets': [ + { + 'target_name': 'unittest', + 'type': 'executable', + 'dependencies': [ + '../../system_wrappers/source/system_wrappers.gyp:system_wrappers', + '../../../testing/gtest.gyp:gtest', + '../../../testing/gtest.gyp:gtest_main', + ], + 'include_dirs': [ + '../../../testing/gtest/include', + ], + 'sources': [ + 'list_unittest.cc', + ], + }, + ], +} + +# Local Variables: +# tab-width:2 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=2 shiftwidth=2: