1 // Copyright 2019 PDFium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "core/fxcrt/retained_tree_node.h"
6
7 #include "core/fxcrt/observed_ptr.h"
8 #include "core/fxcrt/retain_ptr.h"
9 #include "testing/gtest/include/gtest/gtest.h"
10
11 namespace fxcrt {
12 namespace {
13
14 class ObservableRetainedTreeNodeForTest
15 : public RetainedTreeNode<ObservableRetainedTreeNodeForTest>,
16 public Observable {
17 public:
18 template <typename T, typename... Args>
19 friend RetainPtr<T> pdfium::MakeRetain(Args&&... args);
20
21 private:
22 ObservableRetainedTreeNodeForTest() = default;
23 };
24
AddClutterToFront(const RetainPtr<ObservableRetainedTreeNodeForTest> & parent)25 void AddClutterToFront(
26 const RetainPtr<ObservableRetainedTreeNodeForTest>& parent) {
27 for (int i = 0; i < 4; ++i) {
28 parent->AppendFirstChild(
29 pdfium::MakeRetain<ObservableRetainedTreeNodeForTest>());
30 }
31 }
32
AddClutterToBack(const RetainPtr<ObservableRetainedTreeNodeForTest> & parent)33 void AddClutterToBack(
34 const RetainPtr<ObservableRetainedTreeNodeForTest>& parent) {
35 for (int i = 0; i < 4; ++i) {
36 parent->AppendLastChild(
37 pdfium::MakeRetain<ObservableRetainedTreeNodeForTest>());
38 }
39 }
40
41 } // namespace
42
TEST(RetainedTreeNode,NoParent)43 TEST(RetainedTreeNode, NoParent) {
44 ObservedPtr<ObservableRetainedTreeNodeForTest> watcher;
45 {
46 RetainPtr<ObservableRetainedTreeNodeForTest> ptr =
47 pdfium::MakeRetain<ObservableRetainedTreeNodeForTest>();
48 EXPECT_FALSE(ptr->HasChild(ptr.Get()));
49 watcher = ObservedPtr<ObservableRetainedTreeNodeForTest>(ptr.Get());
50 EXPECT_TRUE(watcher.Get());
51 }
52 EXPECT_FALSE(watcher.Get());
53 }
54
TEST(RetainedTreeNode,FirstHasParent)55 TEST(RetainedTreeNode, FirstHasParent) {
56 ObservedPtr<ObservableRetainedTreeNodeForTest> watcher;
57 RetainPtr<ObservableRetainedTreeNodeForTest> parent =
58 pdfium::MakeRetain<ObservableRetainedTreeNodeForTest>();
59 {
60 RetainPtr<ObservableRetainedTreeNodeForTest> ptr =
61 pdfium::MakeRetain<ObservableRetainedTreeNodeForTest>();
62 watcher = ObservedPtr<ObservableRetainedTreeNodeForTest>(ptr.Get());
63 parent->AppendFirstChild(ptr);
64 EXPECT_FALSE(parent->HasChild(parent.Get()));
65 EXPECT_TRUE(parent->HasChild(ptr.Get()));
66 EXPECT_TRUE(watcher.Get());
67 }
68 EXPECT_TRUE(watcher.Get());
69 parent->RemoveChild(pdfium::WrapRetain(watcher.Get()));
70 EXPECT_FALSE(watcher.Get());
71 // Now add some clutter.
72 {
73 RetainPtr<ObservableRetainedTreeNodeForTest> ptr =
74 pdfium::MakeRetain<ObservableRetainedTreeNodeForTest>();
75 watcher = ObservedPtr<ObservableRetainedTreeNodeForTest>(ptr.Get());
76 parent->AppendFirstChild(ptr);
77 AddClutterToFront(parent);
78 AddClutterToBack(parent);
79 EXPECT_TRUE(watcher.Get());
80 }
81 EXPECT_TRUE(watcher.Get());
82 parent->RemoveChild(pdfium::WrapRetain(watcher.Get()));
83 EXPECT_FALSE(watcher.Get());
84 }
85
TEST(RetainedTreeNode,LastHasParent)86 TEST(RetainedTreeNode, LastHasParent) {
87 ObservedPtr<ObservableRetainedTreeNodeForTest> watcher;
88 RetainPtr<ObservableRetainedTreeNodeForTest> parent =
89 pdfium::MakeRetain<ObservableRetainedTreeNodeForTest>();
90 {
91 RetainPtr<ObservableRetainedTreeNodeForTest> ptr =
92 pdfium::MakeRetain<ObservableRetainedTreeNodeForTest>();
93 watcher = ObservedPtr<ObservableRetainedTreeNodeForTest>(ptr.Get());
94 parent->AppendLastChild(ptr);
95 EXPECT_FALSE(parent->HasChild(parent.Get()));
96 EXPECT_TRUE(parent->HasChild(ptr.Get()));
97 EXPECT_TRUE(watcher.Get());
98 }
99 {
100 // Now add some clutter.
101 RetainPtr<ObservableRetainedTreeNodeForTest> ptr =
102 pdfium::MakeRetain<ObservableRetainedTreeNodeForTest>();
103 watcher = ObservedPtr<ObservableRetainedTreeNodeForTest>(ptr.Get());
104 parent->AppendLastChild(ptr);
105 AddClutterToFront(parent);
106 AddClutterToBack(parent);
107 EXPECT_TRUE(watcher.Get());
108 }
109 EXPECT_TRUE(watcher.Get());
110 parent->RemoveChild(pdfium::WrapRetain(watcher.Get()));
111 EXPECT_FALSE(watcher.Get());
112 }
113
TEST(RetainedTreeNode,GrandChildCleanedUp)114 TEST(RetainedTreeNode, GrandChildCleanedUp) {
115 ObservedPtr<ObservableRetainedTreeNodeForTest> watcher;
116 RetainPtr<ObservableRetainedTreeNodeForTest> grandparent =
117 pdfium::MakeRetain<ObservableRetainedTreeNodeForTest>();
118 {
119 RetainPtr<ObservableRetainedTreeNodeForTest> parent =
120 pdfium::MakeRetain<ObservableRetainedTreeNodeForTest>();
121 grandparent->AppendFirstChild(parent);
122 {
123 RetainPtr<ObservableRetainedTreeNodeForTest> ptr =
124 pdfium::MakeRetain<ObservableRetainedTreeNodeForTest>();
125 watcher = ObservedPtr<ObservableRetainedTreeNodeForTest>(ptr.Get());
126 parent->AppendFirstChild(ptr);
127 EXPECT_TRUE(watcher.Get());
128 }
129 grandparent->RemoveChild(parent);
130 EXPECT_TRUE(watcher.Get());
131 }
132 EXPECT_FALSE(watcher.Get());
133 }
134
TEST(RetainedTreeNode,RemoveSelf)135 TEST(RetainedTreeNode, RemoveSelf) {
136 ObservedPtr<ObservableRetainedTreeNodeForTest> watcher;
137 auto parent = pdfium::MakeRetain<ObservableRetainedTreeNodeForTest>();
138 {
139 auto child = pdfium::MakeRetain<ObservableRetainedTreeNodeForTest>();
140 watcher = ObservedPtr<ObservableRetainedTreeNodeForTest>(child.Get());
141 parent->AppendFirstChild(child);
142 }
143 EXPECT_TRUE(watcher.Get());
144 watcher->RemoveSelfIfParented();
145 EXPECT_FALSE(watcher.Get());
146 }
147
TEST(RetainedTreeNode,InsertBeforeAfter)148 TEST(RetainedTreeNode, InsertBeforeAfter) {
149 ObservedPtr<ObservableRetainedTreeNodeForTest> watcher;
150 RetainPtr<ObservableRetainedTreeNodeForTest> parent =
151 pdfium::MakeRetain<ObservableRetainedTreeNodeForTest>();
152
153 AddClutterToFront(parent);
154 {
155 RetainPtr<ObservableRetainedTreeNodeForTest> ptr =
156 pdfium::MakeRetain<ObservableRetainedTreeNodeForTest>();
157 watcher = ObservedPtr<ObservableRetainedTreeNodeForTest>(ptr.Get());
158 parent->AppendFirstChild(ptr);
159 parent->InsertBefore(pdfium::WrapRetain(parent->GetFirstChild()),
160 parent->GetLastChild());
161 parent->InsertAfter(pdfium::WrapRetain(parent->GetLastChild()),
162 parent->GetFirstChild());
163 EXPECT_TRUE(watcher.Get());
164 }
165 parent->RemoveChild(pdfium::WrapRetain(watcher.Get()));
166 EXPECT_FALSE(watcher.Get());
167 }
168
TEST(RetainedTreeNode,Traversal)169 TEST(RetainedTreeNode, Traversal) {
170 RetainPtr<ObservableRetainedTreeNodeForTest> parent =
171 pdfium::MakeRetain<ObservableRetainedTreeNodeForTest>();
172
173 AddClutterToFront(parent);
174 int count = 0;
175 for (ObservableRetainedTreeNodeForTest* pNode = parent->GetFirstChild();
176 pNode; pNode = pNode->GetNextSibling()) {
177 ++count;
178 }
179 EXPECT_EQ(4, count);
180 count = 0;
181 for (ObservableRetainedTreeNodeForTest* pNode = parent->GetLastChild(); pNode;
182 pNode = pNode->GetPrevSibling()) {
183 ++count;
184 }
185 EXPECT_EQ(4, count);
186 }
187
188 } // namespace fxcrt
189