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 "ecmascript/serializer/base_deserializer.h"
19 #include "ecmascript/serializer/value_serializer.h"
20 #include "gtest/gtest.h"
21 #include "jsnapi_expo.h"
22
23 using namespace panda::ecmascript;
24
25 namespace panda::test {
26 class JSNApiTests : public testing::Test {
27 public:
SetUpTestCase()28 static void SetUpTestCase()
29 {
30 GTEST_LOG_(INFO) << "SetUpTestCase";
31 }
32
TearDownTestCase()33 static void TearDownTestCase()
34 {
35 GTEST_LOG_(INFO) << "TearDownCase";
36 }
37
SetUp()38 void SetUp() override
39 {
40 RuntimeOption option;
41 option.SetLogLevel(RuntimeOption::LOG_LEVEL::ERROR);
42 vm_ = JSNApi::CreateJSVM(option);
43 ASSERT_TRUE(vm_ != nullptr) << "Cannot create Runtime";
44 thread_ = vm_->GetJSThread();
45 vm_->SetEnableForceGC(true);
46 thread_->ManagedCodeBegin();
47 staticKey = StringRef::NewFromUtf8(vm_, "static");
48 nonStaticKey = StringRef::NewFromUtf8(vm_, "nonStatic");
49 instanceKey = StringRef::NewFromUtf8(vm_, "instance");
50 getterSetterKey = StringRef::NewFromUtf8(vm_, "getterSetter");
51 invalidKey = StringRef::NewFromUtf8(vm_, "invalid");
52 }
53
TearDown()54 void TearDown() override
55 {
56 thread_->ManagedCodeEnd();
57 vm_->SetEnableForceGC(false);
58 JSNApi::DestroyJSVM(vm_);
59 }
60
61 template <typename T>
TestNumberRef(T val,TaggedType expected)62 void TestNumberRef(T val, TaggedType expected)
63 {
64 LocalScope scope(vm_);
65 Local<NumberRef> obj = NumberRef::New(vm_, val);
66 ASSERT_TRUE(obj->IsNumber());
67 JSTaggedType res = JSNApiHelper::ToJSTaggedValue(*obj).GetRawData();
68 ASSERT_EQ(res, expected);
69 if constexpr (std::is_floating_point_v<T>) {
70 if (std::isnan(val)) {
71 ASSERT_TRUE(std::isnan(obj->Value()));
72 } else {
73 ASSERT_EQ(obj->Value(), val);
74 }
75 } else if constexpr (sizeof(T) >= sizeof(int32_t)) {
76 ASSERT_EQ(obj->IntegerValue(vm_), val);
77 } else if constexpr (std::is_signed_v<T>) {
78 ASSERT_EQ(obj->Int32Value(vm_), val);
79 } else {
80 ASSERT_EQ(obj->Uint32Value(vm_), val);
81 }
82 }
83
ConvertDouble(double val)84 TaggedType ConvertDouble(double val)
85 {
86 return base::bit_cast<JSTaggedType>(val) + JSTaggedValue::DOUBLE_ENCODE_OFFSET;
87 }
88
89 protected:
90 JSThread *thread_ = nullptr;
91 EcmaVM *vm_ = nullptr;
92 Local<StringRef> staticKey;
93 Local<StringRef> nonStaticKey;
94 Local<StringRef> instanceKey;
95 Local<StringRef> getterSetterKey;
96 Local<StringRef> invalidKey;
97 };
98
FunctionCallback(JsiRuntimeCallInfo * info)99 panda::JSValueRef FunctionCallback(JsiRuntimeCallInfo *info)
100 {
101 EcmaVM *vm = info->GetVM();
102 Local<JSValueRef> jsThisRef = info->GetThisRef();
103 Local<ObjectRef> thisRef = jsThisRef->ToObject(vm);
104 return **thisRef;
105 }
106
GetNewSendableClassFunction(EcmaVM * vm,Local<FunctionRef> parent,bool isDict=false,bool duplicated=false,bool isParent=false)107 Local<FunctionRef> GetNewSendableClassFunction(
108 EcmaVM *vm, Local<FunctionRef> parent, bool isDict = false, bool duplicated = false, bool isParent = false)
109 {
110 FunctionRef::SendablePropertiesInfos infos;
111
112 if (isDict) {
113 uint32_t maxInline = std::max(JSSharedFunction::MAX_INLINE, JSSharedObject::MAX_INLINE);
114 for (uint32_t i = 0; i < maxInline; ++i) {
115 Local<StringRef> tempStr = StringRef::NewFromUtf8(vm, std::to_string(i).c_str());
116 infos.instancePropertiesInfo.keys.push_back(tempStr);
117 infos.instancePropertiesInfo.types.push_back(FunctionRef::SendableType::NONE);
118 infos.instancePropertiesInfo.attributes.push_back(PropertyAttribute(tempStr, true, true, true));
119 infos.staticPropertiesInfo.keys.push_back(tempStr);
120 infos.staticPropertiesInfo.types.push_back(FunctionRef::SendableType::NONE);
121 infos.staticPropertiesInfo.attributes.push_back(PropertyAttribute(tempStr, true, true, true));
122 infos.nonStaticPropertiesInfo.keys.push_back(tempStr);
123 infos.nonStaticPropertiesInfo.types.push_back(FunctionRef::SendableType::NONE);
124 infos.nonStaticPropertiesInfo.attributes.push_back(PropertyAttribute(tempStr, true, true, true));
125 }
126 }
127
128 std::string instanceKey = "instance";
129 std::string staticKey = "static";
130 std::string nonStaticKey = "nonStatic";
131
132 if (isParent) {
133 instanceKey = "parentInstance";
134 staticKey = "parentStatic";
135 nonStaticKey = "parentNonStatic";
136 }
137
138 Local<StringRef> instanceStr = StringRef::NewFromUtf8(vm, instanceKey.c_str());
139 infos.instancePropertiesInfo.keys.push_back(instanceStr);
140 infos.instancePropertiesInfo.types.push_back(FunctionRef::SendableType::NONE);
141 infos.instancePropertiesInfo.attributes.push_back(PropertyAttribute(instanceStr, true, true, true));
142
143 Local<StringRef> staticStr = StringRef::NewFromUtf8(vm, staticKey.c_str());
144 infos.staticPropertiesInfo.keys.push_back(staticStr);
145 infos.staticPropertiesInfo.types.push_back(FunctionRef::SendableType::NONE);
146 infos.staticPropertiesInfo.attributes.push_back(PropertyAttribute(staticStr, true, true, true));
147
148 Local<StringRef> nonStaticStr = StringRef::NewFromUtf8(vm, nonStaticKey.c_str());
149 infos.nonStaticPropertiesInfo.keys.push_back(nonStaticStr);
150 infos.nonStaticPropertiesInfo.types.push_back(FunctionRef::SendableType::NONE);
151 infos.nonStaticPropertiesInfo.attributes.push_back(PropertyAttribute(nonStaticStr, true, true, true));
152
153 if (duplicated) {
154 Local<StringRef> duplicatedKey = StringRef::NewFromUtf8(vm, "parentInstance");
155 Local<NumberRef> duplicatedValue = NumberRef::New(vm, 0);
156 infos.instancePropertiesInfo.keys.push_back(duplicatedKey);
157 infos.instancePropertiesInfo.types.push_back(FunctionRef::SendableType::NONE);
158 infos.instancePropertiesInfo.attributes.push_back(PropertyAttribute(duplicatedValue, true, true, true));
159 }
160
161 Local<FunctionRef> constructor = FunctionRef::NewSendableClassFunction(
162 vm, FunctionCallback, nullptr, nullptr, StringRef::NewFromUtf8(vm, "name"), infos, parent);
163
164 return constructor;
165 }
166
HWTEST_F_L0(JSNApiTests,NewSendableClassFunction)167 HWTEST_F_L0(JSNApiTests, NewSendableClassFunction)
168 {
169 LocalScope scope(vm_);
170 Local<FunctionRef> constructor = GetNewSendableClassFunction(vm_, JSValueRef::Hole(vm_));
171
172 ASSERT_EQ("name", constructor->GetName(vm_)->ToString(vm_));
173 ASSERT_TRUE(constructor->IsFunction(vm_));
174 JSHandle<JSTaggedValue> jsConstructor = JSNApiHelper::ToJSHandle(constructor);
175 ASSERT_TRUE(jsConstructor->IsClassConstructor());
176
177 Local<JSValueRef> functionPrototype = constructor->GetFunctionPrototype(vm_);
178 ASSERT_TRUE(functionPrototype->IsObject(vm_));
179 JSHandle<JSTaggedValue> jsPrototype = JSNApiHelper::ToJSHandle(functionPrototype);
180 ASSERT_TRUE(jsPrototype->IsClassPrototype());
181
182 const GlobalEnvConstants *globalConst = thread_->GlobalConstants();
183 auto prototype = JSTaggedValue::GetProperty(
184 thread_, JSNApiHelper::ToJSHandle(constructor), globalConst->GetHandledPrototypeString())
185 .GetValue();
186 ASSERT_FALSE(prototype->IsUndefined());
187 ASSERT_TRUE(prototype->IsECMAObject() || prototype->IsNull());
188 }
189
HWTEST_F_L0(JSNApiTests,NewSendableClassFunctionProperties)190 HWTEST_F_L0(JSNApiTests, NewSendableClassFunctionProperties)
191 {
192 LocalScope scope(vm_);
193 Local<FunctionRef> constructor = GetNewSendableClassFunction(vm_, JSValueRef::Hole(vm_));
194 Local<ObjectRef> prototype = constructor->GetFunctionPrototype(vm_);
195
196 ASSERT_EQ("static", constructor->Get(vm_, staticKey)->ToString(vm_)->ToString(vm_));
197 ASSERT_EQ("nonStatic", prototype->Get(vm_, nonStaticKey)->ToString(vm_)->ToString(vm_));
198 ASSERT_EQ("undefined", constructor->Get(vm_, invalidKey)->ToString(vm_)->ToString(vm_));
199 ASSERT_EQ("undefined", prototype->Get(vm_, invalidKey)->ToString(vm_)->ToString(vm_));
200
201 // set static property on constructor
202 constructor->Set(vm_, staticKey, StringRef::NewFromUtf8(vm_, "static0"));
203 ASSERT_EQ("static0", constructor->Get(vm_, staticKey)->ToString(vm_)->ToString(vm_));
204
205 // set non static property on prototype
206 prototype->Set(vm_, nonStaticKey, StringRef::NewFromUtf8(vm_, "nonStatic0"));
207 ASSERT_EQ("nonStatic0", prototype->Get(vm_, nonStaticKey)->ToString(vm_)->ToString(vm_));
208
209 // set invalid property on constructor
210 ASSERT_FALSE(vm_->GetJSThread()->HasPendingException());
211 constructor->Set(vm_, invalidKey, StringRef::NewFromUtf8(vm_, "invalid"));
212 ASSERT_TRUE(vm_->GetJSThread()->HasPendingException());
213 JSNApi::GetAndClearUncaughtException(vm_);
214 ASSERT_EQ("undefined", constructor->Get(vm_, invalidKey)->ToString(vm_)->ToString(vm_));
215
216 // set invalid property on prototype
217 ASSERT_FALSE(vm_->GetJSThread()->HasPendingException());
218 prototype->Set(vm_, invalidKey, StringRef::NewFromUtf8(vm_, "invalid"));
219 ASSERT_TRUE(vm_->GetJSThread()->HasPendingException());
220 JSNApi::GetAndClearUncaughtException(vm_);
221 ASSERT_EQ("undefined", prototype->Get(vm_, invalidKey)->ToString(vm_)->ToString(vm_));
222 }
223
HWTEST_F_L0(JSNApiTests,NewSendableClassFunctionDictProperties)224 HWTEST_F_L0(JSNApiTests, NewSendableClassFunctionDictProperties)
225 {
226 LocalScope scope(vm_);
227 Local<FunctionRef> constructor = GetNewSendableClassFunction(vm_, JSValueRef::Hole(vm_), true);
228 Local<ObjectRef> prototype = constructor->GetFunctionPrototype(vm_);
229
230 ASSERT_EQ("static", constructor->Get(vm_, staticKey)->ToString(vm_)->ToString(vm_));
231 ASSERT_EQ("nonStatic", prototype->Get(vm_, nonStaticKey)->ToString(vm_)->ToString(vm_));
232 ASSERT_EQ("undefined", constructor->Get(vm_, invalidKey)->ToString(vm_)->ToString(vm_));
233 ASSERT_EQ("undefined", prototype->Get(vm_, invalidKey)->ToString(vm_)->ToString(vm_));
234
235 // set static property on constructor
236 constructor->Set(vm_, staticKey, StringRef::NewFromUtf8(vm_, "static0"));
237 ASSERT_EQ("static0", constructor->Get(vm_, staticKey)->ToString(vm_)->ToString(vm_));
238
239 // set non static property on prototype
240 prototype->Set(vm_, nonStaticKey, StringRef::NewFromUtf8(vm_, "nonStatic0"));
241 ASSERT_EQ("nonStatic0", prototype->Get(vm_, nonStaticKey)->ToString(vm_)->ToString(vm_));
242
243 // set invalid property on constructor
244 ASSERT_FALSE(vm_->GetJSThread()->HasPendingException());
245 constructor->Set(vm_, invalidKey, StringRef::NewFromUtf8(vm_, "invalid"));
246 ASSERT_TRUE(vm_->GetJSThread()->HasPendingException());
247 JSNApi::GetAndClearUncaughtException(vm_);
248 ASSERT_EQ("undefined", constructor->Get(vm_, invalidKey)->ToString(vm_)->ToString(vm_));
249
250 // set invalid property on prototype
251 ASSERT_FALSE(vm_->GetJSThread()->HasPendingException());
252 prototype->Set(vm_, invalidKey, StringRef::NewFromUtf8(vm_, "invalid"));
253 ASSERT_TRUE(vm_->GetJSThread()->HasPendingException());
254 JSNApi::GetAndClearUncaughtException(vm_);
255 ASSERT_EQ("undefined", prototype->Get(vm_, invalidKey)->ToString(vm_)->ToString(vm_));
256 }
257
HWTEST_F_L0(JSNApiTests,NewSendableClassFunctionInstance)258 HWTEST_F_L0(JSNApiTests, NewSendableClassFunctionInstance)
259 {
260 LocalScope scope(vm_);
261 Local<FunctionRef> constructor = GetNewSendableClassFunction(vm_, JSValueRef::Hole(vm_));
262 Local<ObjectRef> obj = constructor->Constructor(vm_, nullptr, 0);
263 Local<ObjectRef> obj0 = constructor->Constructor(vm_, nullptr, 0);
264
265 ASSERT_TRUE(JSFunction::InstanceOf(thread_, JSNApiHelper::ToJSHandle(obj), JSNApiHelper::ToJSHandle(constructor)));
266 ASSERT_TRUE(JSFunction::InstanceOf(thread_, JSNApiHelper::ToJSHandle(obj0), JSNApiHelper::ToJSHandle(constructor)));
267
268 // set instance property
269 ASSERT_EQ("undefined", obj->Get(vm_, instanceKey)->ToString(vm_)->ToString(vm_));
270 ASSERT_EQ("undefined", obj0->Get(vm_, instanceKey)->ToString(vm_)->ToString(vm_));
271 obj->Set(vm_, instanceKey, StringRef::NewFromUtf8(vm_, "instance"));
272 ASSERT_EQ("instance", obj->Get(vm_, instanceKey)->ToString(vm_)->ToString(vm_));
273 ASSERT_EQ("undefined", obj0->Get(vm_, instanceKey)->ToString(vm_)->ToString(vm_));
274
275 // set non static property on prototype and get from instance
276 ASSERT_EQ("nonStatic", obj->Get(vm_, nonStaticKey)->ToString(vm_)->ToString(vm_));
277 ASSERT_EQ("nonStatic", obj0->Get(vm_, nonStaticKey)->ToString(vm_)->ToString(vm_));
278 Local<ObjectRef> prototype = obj->GetPrototype(vm_);
279 prototype->Set(vm_, nonStaticKey, StringRef::NewFromUtf8(vm_, "nonStatic0"));
280 ASSERT_EQ("nonStatic0", obj->Get(vm_, nonStaticKey)->ToString(vm_)->ToString(vm_));
281 ASSERT_EQ("nonStatic0", obj0->Get(vm_, nonStaticKey)->ToString(vm_)->ToString(vm_));
282
283 // set non static property on instance
284 ASSERT_FALSE(vm_->GetJSThread()->HasPendingException());
285 obj->Set(vm_, nonStaticKey, StringRef::NewFromUtf8(vm_, "nonStatic1"));
286 ASSERT_TRUE(vm_->GetJSThread()->HasPendingException());
287 JSNApi::GetAndClearUncaughtException(vm_);
288 ASSERT_EQ("nonStatic0", obj->Get(vm_, nonStaticKey)->ToString(vm_)->ToString(vm_));
289 ASSERT_EQ("nonStatic0", obj0->Get(vm_, nonStaticKey)->ToString(vm_)->ToString(vm_));
290
291 // set invalid property on instance
292 ASSERT_EQ("undefined", obj->Get(vm_, invalidKey)->ToString(vm_)->ToString(vm_));
293 ASSERT_FALSE(vm_->GetJSThread()->HasPendingException());
294 obj->Set(vm_, invalidKey, StringRef::NewFromUtf8(vm_, "invalid"));
295 ASSERT_TRUE(vm_->GetJSThread()->HasPendingException());
296 JSNApi::GetAndClearUncaughtException(vm_);
297 ASSERT_EQ("undefined", obj->Get(vm_, invalidKey)->ToString(vm_)->ToString(vm_));
298 }
299
HWTEST_F_L0(JSNApiTests,NewSendableClassFunctionDictInstance)300 HWTEST_F_L0(JSNApiTests, NewSendableClassFunctionDictInstance)
301 {
302 LocalScope scope(vm_);
303 Local<FunctionRef> constructor = GetNewSendableClassFunction(vm_, JSValueRef::Hole(vm_), true);
304 Local<ObjectRef> obj = constructor->Constructor(vm_, nullptr, 0);
305 Local<ObjectRef> obj0 = constructor->Constructor(vm_, nullptr, 0);
306
307 ASSERT_TRUE(JSFunction::InstanceOf(thread_, JSNApiHelper::ToJSHandle(obj), JSNApiHelper::ToJSHandle(constructor)));
308 ASSERT_TRUE(JSFunction::InstanceOf(thread_, JSNApiHelper::ToJSHandle(obj0), JSNApiHelper::ToJSHandle(constructor)));
309
310 // set instance property
311 ASSERT_EQ("undefined", obj->Get(vm_, instanceKey)->ToString(vm_)->ToString(vm_));
312 ASSERT_EQ("undefined", obj0->Get(vm_, instanceKey)->ToString(vm_)->ToString(vm_));
313 obj->Set(vm_, instanceKey, StringRef::NewFromUtf8(vm_, "instance"));
314 ASSERT_EQ("instance", obj->Get(vm_, instanceKey)->ToString(vm_)->ToString(vm_));
315 ASSERT_EQ("undefined", obj0->Get(vm_, instanceKey)->ToString(vm_)->ToString(vm_));
316
317 // set non static property on prototype and get from instance
318 ASSERT_EQ("nonStatic", obj->Get(vm_, nonStaticKey)->ToString(vm_)->ToString(vm_));
319 ASSERT_EQ("nonStatic", obj0->Get(vm_, nonStaticKey)->ToString(vm_)->ToString(vm_));
320 Local<ObjectRef> prototype = obj->GetPrototype(vm_);
321 prototype->Set(vm_, nonStaticKey, StringRef::NewFromUtf8(vm_, "nonStatic0"));
322 ASSERT_EQ("nonStatic0", obj->Get(vm_, nonStaticKey)->ToString(vm_)->ToString(vm_));
323 ASSERT_EQ("nonStatic0", obj0->Get(vm_, nonStaticKey)->ToString(vm_)->ToString(vm_));
324
325 // set non static property on instance
326 ASSERT_FALSE(vm_->GetJSThread()->HasPendingException());
327 obj->Set(vm_, nonStaticKey, StringRef::NewFromUtf8(vm_, "nonStatic1"));
328 ASSERT_TRUE(vm_->GetJSThread()->HasPendingException());
329 JSNApi::GetAndClearUncaughtException(vm_);
330 ASSERT_EQ("nonStatic0", obj->Get(vm_, nonStaticKey)->ToString(vm_)->ToString(vm_));
331 ASSERT_EQ("nonStatic0", obj0->Get(vm_, nonStaticKey)->ToString(vm_)->ToString(vm_));
332
333 // set invalid property on instance
334 ASSERT_EQ("undefined", obj->Get(vm_, invalidKey)->ToString(vm_)->ToString(vm_));
335 ASSERT_FALSE(vm_->GetJSThread()->HasPendingException());
336 obj->Set(vm_, invalidKey, StringRef::NewFromUtf8(vm_, "invalid"));
337 ASSERT_TRUE(vm_->GetJSThread()->HasPendingException());
338 JSNApi::GetAndClearUncaughtException(vm_);
339 ASSERT_EQ("undefined", obj->Get(vm_, invalidKey)->ToString(vm_)->ToString(vm_));
340 }
341
HWTEST_F_L0(JSNApiTests,NewSendableClassFunctionInherit)342 HWTEST_F_L0(JSNApiTests, NewSendableClassFunctionInherit)
343 {
344 LocalScope scope(vm_);
345 Local<FunctionRef> parent = GetNewSendableClassFunction(vm_, JSValueRef::Hole(vm_), false, false, true);
346 Local<FunctionRef> constructor = GetNewSendableClassFunction(vm_, parent);
347 Local<ObjectRef> obj = constructor->Constructor(vm_, nullptr, 0);
348
349 ASSERT_TRUE(JSFunction::InstanceOf(thread_, JSNApiHelper::ToJSHandle(obj), JSNApiHelper::ToJSHandle(constructor)));
350 ASSERT_TRUE(JSFunction::InstanceOf(thread_, JSNApiHelper::ToJSHandle(obj), JSNApiHelper::ToJSHandle(parent)));
351
352 // set parent instance property on instance
353 Local<StringRef> parentInstanceKey = StringRef::NewFromUtf8(vm_, "parentInstance");
354 ASSERT_EQ("undefined", obj->Get(vm_, parentInstanceKey)->ToString(vm_)->ToString(vm_));
355 obj->Set(vm_, parentInstanceKey, StringRef::NewFromUtf8(vm_, "parentInstance"));
356 ASSERT_EQ("parentInstance", obj->Get(vm_, parentInstanceKey)->ToString(vm_)->ToString(vm_));
357
358 // get parent static property from constructor
359 Local<StringRef> parentStaticKey = StringRef::NewFromUtf8(vm_, "parentStatic");
360 ASSERT_EQ("parentStatic", constructor->Get(vm_, parentStaticKey)->ToString(vm_)->ToString(vm_));
361
362 // get parent non static property form instance
363 Local<StringRef> parentNonStaticKey = StringRef::NewFromUtf8(vm_, "parentNonStatic");
364 ASSERT_EQ("parentNonStatic", obj->Get(vm_, parentNonStaticKey)->ToString(vm_)->ToString(vm_));
365 }
366
HWTEST_F_L0(JSNApiTests,NewSendableClassFunctionDictInherit)367 HWTEST_F_L0(JSNApiTests, NewSendableClassFunctionDictInherit)
368 {
369 LocalScope scope(vm_);
370 Local<FunctionRef> parent = GetNewSendableClassFunction(vm_, JSValueRef::Hole(vm_), true, false, true);
371 Local<FunctionRef> constructor = GetNewSendableClassFunction(vm_, parent);
372 Local<ObjectRef> obj = constructor->Constructor(vm_, nullptr, 0);
373
374 ASSERT_TRUE(JSFunction::InstanceOf(thread_, JSNApiHelper::ToJSHandle(obj), JSNApiHelper::ToJSHandle(constructor)));
375 ASSERT_TRUE(JSFunction::InstanceOf(thread_, JSNApiHelper::ToJSHandle(obj), JSNApiHelper::ToJSHandle(parent)));
376
377 // set parent instance property on instance
378 Local<StringRef> parentInstanceKey = StringRef::NewFromUtf8(vm_, "parentInstance");
379 ASSERT_EQ("undefined", obj->Get(vm_, parentInstanceKey)->ToString(vm_)->ToString(vm_));
380 obj->Set(vm_, parentInstanceKey, StringRef::NewFromUtf8(vm_, "parentInstance"));
381 ASSERT_EQ("parentInstance", obj->Get(vm_, parentInstanceKey)->ToString(vm_)->ToString(vm_));
382
383 // get parent static property from constructor
384 Local<StringRef> parentStaticKey = StringRef::NewFromUtf8(vm_, "parentStatic");
385 ASSERT_EQ("parentStatic", constructor->Get(vm_, parentStaticKey)->ToString(vm_)->ToString(vm_));
386
387 // get parent non static property form instance
388 Local<StringRef> parentNonStaticKey = StringRef::NewFromUtf8(vm_, "parentNonStatic");
389 ASSERT_EQ("parentNonStatic", obj->Get(vm_, parentNonStaticKey)->ToString(vm_)->ToString(vm_));
390 }
391
HWTEST_F_L0(JSNApiTests,NewSendableClassFunctionInheritWithDuplicatedKey)392 HWTEST_F_L0(JSNApiTests, NewSendableClassFunctionInheritWithDuplicatedKey)
393 {
394 LocalScope scope(vm_);
395 Local<FunctionRef> parent = GetNewSendableClassFunction(vm_, JSValueRef::Hole(vm_), false, false, true);
396 Local<FunctionRef> constructor = GetNewSendableClassFunction(vm_, parent, false, true);
397 Local<ObjectRef> obj = constructor->Constructor(vm_, nullptr, 0);
398
399 ASSERT_TRUE(JSFunction::InstanceOf(thread_, JSNApiHelper::ToJSHandle(obj), JSNApiHelper::ToJSHandle(constructor)));
400 ASSERT_TRUE(JSFunction::InstanceOf(thread_, JSNApiHelper::ToJSHandle(obj), JSNApiHelper::ToJSHandle(parent)));
401
402 // set duplicated instance property on instance
403 Local<StringRef> parentInstanceKey = StringRef::NewFromUtf8(vm_, "parentInstance");
404 ASSERT_EQ("undefined", obj->Get(vm_, parentInstanceKey)->ToString(vm_)->ToString(vm_));
405 obj->Set(vm_, parentInstanceKey, NumberRef::New(vm_, 0));
406 EXPECT_TRUE(NumberRef::New(vm_, 0)->IsStrictEquals(vm_, obj->Get(vm_, parentInstanceKey)));
407 }
408
HWTEST_F_L0(JSNApiTests,NewSendable)409 HWTEST_F_L0(JSNApiTests, NewSendable)
410 {
411 LocalScope scope(vm_);
412 Local<FunctionRef> func = FunctionRef::NewSendable(
413 vm_,
414 [](JsiRuntimeCallInfo *runtimeInfo) -> JSValueRef {
415 EcmaVM *vm = runtimeInfo->GetVM();
416 LocalScope scope(vm);
417 return **StringRef::NewFromUtf8(vm, "funcResult");
418 },
419 nullptr);
420 Local<JSValueRef> res = func->Call(vm_, JSValueRef::Undefined(vm_), nullptr, 0);
421 ASSERT_EQ("funcResult", res->ToString(vm_)->ToString(vm_));
422 }
423
HWTEST_F_L0(JSNApiTests,NewSendableClassFunctionFunction)424 HWTEST_F_L0(JSNApiTests, NewSendableClassFunctionFunction)
425 {
426 LocalScope scope(vm_);
427
428 FunctionRef::SendablePropertiesInfos infos;
429
430 Local<FunctionRef> func = FunctionRef::NewSendable(
431 vm_,
432 [](JsiRuntimeCallInfo *runtimeInfo) -> JSValueRef {
433 EcmaVM *vm = runtimeInfo->GetVM();
434 LocalScope scope(vm);
435 return **StringRef::NewFromUtf8(vm, "funcResult");
436 },
437 nullptr);
438 infos.staticPropertiesInfo.keys.push_back(staticKey);
439 infos.staticPropertiesInfo.types.push_back(FunctionRef::SendableType::OBJECT);
440 infos.staticPropertiesInfo.attributes.push_back(PropertyAttribute(func, true, true, true));
441
442 Local<FunctionRef> constructor = FunctionRef::NewSendableClassFunction(
443 vm_, FunctionCallback, nullptr, nullptr, StringRef::NewFromUtf8(vm_, "name"), infos, JSValueRef::Hole(vm_));
444
445 Local<FunctionRef> staticValue = constructor->Get(vm_, staticKey);
446 ASSERT_TRUE(staticValue->IsFunction(vm_));
447 Local<JSValueRef> res = staticValue->Call(vm_, JSValueRef::Undefined(vm_), nullptr, 0);
448 ASSERT_EQ("funcResult", res->ToString(vm_)->ToString(vm_));
449 }
450
HWTEST_F_L0(JSNApiTests,NewSendableClassFunctionGetterSetter)451 HWTEST_F_L0(JSNApiTests, NewSendableClassFunctionGetterSetter)
452 {
453 LocalScope scope(vm_);
454
455 FunctionRef::SendablePropertiesInfos infos;
456
457 Local<StringRef> getterSetter = StringRef::NewFromUtf8(vm_, "getterSetter");
458 infos.staticPropertiesInfo.keys.push_back(getterSetter);
459 infos.staticPropertiesInfo.types.push_back(FunctionRef::SendableType::NONE);
460 infos.staticPropertiesInfo.attributes.push_back(PropertyAttribute(getterSetter, true, true, true));
461 Local<FunctionRef> staticGetter = FunctionRef::NewSendable(
462 vm_,
463 [](JsiRuntimeCallInfo *info) -> JSValueRef {
464 Local<JSValueRef> value = info->GetThisRef();
465 Local<ObjectRef> obj = value->ToObject(info->GetVM());
466 Local<JSValueRef> temp = obj->Get(info->GetVM(), StringRef::NewFromUtf8(info->GetVM(), "getterSetter"));
467 return **temp->ToString(info->GetVM());
468 },
469 nullptr);
470 Local<FunctionRef> staticSetter = FunctionRef::NewSendable(
471 vm_,
472 [](JsiRuntimeCallInfo *info) -> JSValueRef {
473 Local<JSValueRef> arg = info->GetCallArgRef(0);
474 Local<JSValueRef> value = info->GetThisRef();
475 Local<ObjectRef> obj = value->ToObject(info->GetVM());
476 obj->Set(info->GetVM(), StringRef::NewFromUtf8(info->GetVM(), "getterSetter"), arg);
477 return **JSValueRef::Undefined(info->GetVM());
478 },
479 nullptr);
480 Local<JSValueRef> staticValue = panda::ObjectRef::CreateSendableAccessorData(vm_, staticGetter, staticSetter);
481 infos.staticPropertiesInfo.keys.push_back(staticKey);
482 infos.staticPropertiesInfo.types.push_back(FunctionRef::SendableType::OBJECT);
483 infos.staticPropertiesInfo.attributes.push_back(PropertyAttribute(staticValue, true, true, true));
484
485 Local<FunctionRef> constructor = FunctionRef::NewSendableClassFunction(
486 vm_, FunctionCallback, nullptr, nullptr, StringRef::NewFromUtf8(vm_, "name"), infos, JSValueRef::Hole(vm_));
487
488 ASSERT_EQ("getterSetter", constructor->Get(vm_, getterSetter)->ToString(vm_)->ToString(vm_));
489 ASSERT_EQ("getterSetter", constructor->Get(vm_, staticKey)->ToString(vm_)->ToString(vm_));
490 constructor->Set(vm_, staticKey, StringRef::NewFromUtf8(vm_, "getterSetter0"));
491 ASSERT_EQ("getterSetter0", constructor->Get(vm_, getterSetter)->ToString(vm_)->ToString(vm_));
492 ASSERT_EQ("getterSetter0", constructor->Get(vm_, staticKey)->ToString(vm_)->ToString(vm_));
493 }
494
HWTEST_F_L0(JSNApiTests,NewSendableClassFunctionStringify)495 HWTEST_F_L0(JSNApiTests, NewSendableClassFunctionStringify)
496 {
497 LocalScope scope(vm_);
498
499 FunctionRef::SendablePropertiesInfos infos;
500 Local<FunctionRef> constructor = FunctionRef::NewSendableClassFunction(
501 vm_, FunctionCallback, nullptr, nullptr, StringRef::NewFromUtf8(vm_, "name"), infos, JSValueRef::Hole(vm_));
502
503 Local<ObjectRef> obj = constructor->Constructor(vm_, nullptr, 0);
504 ASSERT_EQ("[object Object]", obj->ToString(vm_)->ToString(vm_));
505 }
506
HWTEST_F_L0(JSNApiTests,NewObjectWithProperties)507 HWTEST_F_L0(JSNApiTests, NewObjectWithProperties)
508 {
509 LocalScope scope(vm_);
510
511 FunctionRef::SendablePropertiesInfo info;
512 Local<StringRef> str = StringRef::NewFromUtf8(vm_, "str");
513 info.keys.push_back(str);
514 info.types.push_back(FunctionRef::SendableType::NONE);
515 info.attributes.push_back(PropertyAttribute(str, true, true, true));
516
517 Local<ObjectRef> object = ObjectRef::NewSWithProperties(vm_, info);
518 Local<JSValueRef> value = object->Get(vm_, str);
519 EXPECT_TRUE(str->IsStrictEquals(vm_, value));
520 }
521
HWTEST_F_L0(JSNApiTests,SendableMapRef_GetSize_GetTotalElements_Get_GetKey_GetValue)522 HWTEST_F_L0(JSNApiTests, SendableMapRef_GetSize_GetTotalElements_Get_GetKey_GetValue)
523 {
524 LocalScope scope(vm_);
525 Local<SendableMapRef> map = SendableMapRef::New(vm_);
526 Local<JSValueRef> key = StringRef::NewFromUtf8(vm_, "TestKey");
527 Local<JSValueRef> value = StringRef::NewFromUtf8(vm_, "TestValue");
528 map->Set(vm_, key, value);
529 Local<JSValueRef> res = map->Get(vm_, key);
530 ASSERT_EQ(res->ToString(vm_)->ToString(vm_), value->ToString(vm_)->ToString(vm_));
531 int32_t num = map->GetSize(vm_);
532 int32_t num1 = map->GetTotalElements(vm_);
533 ASSERT_EQ(num, 1);
534 ASSERT_EQ(num1, 1);
535 Local<JSValueRef> res1 = map->GetKey(vm_, 0);
536 ASSERT_EQ(res1->ToString(vm_)->ToString(vm_), key->ToString(vm_)->ToString(vm_));
537 Local<JSValueRef> res2 = map->GetValue(vm_, 0);
538 ASSERT_EQ(res2->ToString(vm_)->ToString(vm_), value->ToString(vm_)->ToString(vm_));
539 }
540
HWTEST_F_L0(JSNApiTests,SendableSetRef_GetSize_GetTotalElements_GetValue)541 HWTEST_F_L0(JSNApiTests, SendableSetRef_GetSize_GetTotalElements_GetValue)
542 {
543 LocalScope scope(vm_);
544 Local<SendableSetRef> set = SendableSetRef::New(vm_);
545 EXPECT_TRUE(set->IsSharedSet(vm_));
546 Local<JSValueRef> value = StringRef::NewFromUtf8(vm_, "TestValue");
547 set->Add(vm_, value);
548 int32_t num = set->GetSize(vm_);
549 int32_t num1 = set->GetTotalElements(vm_);
550 ASSERT_EQ(num, 1);
551 ASSERT_EQ(num1, 1);
552 Local<JSValueRef> res = set->GetValue(vm_, 0);
553 ASSERT_EQ(res->ToString(vm_)->ToString(vm_), value->ToString(vm_)->ToString(vm_));
554 }
555
HWTEST_F_L0(JSNApiTests,SendableArrayRef_New_Len_GetVal_SetPro)556 HWTEST_F_L0(JSNApiTests, SendableArrayRef_New_Len_GetVal_SetPro)
557 {
558 LocalScope scope(vm_);
559 uint32_t length = 4;
560 Local<SendableArrayRef> array = SendableArrayRef::New(vm_, length);
561 EXPECT_TRUE(array->IsSharedArray(vm_));
562 Local<JSValueRef> value = StringRef::NewFromUtf8(vm_, "TestValue");
563 uint32_t arrayLength = array->Length(vm_);
564 ASSERT_EQ(arrayLength, length);
565 Local<JSValueRef> res = array->GetValueAt(vm_, value, length);
566 uint32_t index = 1;
567 bool flag = array->SetProperty(vm_, res, index, value);
568 EXPECT_FALSE(flag);
569 }
570
HWTEST_F_L0(JSNApiTests,WeakSetRef_New_add)571 HWTEST_F_L0(JSNApiTests, WeakSetRef_New_add)
572 {
573 LocalScope scope(vm_);
574 Local<WeakSetRef> object = WeakSetRef::New(vm_);
575 Local<JSValueRef> value = StringRef::NewFromUtf8(vm_, "TestValue");
576 object->Add(vm_, value);
577 ASSERT_EQ(object->GetSize(vm_), 1);
578 }
579
HWTEST_F_L0(JSNApiTests,JSValueRef_IsWeakMap_Set_Has)580 HWTEST_F_L0(JSNApiTests, JSValueRef_IsWeakMap_Set_Has)
581 {
582 LocalScope scope(vm_);
583 Local<WeakMapRef> map = WeakMapRef::New(vm_);
584 EXPECT_TRUE(map->IsWeakMap(vm_));
585 Local<JSValueRef> key = StringRef::NewFromUtf8(vm_, "TestKey");
586 Local<JSValueRef> value = StringRef::NewFromUtf8(vm_, "TestValue");
587 map->Set(vm_, key, value);
588 EXPECT_TRUE(map->Has(vm_, key));
589 }
590
HWTEST_F_L0(JSNApiTests,SetRef_Add)591 HWTEST_F_L0(JSNApiTests, SetRef_Add)
592 {
593 LocalScope scope(vm_);
594 Local<SetRef> set = SetRef::New(vm_);
595 Local<JSValueRef> value = StringRef::NewFromUtf8(vm_, "TestValue");
596 set->Add(vm_, value);
597 ASSERT_EQ(set->GetSize(vm_), 1);
598 }
599
HWTEST_F_L0(JSNApiTests,Promise_GetPromiseResult)600 HWTEST_F_L0(JSNApiTests, Promise_GetPromiseResult)
601 {
602 LocalScope scope(vm_);
603 Local<PromiseCapabilityRef> capability = PromiseCapabilityRef::New(vm_);
604
605 Local<PromiseRef> promise = capability->GetPromise(vm_);
606 promise->GetPromiseResult(vm_);
607 ASSERT_TRUE(promise->IsPromise(vm_));
608 }
609
HWTEST_F_L0(JSNApiTests,Promise_GetPromiseState)610 HWTEST_F_L0(JSNApiTests, Promise_GetPromiseState)
611 {
612 LocalScope scope(vm_);
613 Local<PromiseCapabilityRef> cap = PromiseCapabilityRef::New(vm_);
614
615 Local<PromiseRef> promise = cap->GetPromise(vm_);
616 promise->GetPromiseState(vm_);
617 ASSERT_TRUE(promise->IsPromise(vm_));
618 }
619
HWTEST_F_L0(JSNApiTests,NapiHasOwnProperty)620 HWTEST_F_L0(JSNApiTests, NapiHasOwnProperty)
621 {
622 Local<ObjectRef> object = ObjectRef::New(vm_);
623 JSTaggedValue value(0);
624 JSHandle<JSTaggedValue> handle(thread_, value);
625 Local<JSValueRef> key = JSNApiHelper::ToLocal<JSValueRef>(handle);
626 const char* utf8Key = "TestKeyForOwnProperty";
627 Local<JSValueRef> key2 = StringRef::NewFromUtf8(vm_, utf8Key);
628 Local<JSValueRef> value2 = ObjectRef::New(vm_);
629 object->Set(vm_, key, value2);
630 object->Set(vm_, key2, value2);
631
632 Local<JSValueRef> flag = JSNApi::NapiHasOwnProperty(vm_, reinterpret_cast<uintptr_t>(*object),
633 reinterpret_cast<uintptr_t>(*key));
634 ASSERT_TRUE(flag->BooleaValue(vm_));
635 flag = JSNApi::NapiHasOwnProperty(vm_, reinterpret_cast<uintptr_t>(*object), reinterpret_cast<uintptr_t>(*key2));
636 ASSERT_TRUE(flag->BooleaValue(vm_));
637
638 flag = JSNApi::NapiDeleteProperty(vm_, reinterpret_cast<uintptr_t>(*object), reinterpret_cast<uintptr_t>(*key));
639 ASSERT_TRUE(flag->BooleaValue(vm_));
640 flag = JSNApi::NapiDeleteProperty(vm_, reinterpret_cast<uintptr_t>(*object), reinterpret_cast<uintptr_t>(*key2));
641 ASSERT_TRUE(flag->BooleaValue(vm_));
642
643 flag = JSNApi::NapiHasOwnProperty(vm_, reinterpret_cast<uintptr_t>(*object), reinterpret_cast<uintptr_t>(*key));
644 ASSERT_FALSE(flag->BooleaValue(vm_));
645 flag = JSNApi::NapiHasOwnProperty(vm_, reinterpret_cast<uintptr_t>(*object), reinterpret_cast<uintptr_t>(*key2));
646 ASSERT_FALSE(flag->BooleaValue(vm_));
647 }
648
HWTEST_F_L0(JSNApiTests,DeleteSerializationData)649 HWTEST_F_L0(JSNApiTests, DeleteSerializationData)
650 {
651 LocalScope scope(vm_);
652 void *data = JSNApi::SerializeValue(vm_, StringRef::NewFromUtf8(vm_, "testData"),
653 StringRef::NewFromUtf8(vm_, "testTransfer"), JSValueRef::Undefined(vm_));
654 JSNApi::DeleteSerializationData(data);
655 ASSERT_EQ(reinterpret_cast<ecmascript::SerializeData *>(data), nullptr);
656 }
657
HWTEST_F_L0(JSNApiTests,JSNApi_DeserializeValue_String)658 HWTEST_F_L0(JSNApiTests, JSNApi_DeserializeValue_String)
659 {
660 LocalScope scope(vm_);
661 vm_->SetEnableForceGC(true);
662 void *recoder = JSNApi::SerializeValue(vm_, StringRef::NewFromUtf8(vm_, "testData"), JSValueRef::Undefined(vm_),
663 JSValueRef::Undefined(vm_));
664 void *hint = nullptr;
665 Local<JSValueRef> local = JSNApi::DeserializeValue(vm_, recoder, hint);
666 ASSERT_FALSE(local->IsObject(vm_));
667 }
668
HWTEST_F_L0(JSNApiTests,NewSharedFloat64Array)669 HWTEST_F_L0(JSNApiTests, NewSharedFloat64Array)
670 {
671 LocalScope scope(vm_);
672 Local<SendableArrayBufferRef> buffer = SendableArrayBufferRef::New(vm_, 57);
673 ASSERT_TRUE(buffer->IsSendableArrayBuffer(vm_));
674
675 Local<SharedFloat64ArrayRef> typedArray = SharedFloat64ArrayRef::New(vm_, buffer, 8, 6);
676 ASSERT_TRUE(typedArray->IsJSSharedFloat64Array(vm_));
677 ASSERT_EQ(typedArray->ByteLength(vm_), 48U); // 48 : length of bytes
678 ASSERT_EQ(typedArray->ByteOffset(vm_), 8U); // 8 : offset of byte
679 ASSERT_EQ(typedArray->ArrayLength(vm_), 6U); // 6 : length of array
680 ASSERT_EQ(typedArray->GetArrayBuffer(vm_)->GetBuffer(vm_), buffer->GetBuffer(vm_));
681 }
682
HWTEST_F_L0(JSNApiTests,NewSharedBigInt64Array)683 HWTEST_F_L0(JSNApiTests, NewSharedBigInt64Array)
684 {
685 LocalScope scope(vm_);
686 Local<SendableArrayBufferRef> buffer = SendableArrayBufferRef::New(vm_, 57);
687 ASSERT_TRUE(buffer->IsSendableArrayBuffer(vm_));
688
689 Local<SharedBigInt64ArrayRef> typedArray = SharedBigInt64ArrayRef::New(vm_, buffer, 8, 6);
690 ASSERT_TRUE(typedArray->IsJSSharedBigInt64Array(vm_));
691 ASSERT_EQ(typedArray->ByteLength(vm_), 48U); // 48 : length of bytes
692 ASSERT_EQ(typedArray->ByteOffset(vm_), 8U); // 8 : offset of byte
693 ASSERT_EQ(typedArray->ArrayLength(vm_), 6U); // 6 : length of array
694 ASSERT_EQ(typedArray->GetArrayBuffer(vm_)->GetBuffer(vm_), buffer->GetBuffer(vm_));
695 }
696
HWTEST_F_L0(JSNApiTests,NewSharedBigUint64Array)697 HWTEST_F_L0(JSNApiTests, NewSharedBigUint64Array)
698 {
699 LocalScope scope(vm_);
700 Local<SendableArrayBufferRef> buffer = SendableArrayBufferRef::New(vm_, 57);
701 ASSERT_TRUE(buffer->IsSendableArrayBuffer(vm_));
702
703 Local<SharedBigUint64ArrayRef> typedArray = SharedBigUint64ArrayRef::New(vm_, buffer, 8, 6);
704 ASSERT_TRUE(typedArray->IsJSSharedBigUint64Array(vm_));
705 ASSERT_EQ(typedArray->ByteLength(vm_), 48U); // 48 : length of bytes
706 ASSERT_EQ(typedArray->ByteOffset(vm_), 8U); // 8 : offset of byte
707 ASSERT_EQ(typedArray->ArrayLength(vm_), 6U); // 6 : length of array
708 ASSERT_EQ(typedArray->GetArrayBuffer(vm_)->GetBuffer(vm_), buffer->GetBuffer(vm_));
709 }
710
711 } // namespace panda::test
712