blob: 95761542d9e3e98452cb837b986eaef38a5b8cef [file] [log] [blame] [edit]
// Copyright 2020 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 "fxjs/gc/gced_tree_node_mixin.h"
#include <map>
#include "core/fxcrt/observed_ptr.h"
#include "fxjs/gc/heap.h"
#include "testing/fxgc_unittest.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "testing/v8_test_environment.h"
#include "third_party/base/stl_util.h"
#include "v8/include/cppgc/allocation.h"
#include "v8/include/cppgc/persistent.h"
namespace {
class ObservableGCedTreeNodeMixinForTest
: public cppgc::GarbageCollected<ObservableGCedTreeNodeMixinForTest>,
public GCedTreeNodeMixin<ObservableGCedTreeNodeMixinForTest>,
public Observable {
public:
CONSTRUCT_VIA_MAKE_GARBAGE_COLLECTED;
// GCedTreeNodeMixin:
void Trace(cppgc::Visitor* visitor) const override {
GCedTreeNodeMixin<ObservableGCedTreeNodeMixinForTest>::Trace(visitor);
}
private:
ObservableGCedTreeNodeMixinForTest() = default;
};
} // namespace
class GCedTreeNodeMixinUnitTest : public FXGCUnitTest {
public:
GCedTreeNodeMixinUnitTest() = default;
~GCedTreeNodeMixinUnitTest() override = default;
// FXGCUnitTest:
void TearDown() override {
root_ = nullptr; // Can't (yet) outlive |FXGCUnitTest::heap_|.
FXGCUnitTest::TearDown();
}
ObservableGCedTreeNodeMixinForTest* root() const { return root_; }
void CreateRoot() { root_ = CreateNode(); }
ObservableGCedTreeNodeMixinForTest* CreateNode() {
return cppgc::MakeGarbageCollected<ObservableGCedTreeNodeMixinForTest>(
heap()->GetAllocationHandle());
}
void ForceGCAndPump() {
FXGC_ForceGarbageCollection(heap());
V8TestEnvironment::PumpPlatformMessageLoop(isolate());
}
void AddClutterToFront(ObservableGCedTreeNodeMixinForTest* parent) {
for (int i = 0; i < 4; ++i) {
parent->AppendFirstChild(
cppgc::MakeGarbageCollected<ObservableGCedTreeNodeMixinForTest>(
heap()->GetAllocationHandle()));
}
}
void AddClutterToBack(ObservableGCedTreeNodeMixinForTest* parent) {
for (int i = 0; i < 4; ++i) {
parent->AppendLastChild(
cppgc::MakeGarbageCollected<ObservableGCedTreeNodeMixinForTest>(
heap()->GetAllocationHandle()));
}
}
private:
cppgc::Persistent<ObservableGCedTreeNodeMixinForTest> root_;
};
TEST_F(GCedTreeNodeMixinUnitTest, OneRefence) {
CreateRoot();
ObservedPtr<ObservableGCedTreeNodeMixinForTest> watcher(root());
ForceGCAndPump();
EXPECT_TRUE(watcher);
}
TEST_F(GCedTreeNodeMixinUnitTest, NoReferences) {
ObservedPtr<ObservableGCedTreeNodeMixinForTest> watcher(CreateNode());
ForceGCAndPump();
EXPECT_FALSE(watcher);
}
TEST_F(GCedTreeNodeMixinUnitTest, FirstHasParent) {
CreateRoot();
ObservedPtr<ObservableGCedTreeNodeMixinForTest> watcher(CreateNode());
root()->AppendFirstChild(watcher.Get());
ForceGCAndPump();
ASSERT_TRUE(root());
EXPECT_TRUE(watcher);
root()->RemoveChild(watcher.Get());
ForceGCAndPump();
ASSERT_TRUE(root());
EXPECT_FALSE(watcher);
// Now add some clutter.
watcher.Reset(CreateNode());
root()->AppendFirstChild(watcher.Get());
AddClutterToFront(root());
AddClutterToBack(root());
ForceGCAndPump();
ASSERT_TRUE(root());
EXPECT_TRUE(watcher);
root()->RemoveChild(watcher.Get());
ForceGCAndPump();
EXPECT_TRUE(root());
EXPECT_FALSE(watcher);
}
TEST_F(GCedTreeNodeMixinUnitTest, RemoveSelf) {
CreateRoot();
ObservedPtr<ObservableGCedTreeNodeMixinForTest> watcher(CreateNode());
root()->AppendFirstChild(watcher.Get());
ForceGCAndPump();
EXPECT_TRUE(root());
ASSERT_TRUE(watcher);
watcher->RemoveSelfIfParented();
ForceGCAndPump();
EXPECT_TRUE(root());
EXPECT_FALSE(watcher);
}
TEST_F(GCedTreeNodeMixinUnitTest, InsertBeforeAfter) {
CreateRoot();
AddClutterToFront(root());
ObservedPtr<ObservableGCedTreeNodeMixinForTest> watcher(CreateNode());
root()->AppendFirstChild(watcher.Get());
root()->InsertBefore(root()->GetFirstChild(), root()->GetLastChild());
root()->InsertAfter(root()->GetLastChild(), root()->GetFirstChild());
ForceGCAndPump();
ASSERT_TRUE(root());
EXPECT_TRUE(watcher);
root()->RemoveChild(watcher.Get());
ForceGCAndPump();
EXPECT_TRUE(root());
EXPECT_FALSE(watcher);
}
TEST_F(GCedTreeNodeMixinUnitTest, AsMapKey) {
std::map<cppgc::Persistent<ObservableGCedTreeNodeMixinForTest>, int> score;
ObservableGCedTreeNodeMixinForTest* node = CreateNode();
score[node] = 100;
EXPECT_EQ(100, score[node]);
}