1 /*
2 * Copyright (c) 2024 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "ecmascript/napi/jsnapi_helper.h"
17 #include "ecmascript/tests/test_helper.h"
18 #include "gtest/gtest.h"
19
20 using namespace panda::ecmascript;
21
22 namespace panda::test {
23 class JSNApiTests : public testing::Test {
24 public:
SetUpTestCase()25 static void SetUpTestCase()
26 {
27 GTEST_LOG_(INFO) << "SetUpTestCase";
28 }
29
TearDownTestCase()30 static void TearDownTestCase()
31 {
32 GTEST_LOG_(INFO) << "TearDownCase";
33 }
34
SetUp()35 void SetUp() override
36 {
37 RuntimeOption option;
38 option.SetLogLevel(RuntimeOption::LOG_LEVEL::ERROR);
39 vm_ = JSNApi::CreateJSVM(option);
40 ASSERT_TRUE(vm_ != nullptr) << "Cannot create Runtime";
41 thread_ = vm_->GetJSThread();
42 vm_->SetEnableForceGC(true);
43 thread_->ManagedCodeBegin();
44 staticKey = StringRef::NewFromUtf8(vm_, "static");
45 nonStaticKey = StringRef::NewFromUtf8(vm_, "nonStatic");
46 instanceKey = StringRef::NewFromUtf8(vm_, "instance");
47 getterSetterKey = StringRef::NewFromUtf8(vm_, "getterSetter");
48 invalidKey = StringRef::NewFromUtf8(vm_, "invalid");
49 }
50
TearDown()51 void TearDown() override
52 {
53 thread_->ManagedCodeEnd();
54 vm_->SetEnableForceGC(false);
55 JSNApi::DestroyJSVM(vm_);
56 }
57
58 template <typename T>
TestNumberRef(T val,TaggedType expected)59 void TestNumberRef(T val, TaggedType expected)
60 {
61 LocalScope scope(vm_);
62 Local<NumberRef> obj = NumberRef::New(vm_, val);
63 ASSERT_TRUE(obj->IsNumber());
64 JSTaggedType res = JSNApiHelper::ToJSTaggedValue(*obj).GetRawData();
65 ASSERT_EQ(res, expected);
66 if constexpr (std::is_floating_point_v<T>) {
67 if (std::isnan(val)) {
68 ASSERT_TRUE(std::isnan(obj->Value()));
69 } else {
70 ASSERT_EQ(obj->Value(), val);
71 }
72 } else if constexpr (sizeof(T) >= sizeof(int32_t)) {
73 ASSERT_EQ(obj->IntegerValue(vm_), val);
74 } else if constexpr (std::is_signed_v<T>) {
75 ASSERT_EQ(obj->Int32Value(vm_), val);
76 } else {
77 ASSERT_EQ(obj->Uint32Value(vm_), val);
78 }
79 }
80
ConvertDouble(double val)81 TaggedType ConvertDouble(double val)
82 {
83 return base::bit_cast<JSTaggedType>(val) + JSTaggedValue::DOUBLE_ENCODE_OFFSET;
84 }
85
86 protected:
87 JSThread *thread_ = nullptr;
88 EcmaVM *vm_ = nullptr;
89 Local<StringRef> staticKey;
90 Local<StringRef> nonStaticKey;
91 Local<StringRef> instanceKey;
92 Local<StringRef> getterSetterKey;
93 Local<StringRef> invalidKey;
94 };
95
FunctionCallback(JsiRuntimeCallInfo * info)96 panda::JSValueRef FunctionCallback(JsiRuntimeCallInfo *info)
97 {
98 EcmaVM *vm = info->GetVM();
99 Local<JSValueRef> jsThisRef = info->GetThisRef();
100 Local<ObjectRef> thisRef = jsThisRef->ToObject(vm);
101 return **thisRef;
102 }
103
GetNewSendableClassFunction(EcmaVM * vm,Local<FunctionRef> parent,bool isDict=false,bool duplicated=false,bool isParent=false)104 Local<FunctionRef> GetNewSendableClassFunction(
105 EcmaVM *vm, Local<FunctionRef> parent, bool isDict = false, bool duplicated = false, bool isParent = false)
106 {
107 FunctionRef::SendablePropertiesInfos infos;
108
109 if (isDict) {
110 uint32_t maxInline = std::max(JSSharedFunction::MAX_INLINE, JSSharedObject::MAX_INLINE);
111 for (uint32_t i = 0; i < maxInline; ++i) {
112 Local<StringRef> tempStr = StringRef::NewFromUtf8(vm, std::to_string(i).c_str());
113 infos.instancePropertiesInfo.keys.push_back(tempStr);
114 infos.instancePropertiesInfo.types.push_back(FunctionRef::SendableType::NONE);
115 infos.instancePropertiesInfo.attributes.push_back(PropertyAttribute(tempStr, true, true, true));
116 infos.staticPropertiesInfo.keys.push_back(tempStr);
117 infos.staticPropertiesInfo.types.push_back(FunctionRef::SendableType::NONE);
118 infos.staticPropertiesInfo.attributes.push_back(PropertyAttribute(tempStr, true, true, true));
119 infos.nonStaticPropertiesInfo.keys.push_back(tempStr);
120 infos.nonStaticPropertiesInfo.types.push_back(FunctionRef::SendableType::NONE);
121 infos.nonStaticPropertiesInfo.attributes.push_back(PropertyAttribute(tempStr, true, true, true));
122 }
123 }
124
125 std::string instanceKey = "instance";
126 std::string staticKey = "static";
127 std::string nonStaticKey = "nonStatic";
128
129 if (isParent) {
130 instanceKey = "parentInstance";
131 staticKey = "parentStatic";
132 nonStaticKey = "parentNonStatic";
133 }
134
135 Local<StringRef> instanceStr = StringRef::NewFromUtf8(vm, instanceKey.c_str());
136 infos.instancePropertiesInfo.keys.push_back(instanceStr);
137 infos.instancePropertiesInfo.types.push_back(FunctionRef::SendableType::NONE);
138 infos.instancePropertiesInfo.attributes.push_back(PropertyAttribute(instanceStr, true, true, true));
139
140 Local<StringRef> staticStr = StringRef::NewFromUtf8(vm, staticKey.c_str());
141 infos.staticPropertiesInfo.keys.push_back(staticStr);
142 infos.staticPropertiesInfo.types.push_back(FunctionRef::SendableType::NONE);
143 infos.staticPropertiesInfo.attributes.push_back(PropertyAttribute(staticStr, true, true, true));
144
145 Local<StringRef> nonStaticStr = StringRef::NewFromUtf8(vm, nonStaticKey.c_str());
146 infos.nonStaticPropertiesInfo.keys.push_back(nonStaticStr);
147 infos.nonStaticPropertiesInfo.types.push_back(FunctionRef::SendableType::NONE);
148 infos.nonStaticPropertiesInfo.attributes.push_back(PropertyAttribute(nonStaticStr, true, true, true));
149
150 if (duplicated) {
151 Local<StringRef> duplicatedKey = StringRef::NewFromUtf8(vm, "parentInstance");
152 Local<NumberRef> duplicatedValue = NumberRef::New(vm, 0);
153 infos.instancePropertiesInfo.keys.push_back(duplicatedKey);
154 infos.instancePropertiesInfo.types.push_back(FunctionRef::SendableType::NONE);
155 infos.instancePropertiesInfo.attributes.push_back(PropertyAttribute(duplicatedValue, true, true, true));
156 }
157
158 Local<FunctionRef> constructor = FunctionRef::NewSendableClassFunction(
159 vm, FunctionCallback, nullptr, nullptr, StringRef::NewFromUtf8(vm, "name"), infos, parent);
160
161 return constructor;
162 }
163
HWTEST_F_L0(JSNApiTests,NewSendableClassFunction)164 HWTEST_F_L0(JSNApiTests, NewSendableClassFunction)
165 {
166 LocalScope scope(vm_);
167 Local<FunctionRef> constructor = GetNewSendableClassFunction(vm_, FunctionRef::Null(vm_));
168
169 ASSERT_EQ("name", constructor->GetName(vm_)->ToString(vm_));
170 ASSERT_TRUE(constructor->IsFunction(vm_));
171 JSHandle<JSTaggedValue> jsConstructor = JSNApiHelper::ToJSHandle(constructor);
172 ASSERT_TRUE(jsConstructor->IsClassConstructor());
173
174 Local<JSValueRef> functionPrototype = constructor->GetFunctionPrototype(vm_);
175 ASSERT_TRUE(functionPrototype->IsObject(vm_));
176 JSHandle<JSTaggedValue> jsPrototype = JSNApiHelper::ToJSHandle(functionPrototype);
177 ASSERT_TRUE(jsPrototype->IsClassPrototype());
178
179 const GlobalEnvConstants *globalConst = thread_->GlobalConstants();
180 auto prototype = JSTaggedValue::GetProperty(
181 thread_, JSNApiHelper::ToJSHandle(constructor), globalConst->GetHandledPrototypeString())
182 .GetValue();
183 ASSERT_FALSE(prototype->IsUndefined());
184 ASSERT_TRUE(prototype->IsECMAObject() || prototype->IsNull());
185 }
186
HWTEST_F_L0(JSNApiTests,NewSendableClassFunctionProperties)187 HWTEST_F_L0(JSNApiTests, NewSendableClassFunctionProperties)
188 {
189 LocalScope scope(vm_);
190 Local<FunctionRef> constructor = GetNewSendableClassFunction(vm_, FunctionRef::Null(vm_));
191 Local<ObjectRef> prototype = constructor->GetFunctionPrototype(vm_);
192
193 ASSERT_EQ("static", constructor->Get(vm_, staticKey)->ToString(vm_)->ToString(vm_));
194 ASSERT_EQ("nonStatic", prototype->Get(vm_, nonStaticKey)->ToString(vm_)->ToString(vm_));
195 ASSERT_EQ("undefined", constructor->Get(vm_, invalidKey)->ToString(vm_)->ToString(vm_));
196 ASSERT_EQ("undefined", prototype->Get(vm_, invalidKey)->ToString(vm_)->ToString(vm_));
197
198 // set static property on constructor
199 constructor->Set(vm_, staticKey, StringRef::NewFromUtf8(vm_, "static0"));
200 ASSERT_EQ("static0", constructor->Get(vm_, staticKey)->ToString(vm_)->ToString(vm_));
201
202 // set non static property on prototype
203 prototype->Set(vm_, nonStaticKey, StringRef::NewFromUtf8(vm_, "nonStatic0"));
204 ASSERT_EQ("nonStatic0", prototype->Get(vm_, nonStaticKey)->ToString(vm_)->ToString(vm_));
205
206 // set invalid property on constructor
207 ASSERT_FALSE(vm_->GetJSThread()->HasPendingException());
208 constructor->Set(vm_, invalidKey, StringRef::NewFromUtf8(vm_, "invalid"));
209 ASSERT_TRUE(vm_->GetJSThread()->HasPendingException());
210 JSNApi::GetAndClearUncaughtException(vm_);
211 ASSERT_EQ("undefined", constructor->Get(vm_, invalidKey)->ToString(vm_)->ToString(vm_));
212
213 // set invalid property on prototype
214 ASSERT_FALSE(vm_->GetJSThread()->HasPendingException());
215 prototype->Set(vm_, invalidKey, StringRef::NewFromUtf8(vm_, "invalid"));
216 ASSERT_TRUE(vm_->GetJSThread()->HasPendingException());
217 JSNApi::GetAndClearUncaughtException(vm_);
218 ASSERT_EQ("undefined", prototype->Get(vm_, invalidKey)->ToString(vm_)->ToString(vm_));
219 }
220
HWTEST_F_L0(JSNApiTests,NewSendableClassFunctionDictProperties)221 HWTEST_F_L0(JSNApiTests, NewSendableClassFunctionDictProperties)
222 {
223 LocalScope scope(vm_);
224 Local<FunctionRef> constructor = GetNewSendableClassFunction(vm_, FunctionRef::Null(vm_), true);
225 Local<ObjectRef> prototype = constructor->GetFunctionPrototype(vm_);
226
227 ASSERT_EQ("static", constructor->Get(vm_, staticKey)->ToString(vm_)->ToString(vm_));
228 ASSERT_EQ("nonStatic", prototype->Get(vm_, nonStaticKey)->ToString(vm_)->ToString(vm_));
229 ASSERT_EQ("undefined", constructor->Get(vm_, invalidKey)->ToString(vm_)->ToString(vm_));
230 ASSERT_EQ("undefined", prototype->Get(vm_, invalidKey)->ToString(vm_)->ToString(vm_));
231
232 // set static property on constructor
233 constructor->Set(vm_, staticKey, StringRef::NewFromUtf8(vm_, "static0"));
234 ASSERT_EQ("static0", constructor->Get(vm_, staticKey)->ToString(vm_)->ToString(vm_));
235
236 // set non static property on prototype
237 prototype->Set(vm_, nonStaticKey, StringRef::NewFromUtf8(vm_, "nonStatic0"));
238 ASSERT_EQ("nonStatic0", prototype->Get(vm_, nonStaticKey)->ToString(vm_)->ToString(vm_));
239
240 // set invalid property on constructor
241 ASSERT_FALSE(vm_->GetJSThread()->HasPendingException());
242 constructor->Set(vm_, invalidKey, StringRef::NewFromUtf8(vm_, "invalid"));
243 ASSERT_TRUE(vm_->GetJSThread()->HasPendingException());
244 JSNApi::GetAndClearUncaughtException(vm_);
245 ASSERT_EQ("undefined", constructor->Get(vm_, invalidKey)->ToString(vm_)->ToString(vm_));
246
247 // set invalid property on prototype
248 ASSERT_FALSE(vm_->GetJSThread()->HasPendingException());
249 prototype->Set(vm_, invalidKey, StringRef::NewFromUtf8(vm_, "invalid"));
250 ASSERT_TRUE(vm_->GetJSThread()->HasPendingException());
251 JSNApi::GetAndClearUncaughtException(vm_);
252 ASSERT_EQ("undefined", prototype->Get(vm_, invalidKey)->ToString(vm_)->ToString(vm_));
253 }
254
HWTEST_F_L0(JSNApiTests,NewSendableClassFunctionInstance)255 HWTEST_F_L0(JSNApiTests, NewSendableClassFunctionInstance)
256 {
257 LocalScope scope(vm_);
258 Local<FunctionRef> constructor = GetNewSendableClassFunction(vm_, FunctionRef::Null(vm_));
259 Local<JSValueRef> argv[1] = {NumberRef::New(vm_, 0)};
260 Local<ObjectRef> obj = constructor->Constructor(vm_, argv, 0);
261 Local<ObjectRef> obj0 = constructor->Constructor(vm_, argv, 0);
262
263 ASSERT_TRUE(JSFunction::InstanceOf(thread_, JSNApiHelper::ToJSHandle(obj), JSNApiHelper::ToJSHandle(constructor)));
264 ASSERT_TRUE(JSFunction::InstanceOf(thread_, JSNApiHelper::ToJSHandle(obj0), JSNApiHelper::ToJSHandle(constructor)));
265
266 // set instance property
267 ASSERT_EQ("undefined", obj->Get(vm_, instanceKey)->ToString(vm_)->ToString(vm_));
268 ASSERT_EQ("undefined", obj0->Get(vm_, instanceKey)->ToString(vm_)->ToString(vm_));
269 obj->Set(vm_, instanceKey, StringRef::NewFromUtf8(vm_, "instance"));
270 ASSERT_EQ("instance", obj->Get(vm_, instanceKey)->ToString(vm_)->ToString(vm_));
271 ASSERT_EQ("undefined", obj0->Get(vm_, instanceKey)->ToString(vm_)->ToString(vm_));
272
273 // set non static property on prototype and get from instance
274 ASSERT_EQ("nonStatic", obj->Get(vm_, nonStaticKey)->ToString(vm_)->ToString(vm_));
275 ASSERT_EQ("nonStatic", obj0->Get(vm_, nonStaticKey)->ToString(vm_)->ToString(vm_));
276 Local<ObjectRef> prototype = obj->GetPrototype(vm_);
277 prototype->Set(vm_, nonStaticKey, StringRef::NewFromUtf8(vm_, "nonStatic0"));
278 ASSERT_EQ("nonStatic0", obj->Get(vm_, nonStaticKey)->ToString(vm_)->ToString(vm_));
279 ASSERT_EQ("nonStatic0", obj0->Get(vm_, nonStaticKey)->ToString(vm_)->ToString(vm_));
280
281 // set non static property on instance
282 ASSERT_FALSE(vm_->GetJSThread()->HasPendingException());
283 obj->Set(vm_, nonStaticKey, StringRef::NewFromUtf8(vm_, "nonStatic1"));
284 ASSERT_TRUE(vm_->GetJSThread()->HasPendingException());
285 JSNApi::GetAndClearUncaughtException(vm_);
286 ASSERT_EQ("nonStatic0", obj->Get(vm_, nonStaticKey)->ToString(vm_)->ToString(vm_));
287 ASSERT_EQ("nonStatic0", obj0->Get(vm_, nonStaticKey)->ToString(vm_)->ToString(vm_));
288
289 // set invalid property on instance
290 ASSERT_EQ("undefined", obj->Get(vm_, invalidKey)->ToString(vm_)->ToString(vm_));
291 ASSERT_FALSE(vm_->GetJSThread()->HasPendingException());
292 obj->Set(vm_, invalidKey, StringRef::NewFromUtf8(vm_, "invalid"));
293 ASSERT_TRUE(vm_->GetJSThread()->HasPendingException());
294 JSNApi::GetAndClearUncaughtException(vm_);
295 ASSERT_EQ("undefined", obj->Get(vm_, invalidKey)->ToString(vm_)->ToString(vm_));
296 }
297
HWTEST_F_L0(JSNApiTests,NewSendableClassFunctionDictInstance)298 HWTEST_F_L0(JSNApiTests, NewSendableClassFunctionDictInstance)
299 {
300 LocalScope scope(vm_);
301 Local<FunctionRef> constructor = GetNewSendableClassFunction(vm_, FunctionRef::Null(vm_), true);
302 Local<JSValueRef> argv[1] = {NumberRef::New(vm_, 0)};
303 Local<ObjectRef> obj = constructor->Constructor(vm_, argv, 0);
304 Local<ObjectRef> obj0 = constructor->Constructor(vm_, argv, 0);
305
306 ASSERT_TRUE(JSFunction::InstanceOf(thread_, JSNApiHelper::ToJSHandle(obj), JSNApiHelper::ToJSHandle(constructor)));
307 ASSERT_TRUE(JSFunction::InstanceOf(thread_, JSNApiHelper::ToJSHandle(obj0), JSNApiHelper::ToJSHandle(constructor)));
308
309 // set instance property
310 ASSERT_EQ("undefined", obj->Get(vm_, instanceKey)->ToString(vm_)->ToString(vm_));
311 ASSERT_EQ("undefined", obj0->Get(vm_, instanceKey)->ToString(vm_)->ToString(vm_));
312 obj->Set(vm_, instanceKey, StringRef::NewFromUtf8(vm_, "instance"));
313 ASSERT_EQ("instance", obj->Get(vm_, instanceKey)->ToString(vm_)->ToString(vm_));
314 ASSERT_EQ("undefined", obj0->Get(vm_, instanceKey)->ToString(vm_)->ToString(vm_));
315
316 // set non static property on prototype and get from instance
317 ASSERT_EQ("nonStatic", obj->Get(vm_, nonStaticKey)->ToString(vm_)->ToString(vm_));
318 ASSERT_EQ("nonStatic", obj0->Get(vm_, nonStaticKey)->ToString(vm_)->ToString(vm_));
319 Local<ObjectRef> prototype = obj->GetPrototype(vm_);
320 prototype->Set(vm_, nonStaticKey, StringRef::NewFromUtf8(vm_, "nonStatic0"));
321 ASSERT_EQ("nonStatic0", obj->Get(vm_, nonStaticKey)->ToString(vm_)->ToString(vm_));
322 ASSERT_EQ("nonStatic0", obj0->Get(vm_, nonStaticKey)->ToString(vm_)->ToString(vm_));
323
324 // set non static property on instance
325 ASSERT_FALSE(vm_->GetJSThread()->HasPendingException());
326 obj->Set(vm_, nonStaticKey, StringRef::NewFromUtf8(vm_, "nonStatic1"));
327 ASSERT_TRUE(vm_->GetJSThread()->HasPendingException());
328 JSNApi::GetAndClearUncaughtException(vm_);
329 ASSERT_EQ("nonStatic0", obj->Get(vm_, nonStaticKey)->ToString(vm_)->ToString(vm_));
330 ASSERT_EQ("nonStatic0", obj0->Get(vm_, nonStaticKey)->ToString(vm_)->ToString(vm_));
331
332 // set invalid property on instance
333 ASSERT_EQ("undefined", obj->Get(vm_, invalidKey)->ToString(vm_)->ToString(vm_));
334 ASSERT_FALSE(vm_->GetJSThread()->HasPendingException());
335 obj->Set(vm_, invalidKey, StringRef::NewFromUtf8(vm_, "invalid"));
336 ASSERT_TRUE(vm_->GetJSThread()->HasPendingException());
337 JSNApi::GetAndClearUncaughtException(vm_);
338 ASSERT_EQ("undefined", obj->Get(vm_, invalidKey)->ToString(vm_)->ToString(vm_));
339 }
340
HWTEST_F_L0(JSNApiTests,NewSendableClassFunctionInherit)341 HWTEST_F_L0(JSNApiTests, NewSendableClassFunctionInherit)
342 {
343 LocalScope scope(vm_);
344 Local<FunctionRef> parent = GetNewSendableClassFunction(vm_, FunctionRef::Null(vm_), false, false, true);
345 Local<FunctionRef> constructor = GetNewSendableClassFunction(vm_, parent);
346 Local<JSValueRef> argv[1] = {NumberRef::New(vm_, 0)};
347 Local<ObjectRef> obj = constructor->Constructor(vm_, argv, 0);
348 Local<ObjectRef> obj0 = constructor->Constructor(vm_, argv, 0);
349
350 ASSERT_TRUE(JSFunction::InstanceOf(thread_, JSNApiHelper::ToJSHandle(obj), JSNApiHelper::ToJSHandle(parent)));
351 ASSERT_TRUE(JSFunction::InstanceOf(thread_, JSNApiHelper::ToJSHandle(obj0), JSNApiHelper::ToJSHandle(parent)));
352
353 // set parent instance property on instance
354 Local<StringRef> parentInstanceKey = StringRef::NewFromUtf8(vm_, "parentInstance");
355 ASSERT_EQ("undefined", obj->Get(vm_, parentInstanceKey)->ToString(vm_)->ToString(vm_));
356 obj->Set(vm_, parentInstanceKey, StringRef::NewFromUtf8(vm_, "parentInstance"));
357 ASSERT_EQ("parentInstance", obj->Get(vm_, parentInstanceKey)->ToString(vm_)->ToString(vm_));
358
359 // get parent static property from constructor
360 Local<StringRef> parentStaticKey = StringRef::NewFromUtf8(vm_, "parentStatic");
361 ASSERT_EQ("parentStatic", constructor->Get(vm_, parentStaticKey)->ToString(vm_)->ToString(vm_));
362
363 // get parent non static property form instance
364 Local<StringRef> parentNonStaticKey = StringRef::NewFromUtf8(vm_, "parentNonStatic");
365 ASSERT_EQ("parentNonStatic", obj->Get(vm_, parentNonStaticKey)->ToString(vm_)->ToString(vm_));
366 }
367
HWTEST_F_L0(JSNApiTests,NewSendableClassFunctionDictInherit)368 HWTEST_F_L0(JSNApiTests, NewSendableClassFunctionDictInherit)
369 {
370 LocalScope scope(vm_);
371 Local<FunctionRef> parent = GetNewSendableClassFunction(vm_, FunctionRef::Null(vm_), true, false, true);
372 Local<FunctionRef> constructor = GetNewSendableClassFunction(vm_, parent);
373 Local<JSValueRef> argv[1] = {NumberRef::New(vm_, 0)};
374 Local<ObjectRef> obj = constructor->Constructor(vm_, argv, 0);
375 Local<ObjectRef> obj0 = constructor->Constructor(vm_, argv, 0);
376
377 ASSERT_TRUE(JSFunction::InstanceOf(thread_, JSNApiHelper::ToJSHandle(obj), JSNApiHelper::ToJSHandle(parent)));
378 ASSERT_TRUE(JSFunction::InstanceOf(thread_, JSNApiHelper::ToJSHandle(obj0), JSNApiHelper::ToJSHandle(parent)));
379
380 // set parent instance property on instance
381 Local<StringRef> parentInstanceKey = StringRef::NewFromUtf8(vm_, "parentInstance");
382 ASSERT_EQ("undefined", obj->Get(vm_, parentInstanceKey)->ToString(vm_)->ToString(vm_));
383 obj->Set(vm_, parentInstanceKey, StringRef::NewFromUtf8(vm_, "parentInstance"));
384 ASSERT_EQ("parentInstance", obj->Get(vm_, parentInstanceKey)->ToString(vm_)->ToString(vm_));
385
386 // get parent static property from constructor
387 Local<StringRef> parentStaticKey = StringRef::NewFromUtf8(vm_, "parentStatic");
388 ASSERT_EQ("parentStatic", constructor->Get(vm_, parentStaticKey)->ToString(vm_)->ToString(vm_));
389
390 // get parent non static property form instance
391 Local<StringRef> parentNonStaticKey = StringRef::NewFromUtf8(vm_, "parentNonStatic");
392 ASSERT_EQ("parentNonStatic", obj->Get(vm_, parentNonStaticKey)->ToString(vm_)->ToString(vm_));
393 }
394
HWTEST_F_L0(JSNApiTests,NewSendableClassFunctionInheritWithDuplicatedKey)395 HWTEST_F_L0(JSNApiTests, NewSendableClassFunctionInheritWithDuplicatedKey)
396 {
397 LocalScope scope(vm_);
398 Local<FunctionRef> parent = GetNewSendableClassFunction(vm_, FunctionRef::Null(vm_), false, false, true);
399 Local<FunctionRef> constructor = GetNewSendableClassFunction(vm_, parent, false, true);
400 Local<JSValueRef> argv[1] = {NumberRef::New(vm_, 0)};
401 Local<ObjectRef> obj = constructor->Constructor(vm_, argv, 0);
402
403 ASSERT_TRUE(JSFunction::InstanceOf(thread_, JSNApiHelper::ToJSHandle(obj), JSNApiHelper::ToJSHandle(parent)));
404
405 // set duplicated instance property on instance
406 Local<StringRef> parentInstanceKey = StringRef::NewFromUtf8(vm_, "parentInstance");
407 ASSERT_EQ("undefined", obj->Get(vm_, parentInstanceKey)->ToString(vm_)->ToString(vm_));
408 obj->Set(vm_, parentInstanceKey, NumberRef::New(vm_, 0));
409 EXPECT_TRUE(NumberRef::New(vm_, 0)->IsStrictEquals(vm_, obj->Get(vm_, parentInstanceKey)));
410 }
411
HWTEST_F_L0(JSNApiTests,NewSendable)412 HWTEST_F_L0(JSNApiTests, NewSendable)
413 {
414 LocalScope scope(vm_);
415 Local<FunctionRef> func = FunctionRef::NewSendable(
416 vm_,
417 [](JsiRuntimeCallInfo *runtimeInfo) -> JSValueRef {
418 EcmaVM *vm = runtimeInfo->GetVM();
419 LocalScope scope(vm);
420 return **StringRef::NewFromUtf8(vm, "funcResult");
421 },
422 nullptr);
423 Local<JSValueRef> res = func->Call(vm_, JSValueRef::Undefined(vm_), nullptr, 0);
424 ASSERT_EQ("funcResult", res->ToString(vm_)->ToString(vm_));
425 }
426
HWTEST_F_L0(JSNApiTests,NewSendableClassFunctionFunction)427 HWTEST_F_L0(JSNApiTests, NewSendableClassFunctionFunction)
428 {
429 LocalScope scope(vm_);
430
431 FunctionRef::SendablePropertiesInfos infos;
432
433 Local<FunctionRef> func = FunctionRef::NewSendable(
434 vm_,
435 [](JsiRuntimeCallInfo *runtimeInfo) -> JSValueRef {
436 EcmaVM *vm = runtimeInfo->GetVM();
437 LocalScope scope(vm);
438 return **StringRef::NewFromUtf8(vm, "funcResult");
439 },
440 nullptr);
441 infos.staticPropertiesInfo.keys.push_back(staticKey);
442 infos.staticPropertiesInfo.types.push_back(FunctionRef::SendableType::OBJECT);
443 infos.staticPropertiesInfo.attributes.push_back(PropertyAttribute(func, true, true, true));
444
445 Local<FunctionRef> constructor = FunctionRef::NewSendableClassFunction(
446 vm_, FunctionCallback, nullptr, nullptr, StringRef::NewFromUtf8(vm_, "name"), infos, FunctionRef::Null(vm_));
447
448 Local<FunctionRef> staticValue = constructor->Get(vm_, staticKey);
449 ASSERT_TRUE(staticValue->IsFunction(vm_));
450 Local<JSValueRef> res = staticValue->Call(vm_, JSValueRef::Undefined(vm_), nullptr, 0);
451 ASSERT_EQ("funcResult", res->ToString(vm_)->ToString(vm_));
452 }
453
HWTEST_F_L0(JSNApiTests,NewSendableClassFunctionGetterSetter)454 HWTEST_F_L0(JSNApiTests, NewSendableClassFunctionGetterSetter)
455 {
456 LocalScope scope(vm_);
457
458 FunctionRef::SendablePropertiesInfos infos;
459
460 Local<StringRef> getterSetter = StringRef::NewFromUtf8(vm_, "getterSetter");
461 infos.staticPropertiesInfo.keys.push_back(getterSetter);
462 infos.staticPropertiesInfo.types.push_back(FunctionRef::SendableType::NONE);
463 infos.staticPropertiesInfo.attributes.push_back(PropertyAttribute(getterSetter, true, true, true));
464 Local<FunctionRef> staticGetter = FunctionRef::NewSendable(
465 vm_,
466 [](JsiRuntimeCallInfo *info) -> JSValueRef {
467 Local<JSValueRef> value = info->GetThisRef();
468 Local<ObjectRef> obj = value->ToObject(info->GetVM());
469 Local<JSValueRef> temp = obj->Get(info->GetVM(), StringRef::NewFromUtf8(info->GetVM(), "getterSetter"));
470 return **temp->ToString(info->GetVM());
471 },
472 nullptr);
473 Local<FunctionRef> staticSetter = FunctionRef::NewSendable(
474 vm_,
475 [](JsiRuntimeCallInfo *info) -> JSValueRef {
476 Local<JSValueRef> arg = info->GetCallArgRef(0);
477 Local<JSValueRef> value = info->GetThisRef();
478 Local<ObjectRef> obj = value->ToObject(info->GetVM());
479 obj->Set(info->GetVM(), StringRef::NewFromUtf8(info->GetVM(), "getterSetter"), arg);
480 return **JSValueRef::Undefined(info->GetVM());
481 },
482 nullptr);
483 Local<JSValueRef> staticValue = panda::ObjectRef::CreateSendableAccessorData(vm_, staticGetter, staticSetter);
484 infos.staticPropertiesInfo.keys.push_back(staticKey);
485 infos.staticPropertiesInfo.types.push_back(FunctionRef::SendableType::OBJECT);
486 infos.staticPropertiesInfo.attributes.push_back(PropertyAttribute(staticValue, true, true, true));
487
488 Local<FunctionRef> constructor = FunctionRef::NewSendableClassFunction(
489 vm_, FunctionCallback, nullptr, nullptr, StringRef::NewFromUtf8(vm_, "name"), infos, FunctionRef::Null(vm_));
490
491 ASSERT_EQ("getterSetter", constructor->Get(vm_, getterSetter)->ToString(vm_)->ToString(vm_));
492 ASSERT_EQ("getterSetter", constructor->Get(vm_, staticKey)->ToString(vm_)->ToString(vm_));
493 constructor->Set(vm_, staticKey, StringRef::NewFromUtf8(vm_, "getterSetter0"));
494 ASSERT_EQ("getterSetter0", constructor->Get(vm_, getterSetter)->ToString(vm_)->ToString(vm_));
495 ASSERT_EQ("getterSetter0", constructor->Get(vm_, staticKey)->ToString(vm_)->ToString(vm_));
496 }
497
HWTEST_F_L0(JSNApiTests,NewObjectWithProperties)498 HWTEST_F_L0(JSNApiTests, NewObjectWithProperties)
499 {
500 LocalScope scope(vm_);
501
502 FunctionRef::SendablePropertiesInfo info;
503 Local<StringRef> str = StringRef::NewFromUtf8(vm_, "str");
504 info.keys.push_back(str);
505 info.types.push_back(FunctionRef::SendableType::NONE);
506 info.attributes.push_back(PropertyAttribute(str, true, true, true));
507
508 Local<ObjectRef> object = ObjectRef::NewSWithProperties(vm_, info);
509 Local<JSValueRef> value = object->Get(vm_, str);
510 EXPECT_TRUE(str->IsStrictEquals(vm_, value));
511 }
512
HWTEST_F_L0(JSNApiTests,SendableMapRef_GetSize_GetTotalElements_Get_GetKey_GetValue)513 HWTEST_F_L0(JSNApiTests, SendableMapRef_GetSize_GetTotalElements_Get_GetKey_GetValue)
514 {
515 LocalScope scope(vm_);
516 Local<SendableMapRef> map = SendableMapRef::New(vm_);
517 Local<JSValueRef> key = StringRef::NewFromUtf8(vm_, "TestKey");
518 Local<JSValueRef> value = StringRef::NewFromUtf8(vm_, "TestValue");
519 map->Set(vm_, key, value);
520 Local<JSValueRef> res = map->Get(vm_, key);
521 ASSERT_EQ(res->ToString(vm_)->ToString(vm_), value->ToString(vm_)->ToString(vm_));
522 int32_t num = map->GetSize(vm_);
523 int32_t num1 = map->GetTotalElements(vm_);
524 ASSERT_EQ(num, 1);
525 ASSERT_EQ(num1, 1);
526 Local<JSValueRef> res1 = map->GetKey(vm_, 0);
527 ASSERT_EQ(res1->ToString(vm_)->ToString(vm_), key->ToString(vm_)->ToString(vm_));
528 Local<JSValueRef> res2 = map->GetValue(vm_, 0);
529 ASSERT_EQ(res2->ToString(vm_)->ToString(vm_), value->ToString(vm_)->ToString(vm_));
530 }
531
HWTEST_F_L0(JSNApiTests,SendableSetRef_GetSize_GetTotalElements_GetValue)532 HWTEST_F_L0(JSNApiTests, SendableSetRef_GetSize_GetTotalElements_GetValue)
533 {
534 LocalScope scope(vm_);
535 Local<SendableSetRef> set = SendableSetRef::New(vm_);
536 EXPECT_TRUE(set->IsSharedSet(vm_));
537 Local<JSValueRef> value = StringRef::NewFromUtf8(vm_, "TestValue");
538 set->Add(vm_, value);
539 int32_t num = set->GetSize(vm_);
540 int32_t num1 = set->GetTotalElements(vm_);
541 ASSERT_EQ(num, 1);
542 ASSERT_EQ(num1, 1);
543 Local<JSValueRef> res = set->GetValue(vm_, 0);
544 ASSERT_EQ(res->ToString(vm_)->ToString(vm_), value->ToString(vm_)->ToString(vm_));
545 }
546
547 } // namespace panda::test
548