1 #include "gtest/gtest.h"
2 #include "node.h"
3 #include "base_object-inl.h"
4 #include "node_test_fixture.h"
5
6 using node::BaseObject;
7 using node::BaseObjectPtr;
8 using node::BaseObjectWeakPtr;
9 using node::Environment;
10 using node::MakeBaseObject;
11 using node::MakeDetachedBaseObject;
12 using v8::HandleScope;
13 using v8::Isolate;
14 using v8::Local;
15 using v8::Object;
16
17 class BaseObjectPtrTest : public EnvironmentTestFixture {};
18
19 class DummyBaseObject : public BaseObject {
20 public:
DummyBaseObject(Environment * env,Local<Object> obj)21 DummyBaseObject(Environment* env, Local<Object> obj) : BaseObject(env, obj) {}
22
MakeJSObject(Environment * env)23 static Local<Object> MakeJSObject(Environment* env) {
24 return BaseObject::MakeLazilyInitializedJSTemplate(env)
25 ->GetFunction(env->context()).ToLocalChecked()
26 ->NewInstance(env->context()).ToLocalChecked();
27 }
28
NewDetached(Environment * env)29 static BaseObjectPtr<DummyBaseObject> NewDetached(Environment* env) {
30 Local<Object> obj = MakeJSObject(env);
31 return MakeDetachedBaseObject<DummyBaseObject>(env, obj);
32 }
33
New(Environment * env)34 static BaseObjectPtr<DummyBaseObject> New(Environment* env) {
35 Local<Object> obj = MakeJSObject(env);
36 return MakeBaseObject<DummyBaseObject>(env, obj);
37 }
38
39 SET_NO_MEMORY_INFO()
40 SET_MEMORY_INFO_NAME(DummyBaseObject)
41 SET_SELF_SIZE(DummyBaseObject)
42 };
43
TEST_F(BaseObjectPtrTest,ScopedDetached)44 TEST_F(BaseObjectPtrTest, ScopedDetached) {
45 const HandleScope handle_scope(isolate_);
46 const Argv argv;
47 Env env_{handle_scope, argv};
48 Environment* env = *env_;
49
50 EXPECT_EQ(env->base_object_count(), 0);
51 {
52 BaseObjectPtr<DummyBaseObject> ptr = DummyBaseObject::NewDetached(env);
53 EXPECT_EQ(env->base_object_count(), 1);
54 }
55 EXPECT_EQ(env->base_object_count(), 0);
56 }
57
TEST_F(BaseObjectPtrTest,ScopedDetachedWithWeak)58 TEST_F(BaseObjectPtrTest, ScopedDetachedWithWeak) {
59 const HandleScope handle_scope(isolate_);
60 const Argv argv;
61 Env env_{handle_scope, argv};
62 Environment* env = *env_;
63
64 BaseObjectWeakPtr<DummyBaseObject> weak_ptr;
65
66 EXPECT_EQ(env->base_object_count(), 0);
67 {
68 BaseObjectPtr<DummyBaseObject> ptr = DummyBaseObject::NewDetached(env);
69 weak_ptr = ptr;
70 EXPECT_EQ(env->base_object_count(), 1);
71 }
72 EXPECT_EQ(weak_ptr.get(), nullptr);
73 EXPECT_EQ(env->base_object_count(), 0);
74 }
75
TEST_F(BaseObjectPtrTest,Undetached)76 TEST_F(BaseObjectPtrTest, Undetached) {
77 const HandleScope handle_scope(isolate_);
78 const Argv argv;
79 Env env_{handle_scope, argv};
80 Environment* env = *env_;
81
82 node::AddEnvironmentCleanupHook(isolate_, [](void* arg) {
83 EXPECT_EQ(static_cast<Environment*>(arg)->base_object_count(), 0);
84 }, env);
85
86 BaseObjectPtr<DummyBaseObject> ptr = DummyBaseObject::New(env);
87 EXPECT_EQ(env->base_object_count(), 1);
88 }
89
TEST_F(BaseObjectPtrTest,GCWeak)90 TEST_F(BaseObjectPtrTest, GCWeak) {
91 const HandleScope handle_scope(isolate_);
92 const Argv argv;
93 Env env_{handle_scope, argv};
94 Environment* env = *env_;
95
96 BaseObjectWeakPtr<DummyBaseObject> weak_ptr;
97
98 {
99 const HandleScope handle_scope(isolate_);
100 BaseObjectPtr<DummyBaseObject> ptr = DummyBaseObject::New(env);
101 weak_ptr = ptr;
102 ptr->MakeWeak();
103
104 EXPECT_EQ(env->base_object_count(), 1);
105 EXPECT_EQ(weak_ptr.get(), ptr.get());
106 EXPECT_EQ(weak_ptr->persistent().IsWeak(), false);
107
108 ptr.reset();
109 }
110
111 EXPECT_EQ(env->base_object_count(), 1);
112 EXPECT_NE(weak_ptr.get(), nullptr);
113 EXPECT_EQ(weak_ptr->persistent().IsWeak(), true);
114
115 v8::V8::SetFlagsFromString("--expose-gc");
116 isolate_->RequestGarbageCollectionForTesting(Isolate::kFullGarbageCollection);
117
118 EXPECT_EQ(env->base_object_count(), 0);
119 EXPECT_EQ(weak_ptr.get(), nullptr);
120 }
121
TEST_F(BaseObjectPtrTest,Moveable)122 TEST_F(BaseObjectPtrTest, Moveable) {
123 const HandleScope handle_scope(isolate_);
124 const Argv argv;
125 Env env_{handle_scope, argv};
126 Environment* env = *env_;
127
128 BaseObjectPtr<DummyBaseObject> ptr = DummyBaseObject::NewDetached(env);
129 EXPECT_EQ(env->base_object_count(), 1);
130 BaseObjectWeakPtr<DummyBaseObject> weak_ptr { ptr };
131 EXPECT_EQ(weak_ptr.get(), ptr.get());
132
133 BaseObjectPtr<DummyBaseObject> ptr2 = std::move(ptr);
134 EXPECT_EQ(weak_ptr.get(), ptr2.get());
135 EXPECT_EQ(ptr.get(), nullptr);
136
137 BaseObjectWeakPtr<DummyBaseObject> weak_ptr2 = std::move(weak_ptr);
138 EXPECT_EQ(weak_ptr2.get(), ptr2.get());
139 EXPECT_EQ(weak_ptr.get(), nullptr);
140 EXPECT_EQ(env->base_object_count(), 1);
141
142 ptr2.reset();
143
144 EXPECT_EQ(weak_ptr2.get(), nullptr);
145 EXPECT_EQ(env->base_object_count(), 0);
146 }
147
TEST_F(BaseObjectPtrTest,NestedClasses)148 TEST_F(BaseObjectPtrTest, NestedClasses) {
149 class ObjectWithPtr : public BaseObject {
150 public:
151 ObjectWithPtr(Environment* env, Local<Object> obj) : BaseObject(env, obj) {}
152
153 BaseObjectPtr<BaseObject> ptr1;
154 BaseObjectPtr<BaseObject> ptr2;
155
156 SET_NO_MEMORY_INFO()
157 SET_MEMORY_INFO_NAME(ObjectWithPtr)
158 SET_SELF_SIZE(ObjectWithPtr)
159 };
160
161 const HandleScope handle_scope(isolate_);
162 const Argv argv;
163 Env env_{handle_scope, argv};
164 Environment* env = *env_;
165
166 node::AddEnvironmentCleanupHook(isolate_, [](void* arg) {
167 EXPECT_EQ(static_cast<Environment*>(arg)->base_object_count(), 0);
168 }, env);
169
170 ObjectWithPtr* obj =
171 new ObjectWithPtr(env, DummyBaseObject::MakeJSObject(env));
172 obj->ptr1 = DummyBaseObject::NewDetached(env);
173 obj->ptr2 = DummyBaseObject::New(env);
174
175 EXPECT_EQ(env->base_object_count(), 3);
176 }
177