/* * 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 #include #include #include #include "linked_list.h" namespace { bool alloc_called = false; bool free_called = false; class LinkedListTestAllocator { public: typedef LinkedListEntry entry_t; static entry_t* alloc() { alloc_called = true; return reinterpret_cast(::malloc(sizeof(entry_t))); } static void free(entry_t* p) { free_called = true; ::free(p); } private: DISALLOW_IMPLICIT_CONSTRUCTORS(LinkedListTestAllocator); }; typedef LinkedList 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()); }