TestLinkedList.cpp (3592B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #include "gtest/gtest.h" 8 9 #include "mozilla/LinkedList.h" 10 #include "mozilla/RefPtr.h" 11 #include "mozilla/ReverseIterator.h" 12 13 using mozilla::AutoCleanLinkedList; 14 using mozilla::LinkedList; 15 using mozilla::LinkedListElement; 16 17 class PtrClass : public LinkedListElement<PtrClass> { 18 public: 19 bool* mResult; 20 21 explicit PtrClass(bool* result) : mResult(result) { EXPECT_TRUE(!*mResult); } 22 23 virtual ~PtrClass() { *mResult = true; } 24 }; 25 26 class InheritedPtrClass : public PtrClass { 27 public: 28 bool* mInheritedResult; 29 30 InheritedPtrClass(bool* result, bool* inheritedResult) 31 : PtrClass(result), mInheritedResult(inheritedResult) { 32 EXPECT_TRUE(!*mInheritedResult); 33 } 34 35 virtual ~InheritedPtrClass() { *mInheritedResult = true; } 36 }; 37 38 TEST(LinkedList, AutoCleanLinkedList) 39 { 40 bool rv1 = false; 41 bool rv2 = false; 42 bool rv3 = false; 43 { 44 AutoCleanLinkedList<PtrClass> list; 45 list.insertBack(new PtrClass(&rv1)); 46 list.insertBack(new InheritedPtrClass(&rv2, &rv3)); 47 } 48 49 EXPECT_TRUE(rv1); 50 EXPECT_TRUE(rv2); 51 EXPECT_TRUE(rv3); 52 } 53 54 class CountedClass final : public LinkedListElement<RefPtr<CountedClass>> { 55 public: 56 int mCount; 57 void AddRef() { mCount++; } 58 void Release() { mCount--; } 59 60 CountedClass() : mCount(0) {} 61 ~CountedClass() { EXPECT_TRUE(mCount == 0); } 62 }; 63 64 TEST(LinkedList, AutoCleanLinkedListRefPtr) 65 { 66 RefPtr<CountedClass> elt1 = new CountedClass; 67 CountedClass* elt2 = new CountedClass; 68 { 69 AutoCleanLinkedList<RefPtr<CountedClass>> list; 70 list.insertBack(elt1); 71 list.insertBack(elt2); 72 73 EXPECT_TRUE(elt1->mCount == 2); 74 EXPECT_TRUE(elt2->mCount == 1); 75 } 76 77 EXPECT_TRUE(elt1->mCount == 1); 78 EXPECT_TRUE(elt2->mCount == 0); 79 } 80 81 struct SomeClass : public LinkedListElement<SomeClass> { 82 unsigned int mValue; 83 explicit SomeClass(int aValue = 0) : mValue(aValue) {} 84 SomeClass(SomeClass&&) = default; 85 SomeClass& operator=(SomeClass&&) = default; 86 void incr() { ++mValue; } 87 }; 88 89 TEST(LinkedList, TestReverseIterators) 90 { 91 LinkedList<SomeClass> list; 92 SomeClass one(1), two(2), three(3); 93 list.insertBack(&one); 94 list.insertBack(&two); 95 list.insertBack(&three); 96 97 // Traverse in reverse using rbegin/rend. 98 unsigned int expect1[]{3, 2, 1}; 99 size_t idx = 0; 100 for (auto it = list.rbegin(); it != list.rend(); ++it, ++idx) { 101 EXPECT_EQ((*it)->mValue, expect1[idx]); 102 } 103 EXPECT_EQ(idx, 3u); 104 105 // Const reverse iteration. 106 const LinkedList<SomeClass>& clist = list; 107 unsigned int expect2[]{3, 2, 1}; 108 idx = 0; 109 for (auto it = clist.crbegin(); it != clist.crend(); ++it, ++idx) { 110 EXPECT_EQ((*it)->mValue, expect2[idx]); 111 } 112 EXPECT_EQ(idx, 3u); 113 114 // Use Reversed helper. 115 unsigned int expect3[]{3, 2, 1}; 116 idx = 0; 117 for (SomeClass* entry : mozilla::Reversed(list)) { 118 EXPECT_EQ(entry->mValue, expect3[idx++]); 119 } 120 EXPECT_EQ(idx, 3u); 121 122 // Mutation safety: remove after advancing. 123 auto rit = list.rbegin(); 124 EXPECT_EQ((*rit)->mValue, 3u); 125 SomeClass* toRemove = *rit; 126 ++rit; // advance before removal to avoid invalidating 'rit' 127 toRemove->remove(); // remove 3 128 EXPECT_EQ((*rit)->mValue, 2u); 129 toRemove = *rit; 130 ++rit; // now at 1 131 toRemove->remove(); // remove 2 132 EXPECT_EQ(list.length(), 1u); 133 EXPECT_EQ(list.getFirst()->mValue, 1u); 134 }