1 // Copyright 2020 The PDFium Authors
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 "fxjs/gc/gced_tree_node.h"
6
7 #include <map>
8
9 #include "core/fxcrt/observed_ptr.h"
10 #include "fxjs/gc/heap.h"
11 #include "testing/fxgc_unittest.h"
12 #include "testing/gtest/include/gtest/gtest.h"
13 #include "testing/v8_test_environment.h"
14 #include "v8/include/cppgc/allocation.h"
15 #include "v8/include/cppgc/persistent.h"
16
17 namespace {
18
19 class ObservableGCedTreeNodeForTest
20 : public GCedTreeNode<ObservableGCedTreeNodeForTest>,
21 public Observable {
22 public:
23 CONSTRUCT_VIA_MAKE_GARBAGE_COLLECTED;
24
25 private:
26 ObservableGCedTreeNodeForTest() = default;
27 };
28
29 } // namespace
30
31 class GCedTreeNodeUnitTest : public FXGCUnitTest {
32 public:
33 GCedTreeNodeUnitTest() = default;
34 ~GCedTreeNodeUnitTest() override = default;
35
36 // FXGCUnitTest:
TearDown()37 void TearDown() override {
38 root_ = nullptr; // Can't (yet) outlive |FXGCUnitTest::heap_|.
39 FXGCUnitTest::TearDown();
40 }
41
root() const42 ObservableGCedTreeNodeForTest* root() const { return root_; }
CreateRoot()43 void CreateRoot() { root_ = CreateNode(); }
44
CreateNode()45 ObservableGCedTreeNodeForTest* CreateNode() {
46 return cppgc::MakeGarbageCollected<ObservableGCedTreeNodeForTest>(
47 heap()->GetAllocationHandle());
48 }
49
AddClutterToFront(ObservableGCedTreeNodeForTest * parent)50 void AddClutterToFront(ObservableGCedTreeNodeForTest* parent) {
51 for (int i = 0; i < 4; ++i) {
52 parent->AppendFirstChild(
53 cppgc::MakeGarbageCollected<ObservableGCedTreeNodeForTest>(
54 heap()->GetAllocationHandle()));
55 }
56 }
57
AddClutterToBack(ObservableGCedTreeNodeForTest * parent)58 void AddClutterToBack(ObservableGCedTreeNodeForTest* parent) {
59 for (int i = 0; i < 4; ++i) {
60 parent->AppendLastChild(
61 cppgc::MakeGarbageCollected<ObservableGCedTreeNodeForTest>(
62 heap()->GetAllocationHandle()));
63 }
64 }
65
66 private:
67 cppgc::Persistent<ObservableGCedTreeNodeForTest> root_;
68 };
69
TEST_F(GCedTreeNodeUnitTest,OneRefence)70 TEST_F(GCedTreeNodeUnitTest, OneRefence) {
71 CreateRoot();
72 ObservedPtr<ObservableGCedTreeNodeForTest> watcher(root());
73 ForceGCAndPump();
74 EXPECT_TRUE(watcher);
75 }
76
TEST_F(GCedTreeNodeUnitTest,NoReferences)77 TEST_F(GCedTreeNodeUnitTest, NoReferences) {
78 ObservedPtr<ObservableGCedTreeNodeForTest> watcher(CreateNode());
79 ForceGCAndPump();
80 EXPECT_FALSE(watcher);
81 }
82
TEST_F(GCedTreeNodeUnitTest,FirstHasParent)83 TEST_F(GCedTreeNodeUnitTest, FirstHasParent) {
84 CreateRoot();
85 ObservedPtr<ObservableGCedTreeNodeForTest> watcher(CreateNode());
86 root()->AppendFirstChild(watcher.Get());
87 ForceGCAndPump();
88 ASSERT_TRUE(root());
89 EXPECT_TRUE(watcher);
90 root()->RemoveChild(watcher.Get());
91 ForceGCAndPump();
92 ASSERT_TRUE(root());
93 EXPECT_FALSE(watcher);
94
95 // Now add some clutter.
96 watcher.Reset(CreateNode());
97 root()->AppendFirstChild(watcher.Get());
98 AddClutterToFront(root());
99 AddClutterToBack(root());
100 ForceGCAndPump();
101 ASSERT_TRUE(root());
102 EXPECT_TRUE(watcher);
103 root()->RemoveChild(watcher.Get());
104 ForceGCAndPump();
105 EXPECT_TRUE(root());
106 EXPECT_FALSE(watcher);
107 }
108
TEST_F(GCedTreeNodeUnitTest,RemoveSelf)109 TEST_F(GCedTreeNodeUnitTest, RemoveSelf) {
110 CreateRoot();
111 ObservedPtr<ObservableGCedTreeNodeForTest> watcher(CreateNode());
112 root()->AppendFirstChild(watcher.Get());
113 ForceGCAndPump();
114 EXPECT_TRUE(root());
115 ASSERT_TRUE(watcher);
116 watcher->RemoveSelfIfParented();
117 ForceGCAndPump();
118 EXPECT_TRUE(root());
119 EXPECT_FALSE(watcher);
120 }
121
TEST_F(GCedTreeNodeUnitTest,InsertBeforeAfter)122 TEST_F(GCedTreeNodeUnitTest, InsertBeforeAfter) {
123 CreateRoot();
124 AddClutterToFront(root());
125 ObservedPtr<ObservableGCedTreeNodeForTest> watcher(CreateNode());
126 root()->AppendFirstChild(watcher.Get());
127 root()->InsertBefore(root()->GetFirstChild(), root()->GetLastChild());
128 root()->InsertAfter(root()->GetLastChild(), root()->GetFirstChild());
129 ForceGCAndPump();
130 ASSERT_TRUE(root());
131 EXPECT_TRUE(watcher);
132 root()->RemoveChild(watcher.Get());
133 ForceGCAndPump();
134 EXPECT_TRUE(root());
135 EXPECT_FALSE(watcher);
136 }
137
TEST_F(GCedTreeNodeUnitTest,AsMapKey)138 TEST_F(GCedTreeNodeUnitTest, AsMapKey) {
139 std::map<cppgc::Persistent<ObservableGCedTreeNodeForTest>, int> score;
140 ObservableGCedTreeNodeForTest* node = CreateNode();
141 score[node] = 100;
142 EXPECT_EQ(100, score[node]);
143 }
144