1 #include "node_test_fixture.h"
2 #include "node_api.h"
3
InitializeBinding(v8::Local<v8::Object> exports,v8::Local<v8::Value> module,v8::Local<v8::Context> context,void * priv)4 void InitializeBinding(v8::Local<v8::Object> exports,
5 v8::Local<v8::Value> module,
6 v8::Local<v8::Context> context,
7 void* priv) {
8 v8::Isolate* isolate = context->GetIsolate();
9 exports->Set(
10 context,
11 v8::String::NewFromOneByte(isolate,
12 reinterpret_cast<const uint8_t*>("key"))
13 .ToLocalChecked(),
14 v8::String::NewFromOneByte(isolate,
15 reinterpret_cast<const uint8_t*>("value"))
16 .ToLocalChecked())
17 .FromJust();
18 }
19
20 NODE_MODULE_LINKED(cctest_linkedbinding, InitializeBinding)
21
22 class LinkedBindingTest : public EnvironmentTestFixture {};
23
TEST_F(LinkedBindingTest,SimpleTest)24 TEST_F(LinkedBindingTest, SimpleTest) {
25 const v8::HandleScope handle_scope(isolate_);
26 const Argv argv;
27 Env test_env {handle_scope, argv};
28
29 v8::Local<v8::Context> context = isolate_->GetCurrentContext();
30
31 const char* run_script =
32 "process._linkedBinding('cctest_linkedbinding').key";
33 v8::Local<v8::Script> script = v8::Script::Compile(
34 context,
35 v8::String::NewFromOneByte(isolate_,
36 reinterpret_cast<const uint8_t*>(run_script))
37 .ToLocalChecked())
38 .ToLocalChecked();
39 v8::Local<v8::Value> completion_value = script->Run(context).ToLocalChecked();
40 v8::String::Utf8Value utf8val(isolate_, completion_value);
41 CHECK_NOT_NULL(*utf8val);
42 CHECK_EQ(strcmp(*utf8val, "value"), 0);
43 }
44
InitializeLocalBinding(v8::Local<v8::Object> exports,v8::Local<v8::Value> module,v8::Local<v8::Context> context,void * priv)45 void InitializeLocalBinding(v8::Local<v8::Object> exports,
46 v8::Local<v8::Value> module,
47 v8::Local<v8::Context> context,
48 void* priv) {
49 ++*static_cast<int*>(priv);
50 v8::Isolate* isolate = context->GetIsolate();
51 exports->Set(
52 context,
53 v8::String::NewFromOneByte(isolate,
54 reinterpret_cast<const uint8_t*>("key"))
55 .ToLocalChecked(),
56 v8::String::NewFromOneByte(isolate,
57 reinterpret_cast<const uint8_t*>("value"))
58 .ToLocalChecked())
59 .FromJust();
60 }
61
TEST_F(LinkedBindingTest,LocallyDefinedLinkedBindingTest)62 TEST_F(LinkedBindingTest, LocallyDefinedLinkedBindingTest) {
63 const v8::HandleScope handle_scope(isolate_);
64 const Argv argv;
65 Env test_env {handle_scope, argv};
66
67 int calls = 0;
68 AddLinkedBinding(*test_env, "local_linked", InitializeLocalBinding, &calls);
69
70 v8::Local<v8::Context> context = isolate_->GetCurrentContext();
71
72 const char* run_script =
73 "process._linkedBinding('local_linked').key";
74 v8::Local<v8::Script> script = v8::Script::Compile(
75 context,
76 v8::String::NewFromOneByte(isolate_,
77 reinterpret_cast<const uint8_t*>(run_script))
78 .ToLocalChecked())
79 .ToLocalChecked();
80 v8::Local<v8::Value> completion_value = script->Run(context).ToLocalChecked();
81 v8::String::Utf8Value utf8val(isolate_, completion_value);
82 CHECK_NOT_NULL(*utf8val);
83 CHECK_EQ(strcmp(*utf8val, "value"), 0);
84 CHECK_EQ(calls, 1);
85 }
86
InitializeLocalNapiBinding(napi_env env,napi_value exports)87 napi_value InitializeLocalNapiBinding(napi_env env, napi_value exports) {
88 napi_value key, value;
89 CHECK_EQ(
90 napi_create_string_utf8(env, "hello", NAPI_AUTO_LENGTH, &key), napi_ok);
91 CHECK_EQ(
92 napi_create_string_utf8(env, "world", NAPI_AUTO_LENGTH, &value), napi_ok);
93 CHECK_EQ(napi_set_property(env, exports, key, value), napi_ok);
94 return nullptr;
95 }
96
97 static napi_module local_linked_napi = {
98 NAPI_MODULE_VERSION,
99 node::ModuleFlags::kLinked,
100 nullptr,
101 InitializeLocalNapiBinding,
102 "local_linked_napi",
103 nullptr,
104 {0},
105 };
106
TEST_F(LinkedBindingTest,LocallyDefinedLinkedBindingNapiTest)107 TEST_F(LinkedBindingTest, LocallyDefinedLinkedBindingNapiTest) {
108 const v8::HandleScope handle_scope(isolate_);
109 const Argv argv;
110 Env test_env {handle_scope, argv};
111
112 AddLinkedBinding(*test_env, local_linked_napi);
113
114 v8::Local<v8::Context> context = isolate_->GetCurrentContext();
115
116 const char* run_script =
117 "process._linkedBinding('local_linked_napi').hello";
118 v8::Local<v8::Script> script = v8::Script::Compile(
119 context,
120 v8::String::NewFromOneByte(isolate_,
121 reinterpret_cast<const uint8_t*>(run_script))
122 .ToLocalChecked())
123 .ToLocalChecked();
124 v8::Local<v8::Value> completion_value = script->Run(context).ToLocalChecked();
125 v8::String::Utf8Value utf8val(isolate_, completion_value);
126 CHECK_NOT_NULL(*utf8val);
127 CHECK_EQ(strcmp(*utf8val, "world"), 0);
128 }
129
NapiLinkedWithInstanceData(napi_env env,napi_value exports)130 napi_value NapiLinkedWithInstanceData(napi_env env, napi_value exports) {
131 int* instance_data = new int(0);
132 CHECK_EQ(
133 napi_set_instance_data(
134 env,
135 instance_data,
136 [](napi_env env, void* data, void* hint) {
137 ++*static_cast<int*>(data);
138 }, nullptr),
139 napi_ok);
140
141 napi_value key, value;
142 CHECK_EQ(
143 napi_create_string_utf8(env, "hello", NAPI_AUTO_LENGTH, &key), napi_ok);
144 CHECK_EQ(
145 napi_create_external(env, instance_data, nullptr, nullptr, &value),
146 napi_ok);
147 CHECK_EQ(napi_set_property(env, exports, key, value), napi_ok);
148 return nullptr;
149 }
150
151 static napi_module local_linked_napi_id = {
152 NAPI_MODULE_VERSION,
153 node::ModuleFlags::kLinked,
154 nullptr,
155 NapiLinkedWithInstanceData,
156 "local_linked_napi_id",
157 nullptr,
158 {0},
159 };
160
TEST_F(LinkedBindingTest,LocallyDefinedLinkedBindingNapiInstanceDataTest)161 TEST_F(LinkedBindingTest, LocallyDefinedLinkedBindingNapiInstanceDataTest) {
162 const v8::HandleScope handle_scope(isolate_);
163 int* instance_data = nullptr;
164
165 {
166 const Argv argv;
167 Env test_env {handle_scope, argv};
168
169 AddLinkedBinding(*test_env, local_linked_napi_id);
170
171 v8::Local<v8::Context> context = isolate_->GetCurrentContext();
172
173 const char* run_script =
174 "process._linkedBinding('local_linked_napi_id').hello";
175 v8::Local<v8::Script> script = v8::Script::Compile(
176 context,
177 v8::String::NewFromOneByte(isolate_,
178 reinterpret_cast<const uint8_t*>(run_script))
179 .ToLocalChecked())
180 .ToLocalChecked();
181 v8::Local<v8::Value> completion_value =
182 script->Run(context).ToLocalChecked();
183 CHECK(completion_value->IsExternal());
184 instance_data = static_cast<int*>(
185 completion_value.As<v8::External>()->Value());
186 CHECK_NE(instance_data, nullptr);
187 CHECK_EQ(*instance_data, 0);
188 }
189
190 CHECK_EQ(*instance_data, 1);
191 delete instance_data;
192 }
193
TEST_F(LinkedBindingTest,ManyBindingsTest)194 TEST_F(LinkedBindingTest, ManyBindingsTest) {
195 const v8::HandleScope handle_scope(isolate_);
196 const Argv argv;
197 Env test_env {handle_scope, argv};
198
199 int calls = 0;
200 AddLinkedBinding(*test_env, "local_linked1", InitializeLocalBinding, &calls);
201 AddLinkedBinding(*test_env, "local_linked2", InitializeLocalBinding, &calls);
202 AddLinkedBinding(*test_env, "local_linked3", InitializeLocalBinding, &calls);
203 AddLinkedBinding(*test_env, local_linked_napi); // Add a N-API addon as well.
204 AddLinkedBinding(*test_env, "local_linked4", InitializeLocalBinding, &calls);
205 AddLinkedBinding(*test_env, "local_linked5", InitializeLocalBinding, &calls);
206
207 v8::Local<v8::Context> context = isolate_->GetCurrentContext();
208
209 const char* run_script =
210 "for (let i = 1; i <= 5; i++)process._linkedBinding(`local_linked${i}`);"
211 "process._linkedBinding('local_linked_napi').hello";
212 v8::Local<v8::Script> script = v8::Script::Compile(
213 context,
214 v8::String::NewFromOneByte(isolate_,
215 reinterpret_cast<const uint8_t*>(run_script))
216 .ToLocalChecked())
217 .ToLocalChecked();
218 v8::Local<v8::Value> completion_value = script->Run(context).ToLocalChecked();
219 v8::String::Utf8Value utf8val(isolate_, completion_value);
220 CHECK_NOT_NULL(*utf8val);
221 CHECK_EQ(strcmp(*utf8val, "world"), 0);
222 CHECK_EQ(calls, 5);
223 }
224
225