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 20using namespace panda::ecmascript; 21 22namespace panda::test { 23class JSNApiTests : public testing::Test { 24public: 25 static void SetUpTestCase() 26 { 27 GTEST_LOG_(INFO) << "SetUpTestCase"; 28 } 29 30 static void TearDownTestCase() 31 { 32 GTEST_LOG_(INFO) << "TearDownCase"; 33 } 34 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 51 void TearDown() override 52 { 53 thread_->ManagedCodeEnd(); 54 vm_->SetEnableForceGC(false); 55 JSNApi::DestroyJSVM(vm_); 56 } 57 58 template <typename T> 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 81 TaggedType ConvertDouble(double val) 82 { 83 return base::bit_cast<JSTaggedType>(val) + JSTaggedValue::DOUBLE_ENCODE_OFFSET; 84 } 85 86protected: 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 96panda::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 104Local<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 164HWTEST_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 187HWTEST_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 221HWTEST_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 255HWTEST_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 298HWTEST_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 341HWTEST_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 368HWTEST_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 395HWTEST_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 412HWTEST_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 427HWTEST_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 454HWTEST_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 498HWTEST_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 513HWTEST_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 532HWTEST_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