| /* | |
| * Copyright (C) 2013 The Android Open Source Project | |
| * All rights reserved. | |
| * | |
| * Redistribution and use in source and binary forms, with or without | |
| * modification, are permitted provided that the following conditions | |
| * are met: | |
| * * Redistributions of source code must retain the above copyright | |
| * notice, this list of conditions and the following disclaimer. | |
| * * Redistributions in binary form must reproduce the above copyright | |
| * notice, this list of conditions and the following disclaimer in | |
| * the documentation and/or other materials provided with the | |
| * distribution. | |
| * | |
| * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
| * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
| * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | |
| * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | |
| * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | |
| * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, | |
| * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS | |
| * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED | |
| * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | |
| * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT | |
| * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
| * SUCH DAMAGE. | |
| */ | |
| #include <stdlib.h> | |
| #include <string> | |
| #include <sstream> | |
| #include <gtest/gtest.h> | |
| #include "linked_list.h" | |
| namespace { | |
| bool alloc_called = false; | |
| bool free_called = false; | |
| class LinkedListTestAllocator { | |
| public: | |
| typedef LinkedListEntry<const char> entry_t; | |
| static entry_t* alloc() { | |
| alloc_called = true; | |
| return reinterpret_cast<entry_t*>(::malloc(sizeof(entry_t))); | |
| } | |
| static void free(entry_t* p) { | |
| free_called = true; | |
| ::free(p); | |
| } | |
| private: | |
| DISALLOW_IMPLICIT_CONSTRUCTORS(LinkedListTestAllocator); | |
| }; | |
| typedef LinkedList<const char, LinkedListTestAllocator> test_list_t; | |
| std::string test_list_to_string(test_list_t& list) { | |
| std::stringstream ss; | |
| list.for_each([&] (const char* c) { | |
| ss << c; | |
| }); | |
| return ss.str(); | |
| } | |
| }; | |
| TEST(linked_list, simple) { | |
| alloc_called = free_called = false; | |
| test_list_t list; | |
| ASSERT_EQ("", test_list_to_string(list)); | |
| ASSERT_TRUE(!alloc_called); | |
| ASSERT_TRUE(!free_called); | |
| list.push_front("a"); | |
| ASSERT_TRUE(alloc_called); | |
| ASSERT_TRUE(!free_called); | |
| ASSERT_EQ("a", test_list_to_string(list)); | |
| list.push_front("b"); | |
| ASSERT_EQ("ba", test_list_to_string(list)); | |
| list.push_front("c"); | |
| list.push_front("d"); | |
| ASSERT_EQ("dcba", test_list_to_string(list)); | |
| ASSERT_TRUE(alloc_called); | |
| ASSERT_TRUE(!free_called); | |
| alloc_called = free_called = false; | |
| list.remove_if([] (const char* c) { | |
| return *c == 'c'; | |
| }); | |
| ASSERT_TRUE(!alloc_called); | |
| ASSERT_TRUE(free_called); | |
| ASSERT_EQ("dba", test_list_to_string(list)); | |
| alloc_called = free_called = false; | |
| list.remove_if([] (const char* c) { | |
| return *c == '2'; | |
| }); | |
| ASSERT_TRUE(!alloc_called); | |
| ASSERT_TRUE(!free_called); | |
| ASSERT_EQ("dba", test_list_to_string(list)); | |
| list.clear(); | |
| ASSERT_TRUE(!alloc_called); | |
| ASSERT_TRUE(free_called); | |
| ASSERT_EQ("", test_list_to_string(list)); | |
| } | |
| TEST(linked_list, push_pop) { | |
| test_list_t list; | |
| list.push_front("b"); | |
| list.push_front("a"); | |
| ASSERT_EQ("ab", test_list_to_string(list)); | |
| list.push_back("c"); | |
| ASSERT_EQ("abc", test_list_to_string(list)); | |
| ASSERT_STREQ("a", list.pop_front()); | |
| ASSERT_EQ("bc", test_list_to_string(list)); | |
| ASSERT_STREQ("b", list.pop_front()); | |
| ASSERT_EQ("c", test_list_to_string(list)); | |
| ASSERT_STREQ("c", list.pop_front()); | |
| ASSERT_EQ("", test_list_to_string(list)); | |
| ASSERT_TRUE(list.pop_front() == nullptr); | |
| list.push_back("r"); | |
| ASSERT_EQ("r", test_list_to_string(list)); | |
| ASSERT_STREQ("r", list.pop_front()); | |
| ASSERT_TRUE(list.pop_front() == nullptr); | |
| } | |
| TEST(linked_list, remove_if_then_pop) { | |
| test_list_t list; | |
| list.push_back("a"); | |
| list.push_back("b"); | |
| list.push_back("c"); | |
| list.push_back("d"); | |
| list.remove_if([](const char* c) { | |
| return *c == 'b' || *c == 'c'; | |
| }); | |
| ASSERT_EQ("ad", test_list_to_string(list)); | |
| ASSERT_STREQ("a", list.pop_front()); | |
| ASSERT_EQ("d", test_list_to_string(list)); | |
| ASSERT_STREQ("d", list.pop_front()); | |
| ASSERT_TRUE(list.pop_front() == nullptr); | |
| } | |
| TEST(linked_list, remove_if_last_then_push_back) { | |
| test_list_t list; | |
| list.push_back("a"); | |
| list.push_back("b"); | |
| list.push_back("c"); | |
| list.push_back("d"); | |
| list.remove_if([](const char* c) { | |
| return *c == 'c' || *c == 'd'; | |
| }); | |
| ASSERT_EQ("ab", test_list_to_string(list)); | |
| list.push_back("d"); | |
| ASSERT_EQ("abd", test_list_to_string(list)); | |
| } | |
| TEST(linked_list, copy_to_array) { | |
| test_list_t list; | |
| const size_t max_size = 128; | |
| const char* buf[max_size]; | |
| memset(buf, 0, sizeof(buf)); | |
| ASSERT_EQ(0U, list.copy_to_array(buf, max_size)); | |
| ASSERT_EQ(nullptr, buf[0]); | |
| list.push_back("a"); | |
| list.push_back("b"); | |
| list.push_back("c"); | |
| list.push_back("d"); | |
| memset(buf, 0, sizeof(buf)); | |
| ASSERT_EQ(2U, list.copy_to_array(buf, 2)); | |
| ASSERT_STREQ("a", buf[0]); | |
| ASSERT_STREQ("b", buf[1]); | |
| ASSERT_EQ(nullptr, buf[2]); | |
| ASSERT_EQ(4U, list.copy_to_array(buf, max_size)); | |
| ASSERT_STREQ("a", buf[0]); | |
| ASSERT_STREQ("b", buf[1]); | |
| ASSERT_STREQ("c", buf[2]); | |
| ASSERT_STREQ("d", buf[3]); | |
| ASSERT_EQ(nullptr, buf[4]); | |
| memset(buf, 0, sizeof(buf)); | |
| list.remove_if([](const char* c) { | |
| return *c != 'c'; | |
| }); | |
| ASSERT_EQ(1U, list.copy_to_array(buf, max_size)); | |
| ASSERT_STREQ("c", buf[0]); | |
| ASSERT_EQ(nullptr, buf[1]); | |
| memset(buf, 0, sizeof(buf)); | |
| list.remove_if([](const char* c) { | |
| return *c == 'c'; | |
| }); | |
| ASSERT_EQ(0U, list.copy_to_array(buf, max_size)); | |
| ASSERT_EQ(nullptr, buf[0]); | |
| } | |
| TEST(linked_list, test_visit) { | |
| test_list_t list; | |
| list.push_back("a"); | |
| list.push_back("b"); | |
| list.push_back("c"); | |
| list.push_back("d"); | |
| int visits = 0; | |
| std::stringstream ss; | |
| bool result = list.visit([&](const char* c) { | |
| ++visits; | |
| ss << c; | |
| return true; | |
| }); | |
| ASSERT_TRUE(result); | |
| ASSERT_EQ(4, visits); | |
| ASSERT_EQ("abcd", ss.str()); | |
| visits = 0; | |
| ss.str(std::string()); | |
| result = list.visit([&](const char* c) { | |
| if (++visits == 3) { | |
| return false; | |
| } | |
| ss << c; | |
| return true; | |
| }); | |
| ASSERT_TRUE(!result); | |
| ASSERT_EQ(3, visits); | |
| ASSERT_EQ("ab", ss.str()); | |
| } | |