| // Copyright 2019 PDFium Authors. All rights reserved. | |
| // Use of this source code is governed by a BSD-style license that can be | |
| // found in the LICENSE file. | |
| #include "core/fxcrt/retained_tree_node.h" | |
| #include "core/fxcrt/observed_ptr.h" | |
| #include "core/fxcrt/retain_ptr.h" | |
| #include "testing/gtest/include/gtest/gtest.h" | |
| namespace fxcrt { | |
| namespace { | |
| class ObservableRetainedTreeNodeForTest | |
| : public RetainedTreeNode<ObservableRetainedTreeNodeForTest>, | |
| public Observable { | |
| public: | |
| template <typename T, typename... Args> | |
| friend RetainPtr<T> pdfium::MakeRetain(Args&&... args); | |
| private: | |
| ObservableRetainedTreeNodeForTest() = default; | |
| }; | |
| void AddClutterToFront( | |
| const RetainPtr<ObservableRetainedTreeNodeForTest>& parent) { | |
| for (int i = 0; i < 4; ++i) { | |
| parent->AppendFirstChild( | |
| pdfium::MakeRetain<ObservableRetainedTreeNodeForTest>()); | |
| } | |
| } | |
| void AddClutterToBack( | |
| const RetainPtr<ObservableRetainedTreeNodeForTest>& parent) { | |
| for (int i = 0; i < 4; ++i) { | |
| parent->AppendLastChild( | |
| pdfium::MakeRetain<ObservableRetainedTreeNodeForTest>()); | |
| } | |
| } | |
| } // namespace | |
| TEST(RetainedTreeNode, NoParent) { | |
| ObservedPtr<ObservableRetainedTreeNodeForTest> watcher; | |
| { | |
| RetainPtr<ObservableRetainedTreeNodeForTest> ptr = | |
| pdfium::MakeRetain<ObservableRetainedTreeNodeForTest>(); | |
| EXPECT_FALSE(ptr->HasChild(ptr.Get())); | |
| watcher = ObservedPtr<ObservableRetainedTreeNodeForTest>(ptr.Get()); | |
| EXPECT_TRUE(watcher.Get()); | |
| } | |
| EXPECT_FALSE(watcher.Get()); | |
| } | |
| TEST(RetainedTreeNode, FirstHasParent) { | |
| ObservedPtr<ObservableRetainedTreeNodeForTest> watcher; | |
| RetainPtr<ObservableRetainedTreeNodeForTest> parent = | |
| pdfium::MakeRetain<ObservableRetainedTreeNodeForTest>(); | |
| { | |
| RetainPtr<ObservableRetainedTreeNodeForTest> ptr = | |
| pdfium::MakeRetain<ObservableRetainedTreeNodeForTest>(); | |
| watcher = ObservedPtr<ObservableRetainedTreeNodeForTest>(ptr.Get()); | |
| parent->AppendFirstChild(ptr); | |
| EXPECT_FALSE(parent->HasChild(parent.Get())); | |
| EXPECT_TRUE(parent->HasChild(ptr.Get())); | |
| EXPECT_TRUE(watcher.Get()); | |
| } | |
| EXPECT_TRUE(watcher.Get()); | |
| parent->RemoveChild(pdfium::WrapRetain(watcher.Get())); | |
| EXPECT_FALSE(watcher.Get()); | |
| // Now add some clutter. | |
| { | |
| RetainPtr<ObservableRetainedTreeNodeForTest> ptr = | |
| pdfium::MakeRetain<ObservableRetainedTreeNodeForTest>(); | |
| watcher = ObservedPtr<ObservableRetainedTreeNodeForTest>(ptr.Get()); | |
| parent->AppendFirstChild(ptr); | |
| AddClutterToFront(parent); | |
| AddClutterToBack(parent); | |
| EXPECT_TRUE(watcher.Get()); | |
| } | |
| EXPECT_TRUE(watcher.Get()); | |
| parent->RemoveChild(pdfium::WrapRetain(watcher.Get())); | |
| EXPECT_FALSE(watcher.Get()); | |
| } | |
| TEST(RetainedTreeNode, LastHasParent) { | |
| ObservedPtr<ObservableRetainedTreeNodeForTest> watcher; | |
| RetainPtr<ObservableRetainedTreeNodeForTest> parent = | |
| pdfium::MakeRetain<ObservableRetainedTreeNodeForTest>(); | |
| { | |
| RetainPtr<ObservableRetainedTreeNodeForTest> ptr = | |
| pdfium::MakeRetain<ObservableRetainedTreeNodeForTest>(); | |
| watcher = ObservedPtr<ObservableRetainedTreeNodeForTest>(ptr.Get()); | |
| parent->AppendLastChild(ptr); | |
| EXPECT_FALSE(parent->HasChild(parent.Get())); | |
| EXPECT_TRUE(parent->HasChild(ptr.Get())); | |
| EXPECT_TRUE(watcher.Get()); | |
| } | |
| { | |
| // Now add some clutter. | |
| RetainPtr<ObservableRetainedTreeNodeForTest> ptr = | |
| pdfium::MakeRetain<ObservableRetainedTreeNodeForTest>(); | |
| watcher = ObservedPtr<ObservableRetainedTreeNodeForTest>(ptr.Get()); | |
| parent->AppendLastChild(ptr); | |
| AddClutterToFront(parent); | |
| AddClutterToBack(parent); | |
| EXPECT_TRUE(watcher.Get()); | |
| } | |
| EXPECT_TRUE(watcher.Get()); | |
| parent->RemoveChild(pdfium::WrapRetain(watcher.Get())); | |
| EXPECT_FALSE(watcher.Get()); | |
| } | |
| TEST(RetainedTreeNode, GrandChildCleanedUp) { | |
| ObservedPtr<ObservableRetainedTreeNodeForTest> watcher; | |
| RetainPtr<ObservableRetainedTreeNodeForTest> grandparent = | |
| pdfium::MakeRetain<ObservableRetainedTreeNodeForTest>(); | |
| { | |
| RetainPtr<ObservableRetainedTreeNodeForTest> parent = | |
| pdfium::MakeRetain<ObservableRetainedTreeNodeForTest>(); | |
| grandparent->AppendFirstChild(parent); | |
| { | |
| RetainPtr<ObservableRetainedTreeNodeForTest> ptr = | |
| pdfium::MakeRetain<ObservableRetainedTreeNodeForTest>(); | |
| watcher = ObservedPtr<ObservableRetainedTreeNodeForTest>(ptr.Get()); | |
| parent->AppendFirstChild(ptr); | |
| EXPECT_TRUE(watcher.Get()); | |
| } | |
| grandparent->RemoveChild(parent); | |
| EXPECT_TRUE(watcher.Get()); | |
| } | |
| EXPECT_FALSE(watcher.Get()); | |
| } | |
| TEST(RetainedTreeNode, RemoveSelf) { | |
| ObservedPtr<ObservableRetainedTreeNodeForTest> watcher; | |
| auto parent = pdfium::MakeRetain<ObservableRetainedTreeNodeForTest>(); | |
| { | |
| auto child = pdfium::MakeRetain<ObservableRetainedTreeNodeForTest>(); | |
| watcher = ObservedPtr<ObservableRetainedTreeNodeForTest>(child.Get()); | |
| parent->AppendFirstChild(child); | |
| } | |
| EXPECT_TRUE(watcher.Get()); | |
| watcher->RemoveSelfIfParented(); | |
| EXPECT_FALSE(watcher.Get()); | |
| } | |
| TEST(RetainedTreeNode, InsertBeforeAfter) { | |
| ObservedPtr<ObservableRetainedTreeNodeForTest> watcher; | |
| RetainPtr<ObservableRetainedTreeNodeForTest> parent = | |
| pdfium::MakeRetain<ObservableRetainedTreeNodeForTest>(); | |
| AddClutterToFront(parent); | |
| { | |
| RetainPtr<ObservableRetainedTreeNodeForTest> ptr = | |
| pdfium::MakeRetain<ObservableRetainedTreeNodeForTest>(); | |
| watcher = ObservedPtr<ObservableRetainedTreeNodeForTest>(ptr.Get()); | |
| parent->AppendFirstChild(ptr); | |
| parent->InsertBefore(pdfium::WrapRetain(parent->GetFirstChild()), | |
| parent->GetLastChild()); | |
| parent->InsertAfter(pdfium::WrapRetain(parent->GetLastChild()), | |
| parent->GetFirstChild()); | |
| EXPECT_TRUE(watcher.Get()); | |
| } | |
| parent->RemoveChild(pdfium::WrapRetain(watcher.Get())); | |
| EXPECT_FALSE(watcher.Get()); | |
| } | |
| TEST(RetainedTreeNode, Traversal) { | |
| RetainPtr<ObservableRetainedTreeNodeForTest> parent = | |
| pdfium::MakeRetain<ObservableRetainedTreeNodeForTest>(); | |
| AddClutterToFront(parent); | |
| int count = 0; | |
| for (ObservableRetainedTreeNodeForTest* pNode = parent->GetFirstChild(); | |
| pNode; pNode = pNode->GetNextSibling()) { | |
| ++count; | |
| } | |
| EXPECT_EQ(4, count); | |
| count = 0; | |
| for (ObservableRetainedTreeNodeForTest* pNode = parent->GetLastChild(); pNode; | |
| pNode = pNode->GetPrevSibling()) { | |
| ++count; | |
| } | |
| EXPECT_EQ(4, count); | |
| } | |
| } // namespace fxcrt |