• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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