/* * Copyright (c) 2023 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include <cstddef> #include "ecmascript/builtins/builtins.h" #include "ecmascript/builtins/builtins_function.h" #include "ecmascript/builtins/builtins_object.h" #include "ecmascript/compiler/aot_file/an_file_data_manager.h" #include "ecmascript/compiler/aot_file/aot_file_manager.h" #include "ecmascript/compiler/circuit_builder_helper.h" #include "ecmascript/deoptimizer/deoptimizer.h" #include "ecmascript/ecma_global_storage.h" #include "ecmascript/ecma_vm.h" #include "ecmascript/global_env.h" #include "ecmascript/js_api/js_api_tree_map.h" #include "ecmascript/js_api/js_api_tree_set.h" #include "ecmascript/js_api/js_api_vector.h" #include "ecmascript/js_array.h" #include "ecmascript/js_bigint.h" #include "ecmascript/js_date_time_format.h" #include "ecmascript/js_generator_object.h" #include "ecmascript/js_map.h" #include "ecmascript/js_map_iterator.h" #include "ecmascript/js_primitive_ref.h" #include "ecmascript/js_regexp.h" #include "ecmascript/js_runtime_options.h" #include "ecmascript/js_set.h" #include "ecmascript/js_set_iterator.h" #include "ecmascript/js_tagged_value.h" #include "ecmascript/js_thread.h" #include "ecmascript/js_weak_container.h" #include "ecmascript/linked_hash_table.h" #include "ecmascript/mem/mem_map_allocator.h" #include "ecmascript/module/js_module_manager.h" #include "ecmascript/module/js_module_source_text.h" #include "ecmascript/napi/include/jsnapi.h" #include "ecmascript/napi/include/jsnapi_internals.h" #include "ecmascript/napi/jsnapi_helper.h" #include "ecmascript/object_factory.h" #include "ecmascript/pgo_profiler/pgo_profiler.h" #include "ecmascript/pgo_profiler/pgo_profiler_decoder.h" #include "ecmascript/pgo_profiler/pgo_profiler_encoder.h" #include "ecmascript/pgo_profiler/pgo_profiler_manager.h" #include "ecmascript/tagged_array.h" #include "ecmascript/tests/test_helper.h" #include "ecmascript/tagged_tree.h" #include "ecmascript/weak_vector.h" #include "gtest/gtest.h" using namespace panda; using namespace panda::ecmascript; using namespace panda::ecmascript::kungfu; namespace panda::test { using BuiltinsFunction = ecmascript::builtins::BuiltinsFunction; using PGOProfilerManager = panda::ecmascript::pgo::PGOProfilerManager; using FunctionForRef = Local<JSValueRef> (*)(JsiRuntimeCallInfo *); class JSNApiTests : public testing::Test { public: static void SetUpTestCase() { GTEST_LOG_(INFO) << "SetUpTestCase"; } static void TearDownTestCase() { GTEST_LOG_(INFO) << "TearDownCase"; } void SetUp() override { RuntimeOption option; option.SetLogLevel(RuntimeOption::LOG_LEVEL::ERROR); vm_ = JSNApi::CreateJSVM(option); ASSERT_TRUE(vm_ != nullptr) << "Cannot create Runtime"; thread_ = vm_->GetJSThread(); vm_->SetEnableForceGC(true); } void TearDown() override { vm_->SetEnableForceGC(false); JSNApi::DestroyJSVM(vm_); } template <typename T> void TestNumberRef(T val, TaggedType expected) { LocalScope scope(vm_); Local<NumberRef> obj = NumberRef::New(vm_, val); ASSERT_TRUE(obj->IsNumber()); JSTaggedType res = JSNApiHelper::ToJSTaggedValue(*obj).GetRawData(); ASSERT_EQ(res, expected); if constexpr (std::is_floating_point_v<T>) { if (std::isnan(val)) { ASSERT_TRUE(std::isnan(obj->Value())); } else { ASSERT_EQ(obj->Value(), val); } } else if constexpr (sizeof(T) >= sizeof(int32_t)) { ASSERT_EQ(obj->IntegerValue(vm_), val); } else if constexpr (std::is_signed_v<T>) { ASSERT_EQ(obj->Int32Value(vm_), val); } else { ASSERT_EQ(obj->Uint32Value(vm_), val); } } TaggedType ConvertDouble(double val) { return base::bit_cast<JSTaggedType>(val) + JSTaggedValue::DOUBLE_ENCODE_OFFSET; } protected: JSThread *thread_ = nullptr; EcmaVM *vm_ = nullptr; }; Local<JSValueRef> FunctionCallback(JsiRuntimeCallInfo *info) { EscapeLocalScope scope(info->GetVM()); return scope.Escape(ArrayRef::New(info->GetVM(), info->GetArgsNumber())); } void WeakRefCallback(EcmaVM *vm) { LocalScope scope(vm); Local<ObjectRef> object = ObjectRef::New(vm); Global<ObjectRef> globalObject(vm, object); globalObject.SetWeak(); Local<ObjectRef> object1 = ObjectRef::New(vm); Global<ObjectRef> globalObject1(vm, object1); globalObject1.SetWeak(); vm->CollectGarbage(TriggerGCType::YOUNG_GC); vm->CollectGarbage(TriggerGCType::OLD_GC); globalObject.FreeGlobalHandleAddr(); } void ThreadCheck(const EcmaVM *vm) { EXPECT_TRUE(vm->GetJSThread()->GetThreadId() != JSThread::GetCurrentThreadId()); } void CheckReject(JsiRuntimeCallInfo *info) { ASSERT_EQ(info->GetArgsNumber(), 1U); Local<JSValueRef> reason = info->GetCallArgRef(0); ASSERT_TRUE(reason->IsString()); ASSERT_EQ(Local<StringRef>(reason)->ToString(), "Reject"); } Local<JSValueRef> RejectCallback(JsiRuntimeCallInfo *info) { LocalScope scope(info->GetVM()); CheckReject(info); return JSValueRef::Undefined(info->GetVM()); } /** * @tc.number: ffi_interface_api_105 * @tc.name: JSValueRef_IsGeneratorObject * @tc.desc: Determine if it is a Generator generator object * @tc.type: FUNC * @tc.require: parameter */ HWTEST_F_L0(JSNApiTests, JSValueRef_IsGeneratorObject) { LocalScope scope(vm_); ObjectFactory *factory = vm_->GetFactory(); auto env = vm_->GetGlobalEnv(); JSHandle<JSTaggedValue> genFunc = env->GetGeneratorFunctionFunction(); JSHandle<JSGeneratorObject> genObjHandleVal = factory->NewJSGeneratorObject(genFunc); JSHandle<JSHClass> hclass = JSHandle<JSHClass>::Cast(env->GetGeneratorFunctionClass()); JSHandle<JSFunction> generatorFunc = JSHandle<JSFunction>::Cast(factory->NewJSObject(hclass)); JSFunction::InitializeJSFunction(thread_, generatorFunc, FunctionKind::GENERATOR_FUNCTION); JSHandle<GeneratorContext> generatorContext = factory->NewGeneratorContext(); generatorContext->SetMethod(thread_, generatorFunc.GetTaggedValue()); JSHandle<JSTaggedValue> generatorContextVal = JSHandle<JSTaggedValue>::Cast(generatorContext); genObjHandleVal->SetGeneratorContext(thread_, generatorContextVal.GetTaggedValue()); JSHandle<JSTaggedValue> genObjTagHandleVal = JSHandle<JSTaggedValue>::Cast(genObjHandleVal); Local<JSValueRef> genObjectRef = JSNApiHelper::ToLocal<GeneratorObjectRef>(genObjTagHandleVal); ASSERT_TRUE(genObjectRef->IsGeneratorObject()); } static JSFunction *JSObjectTestCreate(JSThread *thread) { EcmaVM *ecmaVM = thread->GetEcmaVM(); JSHandle<GlobalEnv> globalEnv = ecmaVM->GetGlobalEnv(); return globalEnv->GetObjectFunction().GetObject<JSFunction>(); } /** * @tc.number: ffi_interface_api_106 * @tc.name: JSValueRef_IsProxy * @tc.desc: Determine if it is the type of proxy * @tc.type: FUNC * @tc.require: parameter */ HWTEST_F_L0(JSNApiTests, JSValueRef_IsProxy) { LocalScope scope(vm_); JSHandle<JSTaggedValue> hclass(thread_, JSObjectTestCreate(thread_)); JSHandle<JSTaggedValue> targetHandle( thread_->GetEcmaVM()->GetFactory()->NewJSObjectByConstructor(JSHandle<JSFunction>::Cast(hclass), hclass)); JSHandle<JSTaggedValue> key(thread_->GetEcmaVM()->GetFactory()->NewFromASCII("x")); JSHandle<JSTaggedValue> value(thread_, JSTaggedValue(1)); JSObject::SetProperty(thread_, targetHandle, key, value); EXPECT_EQ(JSObject::GetProperty(thread_, targetHandle, key).GetValue()->GetInt(), 1); JSHandle<JSTaggedValue> handlerHandle( thread_->GetEcmaVM()->GetFactory()->NewJSObjectByConstructor(JSHandle<JSFunction>::Cast(hclass), hclass)); EXPECT_TRUE(handlerHandle->IsECMAObject()); JSHandle<JSProxy> proxyHandle = JSProxy::ProxyCreate(thread_, targetHandle, handlerHandle); EXPECT_TRUE(*proxyHandle != nullptr); EXPECT_EQ(JSProxy::GetProperty(thread_, proxyHandle, key).GetValue()->GetInt(), 1); PropertyDescriptor desc(thread_); JSProxy::GetOwnProperty(thread_, proxyHandle, key, desc); EXPECT_EQ(desc.GetValue()->GetInt(), 1); Local<JSValueRef> proxy = JSNApiHelper::ToLocal<JSProxy>(JSHandle<JSTaggedValue>(proxyHandle)); ASSERT_TRUE(proxy->IsProxy()); } /** * @tc.number: ffi_interface_api_107 * @tc.name: BufferRef_New_ByteLength * @tc.desc: * New:Create a buffer and specify the length size * ByteLength:Returns the length of the buffer * @tc.type: FUNC * @tc.require: parameter */ HWTEST_F_L0(JSNApiTests, BufferRef_New_ByteLength) { LocalScope scope(vm_); int32_t length = 10; Local<BufferRef> buffer = BufferRef::New(vm_, length); ASSERT_TRUE(buffer->IsBuffer()); EXPECT_EQ(buffer->ByteLength(vm_), length); } /** * @tc.number: ffi_interface_api_108 * @tc.name: BufferRef_New_ByteLength_GetBuffer * @tc.desc: * New:Create a buffer and specify the length size * ByteLength:Returns the length of the buffer * GetBuffer:Return buffer pointer * @tc.type: FUNC * @tc.require: parameter */ HWTEST_F_L0(JSNApiTests, BufferRef_New_ByteLength_GetBuffer) { LocalScope scope(vm_); int32_t length = 10; Local<BufferRef> buffer = BufferRef::New(vm_, length); ASSERT_TRUE(buffer->IsBuffer()); EXPECT_EQ(buffer->ByteLength(vm_), 10U); ASSERT_NE(buffer->GetBuffer(), nullptr); } /** * @tc.number: ffi_interface_api_109 * @tc.name: BufferRef_New01_ByteLength_GetBuffer_BufferToStringCallback * @tc.desc: * BufferToStringCallback:Implement callback when calling ToString (vm) mode in buffer * @tc.type: FUNC * @tc.require: parameter */ HWTEST_F_L0(JSNApiTests, BufferRef_New01_ByteLength_GetBuffer_BufferToStringCallback) { LocalScope scope(vm_); static bool isFree = false; struct Data { int32_t length; }; const int32_t length = 15; Deleter deleter = [](void *buffer, void *data) -> void { delete[] reinterpret_cast<uint8_t *>(buffer); Data *currentData = reinterpret_cast<Data *>(data); delete currentData; isFree = true; }; isFree = false; uint8_t *buffer = new uint8_t[length](); Data *data = new Data(); data->length = length; Local<BufferRef> bufferRef = BufferRef::New(vm_, buffer, length, deleter, data); ASSERT_TRUE(bufferRef->IsBuffer()); ASSERT_TRUE(bufferRef->IsBuffer()); EXPECT_EQ(bufferRef->ByteLength(vm_), 15U); Local<StringRef> bufferStr = bufferRef->ToString(vm_); ASSERT_TRUE(bufferStr->IsString()); } /** * @tc.number: ffi_interface_api_110 * @tc.name: LocalScope_LocalScope * @tc.desc: Build Escape LocalScope sub Vm scope * @tc.type: FUNC * @tc.require: parameter */ HWTEST_F_L0(JSNApiTests, LocalScope_LocalScope) { EscapeLocalScope scope(vm_); LocalScope *perScope = nullptr; perScope = &scope; ASSERT_TRUE(perScope != nullptr); } /** * @tc.number: ffi_interface_api_111 * @tc.name: JSNApi_CreateJSContext_SwitchCurrentContext_DestroyJSContext * @tc.desc: * CreateJSContext:Create Context Object Pointer * SwitchCurrentContext:Record Update Context Object * DestroyJSContext:Delete Context Object * @tc.type: FUNC * @tc.require: parameter */ HWTEST_F_L0(JSNApiTests, JSNApi_SwitchCurrentContext_DestroyJSContext) { LocalScope scope(vm_); EXPECT_EQ(vm_->GetJSThread()->GetEcmaContexts().size(), 1); EcmaContext *context = JSNApi::CreateJSContext(vm_); GTEST_LOG_(WARNING) << "context test =" << context; EXPECT_EQ(vm_->GetJSThread()->GetEcmaContexts().size(), 2); EcmaContext *context1 = JSNApi::CreateJSContext(vm_); EXPECT_EQ(vm_->GetJSThread()->GetEcmaContexts().size(), 3); JSNApi::SwitchCurrentContext(vm_, context1); EXPECT_EQ(vm_->GetJSThread()->GetEcmaContexts().size(), 3); JSNApi::DestroyJSContext(vm_, context1); EXPECT_EQ(vm_->GetJSThread()->GetEcmaContexts().size(), 2); } /** * @tc.number: ffi_interface_api_112 * @tc.name: JSNApi_CreateJSVM_DestroyJSVM * @tc.desc: Create/delete JSVM * @tc.type: FUNC * @tc.require: parameter */ HWTEST_F_L0(JSNApiTests, JSNApi_CreateJSVM_DestroyJSVM) { LocalScope scope(vm_); EcmaVM *vm1_ = nullptr; RuntimeOption option; option.SetLogLevel(RuntimeOption::LOG_LEVEL::ERROR); vm1_ = JSNApi::CreateJSVM(option); ASSERT_TRUE(vm1_ != nullptr) << "Cannot create Runtime"; vm1_->SetEnableForceGC(true); vm1_->SetEnableForceGC(false); JSNApi::DestroyJSVM(vm1_); } /** * @tc.number: ffi_interface_api_114 * @tc.name: JSNApi_GetUncaughtException * @tc.desc: Get uncaught exceptions * @tc.type: FUNC * @tc.require: parameter */ HWTEST_F_L0(JSNApiTests, JSNApi_GetUncaughtException) { LocalScope scope(vm_); Local<ObjectRef> excep = JSNApi::GetUncaughtException(vm_); ASSERT_TRUE(excep.IsNull()) << "CreateInstance occur Exception"; } Local<JSValueRef> FuncRefNewCallbackForTest(JsiRuntimeCallInfo *info) { GTEST_LOG_(INFO) << "runing FuncRefNewCallbackForTest"; EscapeLocalScope scope(info->GetVM()); return scope.Escape(ArrayRef::New(info->GetVM(), info->GetArgsNumber())); } /** * @tc.number: ffi_interface_api_115 * @tc.name: ObjectRef_SetAccessorProperty * @tc.desc: * SetAccessorProperty:Set AccessorPro Properties * GetVM:Obtain environment information for runtime calls * LocalScope:Build Vm Scope * @tc.type: FUNC * @tc.require: parameter */ HWTEST_F_L0(JSNApiTests, ObjectRef_SetAccessorProperty_JsiRuntimeCallInfo_GetVM) { LocalScope scope(vm_); Local<JSValueRef> key = StringRef::NewFromUtf8(vm_, "TestKey"); FunctionForRef nativeFunc = FuncRefNewCallbackForTest; Local<FunctionRef> getter = FunctionRef::New(vm_, nativeFunc); Local<FunctionRef> setter = FunctionRef::New(vm_, nativeFunc); Local<ObjectRef> object = ObjectRef::New(vm_); ASSERT_TRUE(object->SetAccessorProperty(vm_, key, getter, setter)); } /* * @tc.number: ffi_interface_api_116 * @tc.name: JSNApi_IsBoolean * @tc.desc: Judge whether obj is a boolean type * @tc.type: FUNC * @tc.require: parameter */ HWTEST_F_L0(JSNApiTests, IsBoolean) { LocalScope scope(vm_); char16_t utf16[] = u"This is a char16 array"; int size = sizeof(utf16); Local<StringRef> obj = StringRef::NewFromUtf16(vm_, utf16, size); ASSERT_FALSE(obj->IsBoolean()); } /* * @tc.number: ffi_interface_api_117 * @tc.name: JSNApi_IsNULL * @tc.desc: Judge whether obj is a null type * @tc.type: FUNC * @tc.require: parameter */ HWTEST_F_L0(JSNApiTests, IsNULL) { LocalScope scope(vm_); char16_t utf16[] = u"This is a char16 array"; int size = sizeof(utf16); Local<StringRef> obj = StringRef::NewFromUtf16(vm_, utf16, size); ASSERT_FALSE(obj->IsNull()); } /* * @tc.number: ffi_interface_api_118 * @tc.name: JSNApi_GetTime * @tc.desc: This function is to catch time * @tc.type: FUNC * @tc.require: parameter */ HWTEST_F_L0(JSNApiTests, GetTime) { LocalScope scope(vm_); const double time = 14.29; Local<DateRef> date = DateRef::New(vm_, time); ASSERT_EQ(date->GetTime(), time); } /* * @tc.number: ffi_interface_api_119 * @tc.name: JSNApi_IsDetach * @tc.desc: Judge whether arraybuffer is detached * @tc.type: FUNC * @tc.require: parameter */ HWTEST_F_L0(JSNApiTests, IsDetach) { LocalScope scope(vm_); const int32_t length = 33; Local<ArrayBufferRef> arraybuffer = ArrayBufferRef::New(vm_, length); ASSERT_FALSE(arraybuffer->IsDetach()); } /* * @tc.number: ffi_interface_api_120 * @tc.name: JSNApi_Detach * @tc.desc: This function is to detach arraybuffer * @tc.type: FUNC * @tc.require: parameter */ HWTEST_F_L0(JSNApiTests, Detach) { LocalScope scope(vm_); const int32_t length = 33; Local<ArrayBufferRef> arraybuffer = ArrayBufferRef::New(vm_, length); arraybuffer->Detach(vm_); } /* * @tc.number: ffi_interface_api_121 * @tc.name: JSNApi_New1 * @tc.desc: create a obj that is a arraybuffer type * @tc.type: FUNC * @tc.require: parameter */ HWTEST_F_L0(JSNApiTests, New1) { LocalScope scope(vm_); const int32_t length = 33; Local<ArrayBufferRef> arrayBuffer = ArrayBufferRef::New(vm_, length); ASSERT_TRUE(arrayBuffer->IsArrayBuffer()); ASSERT_EQ(arrayBuffer->ByteLength(vm_), length); ASSERT_NE(arrayBuffer->GetBuffer(), nullptr); } /* * @tc.number: ffi_interface_api_122 * @tc.name: JSNApi_New1 * @tc.desc: create a obj that is a arraybuffer type * @tc.type: FUNC * @tc.require: parameter */ HWTEST_F_L0(JSNApiTests, New2) { static bool isFree = false; struct Data { int32_t length; }; const int32_t length = 15; Data *data = new Data(); data->length = length; Deleter deleter = [](void *buffer, void *data) -> void { delete[] reinterpret_cast<uint8_t *>(buffer); Data *currentData = reinterpret_cast<Data *>(data); ASSERT_EQ(currentData->length, 15); // 5 : size of arguments delete currentData; isFree = true; }; { LocalScope scope(vm_); uint8_t *buffer = new uint8_t[length](); Local<ArrayBufferRef> arrayBuffer = ArrayBufferRef::New(vm_, buffer, length, deleter, data); ASSERT_TRUE(arrayBuffer->IsArrayBuffer()); ASSERT_EQ(arrayBuffer->ByteLength(vm_), length); ASSERT_EQ(arrayBuffer->GetBuffer(), buffer); } } /* * @tc.number: ffi_interface_api_123 * @tc.name: JSNApi_Bytelength * @tc.desc: capture bytelength of arraybuffer * @tc.type: FUNC * @tc.require: parameter */ HWTEST_F_L0(JSNApiTests, Bytelength) { LocalScope scope(vm_); const int32_t length = 33; Local<ArrayBufferRef> arrayBuffer = ArrayBufferRef::New(vm_, length); ASSERT_EQ(arrayBuffer->ByteLength(vm_), length); } /* * @tc.number: ffi_interface_api_124 * @tc.name: JSNApi_GetBuffer * @tc.desc: capture buffer of arraybuffer * @tc.type: FUNC * @tc.require: parameter */ HWTEST_F_L0(JSNApiTests, GetBuffer) { LocalScope scope(vm_); const int32_t length = 33; Local<ArrayBufferRef> arraybuffer = ArrayBufferRef::New(vm_, length); ASSERT_NE(arraybuffer->GetBuffer(), nullptr); } /* * @tc.number: ffi_interface_api_125 * @tc.name: JSNApi_Is32Arraytest * @tc.desc: judge whether obj is a int32array type, * judge whether obj is a uint32array type, * judge whether obj is a float32array type, * judge whether obj is a float64array type, * @tc.type: FUNC * @tc.require: parameter */ HWTEST_F_L0(JSNApiTests, Is32Arraytest) { LocalScope scope(vm_); char16_t utf16[] = u"This is a char16 array"; int size = sizeof(utf16); Local<StringRef> obj = StringRef::NewFromUtf16(vm_, utf16, size); ASSERT_FALSE(obj->IsInt32Array()); ASSERT_FALSE(obj->IsUint32Array()); ASSERT_FALSE(obj->IsFloat32Array()); ASSERT_FALSE(obj->IsFloat64Array()); } /* * @tc.number: ffi_interface_api_126 * @tc.name: JSNApi_SynchronizVMInfo * @tc.desc: capture synchronous info of vm * @tc.type: FUNC * @tc.require: parameter */ HWTEST_F_L0(JSNApiTests, SynchronizVMInfo) { LocalScope scope(vm_); JSRuntimeOptions option; EcmaVM *hostVM = JSNApi::CreateEcmaVM(option); LocalScope scope2(hostVM); JSNApi::SynchronizVMInfo(vm_, hostVM); } /* * @tc.number: ffi_interface_api_127 * @tc.name: JSNApi_IsProfiling * @tc.desc: judge whether vm is profiling * @tc.type: FUNC * @tc.require: parameter */ HWTEST_F_L0(JSNApiTests, IsProfiling) { LocalScope scope(vm_); ASSERT_FALSE(JSNApi::IsProfiling(vm_)); } /* * @tc.number: ffi_interface_api_128 * @tc.name: JSNApi_SetProfilerState * @tc.desc: This function is to set state of profiler * @tc.type: FUNC * @tc.require: parameter */ HWTEST_F_L0(JSNApiTests, SetProfilerState) { bool value = true; bool value2 = false; LocalScope scope(vm_); JSNApi::SetProfilerState(vm_, value); JSNApi::SetProfilerState(vm_, value2); } /* * @tc.number: ffi_interface_api_129 * @tc.name: JSNApi_SetLoop * @tc.desc: This function is to set loop * @tc.type: FUNC * @tc.require: parameter */ HWTEST_F_L0(JSNApiTests, SetLoop) { LocalScope scope(vm_); void *data = reinterpret_cast<void *>(BuiltinsFunction::FunctionPrototypeInvokeSelf); JSNApi::SetLoop(vm_, data); } /* * @tc.number: ffi_interface_api_130 * @tc.name: JSNApi_SetHostPromiseRejectionTracker * @tc.desc: This function is to set host promise rejection about tracker * @tc.type: FUNC * @tc.require: parameter */ HWTEST_F_L0(JSNApiTests, SetHostPromiseRejectionTracker) { LocalScope scope(vm_); void *data = reinterpret_cast<void *>(BuiltinsFunction::FunctionPrototypeInvokeSelf); void *cb = reinterpret_cast<void *>(BuiltinsFunction::FunctionPrototypeInvokeSelf); JSNApi::SetHostPromiseRejectionTracker(vm_, cb, data); } /* * @tc.number: ffi_interface_api_131 * @tc.name: JSNApi_SetHostResolveBufferTracker * @tc.desc: This function is to set host resolve buffer about tracker * @tc.type: FUNC * @tc.require: parameter */ HWTEST_F_L0(JSNApiTests, SetHostResolveBufferTracker) { LocalScope scope(vm_); JSNApi::SetHostResolveBufferTracker(vm_, [&](std::string, uint8_t **, size_t *) -> bool { return true; }); } /* * @tc.number: ffi_interface_api_132 * @tc.name: JSNApi_SetUnloadNativeModuleCallback * @tc.desc: This function is to set unload native module about callback * @tc.type: FUNC * @tc.require: parameter */ HWTEST_F_L0(JSNApiTests, SetUnloadNativeModuleCallback) { LocalScope scope(vm_); JSNApi::SetUnloadNativeModuleCallback(vm_, [&](const std::string &) -> bool { return true; }); } /* * @tc.number: ffi_interface_api_133 * @tc.name: JSNApi_SetNativePtrGetter * @tc.desc: This function is to set a native pointer about getter * @tc.type: FUNC * @tc.require: parameter */ HWTEST_F_L0(JSNApiTests, SetNativePtrGetter) { LocalScope scope(vm_); void *cb = reinterpret_cast<void *>(BuiltinsFunction::FunctionPrototypeInvokeSelf); JSNApi::SetNativePtrGetter(vm_, cb); } /* * @tc.number: ffi_interface_api_134 * @tc.name: JSNApi_PreFork * @tc.desc: This function is to set prefork * @tc.type: FUNC * @tc.require: parameter */ HWTEST_F_L0(JSNApiTests, PreFork) { LocalScope scope(vm_); JSNApi::PreFork(vm_); } /* * @tc.number: ffi_interface_api_135 * @tc.name: JSNApi_PostFork * @tc.desc: This function is to set postfork * @tc.type: FUNC * @tc.require: parameter */ HWTEST_F_L0(JSNApiTests, PostFork) { RuntimeOption option; LocalScope scope(vm_); JSNApi::PostFork(vm_, option); } /* * @tc.number: ffi_interface_api_136 * @tc.name: JSNApi_NewFromUtf8 * @tc.desc: create a newfromutf8 object * @tc.type: FUNC * @tc.require: parameter */ HWTEST_F_L0(JSNApiTests, NewFromUtf8) { LocalScope scope(vm_); char utf8[] = "hello world!"; int length = strlen(utf8); Local<StringRef> result = StringRef::NewFromUtf8(vm_, utf8, length); ASSERT_EQ(result->Utf8Length(vm_), length + 1); } /* * @tc.number: ffi_interface_api_137 * @tc.name: JSNApi_NewFromUtf16 * @tc.desc: create a newfromutf16 object * @tc.type: FUNC * @tc.require: parameter */ HWTEST_F_L0(JSNApiTests, NewFromUtf16) { LocalScope scope(vm_); char16_t utf16[] = u"This is a char16 array"; int length = sizeof(utf16); Local<StringRef> result = StringRef::NewFromUtf16(vm_, utf16, length); ASSERT_EQ(result->Length(), length); } /* * @tc.number: ffi_interface_api_138 * @tc.name: JSNApi_GetNapiWrapperString * @tc.desc: This function is to get a napiwrapper string * @tc.type: FUNC * @tc.require: parameter */ HWTEST_F_L0(JSNApiTests, GetNapiWrapperString) { LocalScope scope(vm_); Local<StringRef> result = StringRef::GetNapiWrapperString(vm_); ASSERT_TRUE(result->IsString()); } /* * @tc.number: ffi_interface_api_139 * @tc.name: JSNApi_JSExecutionScope * @tc.desc: This function is to construct a object of jsexecutionscope * @tc.type: FUNC * @tc.require: parameter */ HWTEST_F_L0(JSNApiTests, JSExecutionScope) { LocalScope scope(vm_); JSExecutionScope jsexecutionScope(vm_); } /* * @tc.number: ffi_interface_api_140 * @tc.name: WeakMapRef_GetSize_GetTotalElements_GetKey_GetValue * @tc.desc: This function is to set a weakmap and capture it's size , * key, value and total elements * @tc.type: FUNC * @tc.require: parameter */ HWTEST_F_L0(JSNApiTests, WeakMapRef_GetSize_GetTotalElements_GetKey_GetValue) { LocalScope scope(vm_); JSThread *thread = vm_->GetJSThread(); ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv(); JSHandle<JSTaggedValue> constructor = env->GetBuiltinsWeakMapFunction(); JSHandle<JSWeakMap> weakMap = JSHandle<JSWeakMap>::Cast(factory->NewJSObjectByConstructor(JSHandle<JSFunction>(constructor), constructor)); JSHandle<LinkedHashMap> hashMap = LinkedHashMap::Create(thread); weakMap->SetLinkedMap(thread, hashMap); JSHandle<JSTaggedValue> weakMapTag = JSHandle<JSTaggedValue>::Cast(weakMap); Local<WeakMapRef> map = JSNApiHelper::ToLocal<WeakMapRef>(weakMapTag); EXPECT_TRUE(map->IsWeakMap()); JSHandle<JSTaggedValue> value(factory->NewFromASCII("value")); JSHandle<JSTaggedValue> key(factory->NewFromASCII("key")); JSWeakMap::Set(thread, weakMap, key, value); int32_t num = map->GetSize(); int32_t num1 = map->GetTotalElements(); ASSERT_EQ(num, 1); ASSERT_EQ(num1, 1); Local<JSValueRef> res1 = map->GetKey(vm_, 0); ASSERT_EQ(res1->ToString(vm_)->ToString(), "key"); Local<JSValueRef> res2 = map->GetValue(vm_, 0); ASSERT_EQ(res2->ToString(vm_)->ToString(), "value"); } /* * @tc.number: ffi_interface_api_141 * @tc.name: JSNApi_ IsAGJA * @tc.desc: This function is to judge whether object is a argumentsobject or * is a generatorfunction or is a asyncfunction * @tc.type: FUNC * @tc.require: parameter */ HWTEST_F_L0(JSNApiTests, IsAGJA) { LocalScope scope(vm_); char16_t utf16[] = u"This is a char16 array"; int size = sizeof(utf16); Local<StringRef> obj = StringRef::NewFromUtf16(vm_, utf16, size); ASSERT_FALSE(obj->IsArgumentsObject()); ASSERT_FALSE(obj->IsGeneratorFunction()); ASSERT_FALSE(obj->IsAsyncFunction()); } /** * @tc.number: ffi_interface_api_143 * @tc.name: Int32Array * @tc.desc: Catch exceptions correctly * @tc.type: FUNC * @tc.require: parameter */ HWTEST_F_L0(JSNApiTests, HasCaught) { LocalScope scope(vm_); Local<StringRef> message = StringRef::NewFromUtf8(vm_, "ErrorTest"); Local<JSValueRef> error = Exception::Error(vm_, message); ASSERT_TRUE(error->IsError()); JSNApi::ThrowException(vm_, error); TryCatch tryCatch(vm_); ASSERT_TRUE(tryCatch.HasCaught()); vm_->GetJSThread()->ClearException(); ASSERT_FALSE(tryCatch.HasCaught()); } /** * @tc.number: ffi_interface_api_144 * @tc.name: Int32Array * @tc.desc: Rethrow the exception * @tc.type: FUNC * @tc.require: parameter */ HWTEST_F_L0(JSNApiTests, Rethrow) { LocalScope scope(vm_); TryCatch tryCatch(vm_); tryCatch.Rethrow(); ASSERT_TRUE(tryCatch.getrethrow_()); } /** * @tc.number: ffi_interface_api_145 * @tc.name: Int32Array * @tc.desc: Clear caught exceptions * @tc.type: FUNC * @tc.require: parameter */ HWTEST_F_L0(JSNApiTests, GetAndClearException) { LocalScope scope(vm_); Local<StringRef> message = StringRef::NewFromUtf8(vm_, "ErrorTest"); Local<JSValueRef> error = Exception::Error(vm_, message); ASSERT_TRUE(error->IsError()); JSNApi::ThrowException(vm_, error); ASSERT_TRUE(vm_->GetJSThread()->HasPendingException()); TryCatch tryCatch(vm_); tryCatch.GetAndClearException(); EXPECT_FALSE(vm_->GetJSThread()->HasPendingException()); } /** * @tc.number: ffi_interface_api_146 * @tc.name: Int32Array * @tc.desc: trycatch class construction * @tc.type: FUNC * @tc.require: parameter */ HWTEST_F_L0(JSNApiTests, TryCatch) { LocalScope scope(vm_); TryCatch tryCatch(vm_); EXPECT_EQ(tryCatch.getrethrow_(), false); EXPECT_FALSE(tryCatch.HasCaught()); tryCatch.Rethrow(); EXPECT_EQ(tryCatch.getrethrow_(), true); } HWTEST_F_L0(JSNApiTests, NewObjectWithProperties) { LocalScope scope(vm_); Local<JSValueRef> keys[1100]; Local<JSValueRef> values[1100]; PropertyAttribute attributes[1100]; for (int i = 0; i < 1100; i += (i < 80 ? (i < 10 ? 1 : 80) : 1000)) { for (int j = 0; j <= i; ++j) { std::string strKey("TestKey" + std::to_string(i) + "_" + std::to_string(j)); std::string strVal("TestValue" + std::to_string(i) + "_" + std::to_string(j)); keys[j] = StringRef::NewFromUtf8(vm_, strKey.c_str()); values[j] = StringRef::NewFromUtf8(vm_, strVal.c_str()); attributes[j] = PropertyAttribute(values[j], true, true, true); } Local<ObjectRef> object = ObjectRef::NewWithProperties(vm_, i + 1, keys, attributes); for (int j = 0; j <= i; ++j) { Local<JSValueRef> value1 = object->Get(vm_, keys[j]); EXPECT_TRUE(values[j]->IsStrictEquals(vm_, value1)); } JSHandle<JSObject> obj(JSNApiHelper::ToJSHandle(object)); uint32_t propCount = obj->GetJSHClass()->NumberOfProps(); if (i + 1 > PropertyAttributes::MAX_FAST_PROPS_CAPACITY) { EXPECT_TRUE(propCount == 0); EXPECT_TRUE(obj->GetJSHClass()->IsDictionaryMode()); JSHandle<NameDictionary> dict(thread_, obj->GetProperties()); EXPECT_TRUE(dict->EntriesCount() == i + 1); } else { EXPECT_TRUE(propCount == i + 1); int32_t in_idx = obj->GetJSHClass()->GetNextInlinedPropsIndex(); int32_t nonin_idx = obj->GetJSHClass()->GetNextNonInlinedPropsIndex(); if (i + 1 < JSHClass::DEFAULT_CAPACITY_OF_IN_OBJECTS) { EXPECT_TRUE(in_idx == i + 1); EXPECT_TRUE(nonin_idx == -1); } else { EXPECT_TRUE(in_idx == -1); EXPECT_TRUE(nonin_idx == 0); } } } } HWTEST_F_L0(JSNApiTests, NewObjectWithPropertieNonPureStringKey) { LocalScope scope(vm_); Local<JSValueRef> keys[] = { StringRef::NewFromUtf8(vm_, "1"), }; Local<JSValueRef> values[] = { StringRef::NewFromUtf8(vm_, "value1"), }; PropertyAttribute attributes[] = { PropertyAttribute(values[0], true, true, true), }; Local<ObjectRef> object = ObjectRef::NewWithProperties(vm_, 1, keys, attributes); JSHandle<JSTaggedValue> obj = JSNApiHelper::ToJSHandle(object); EXPECT_TRUE(obj.GetTaggedValue() == JSTaggedValue::Undefined()); thread_->ClearException(); } HWTEST_F_L0(JSNApiTests, NewObjectWithPropertiesDuplicate) { LocalScope scope(vm_); Local<JSValueRef> keys[] = { StringRef::NewFromUtf8(vm_, "duplicateKey"), StringRef::NewFromUtf8(vm_, "simpleKey"), StringRef::NewFromUtf8(vm_, "duplicateKey"), }; Local<JSValueRef> values[] = { StringRef::NewFromUtf8(vm_, "value1"), StringRef::NewFromUtf8(vm_, "value2"), StringRef::NewFromUtf8(vm_, "value3"), }; PropertyAttribute attributes[] = { PropertyAttribute(values[0], true, true, true), PropertyAttribute(values[1], true, true, true), PropertyAttribute(values[2], true, true, true), }; Local<ObjectRef> object = ObjectRef::NewWithProperties(vm_, 3, keys, attributes); JSHandle<JSTaggedValue> obj = JSNApiHelper::ToJSHandle(object); EXPECT_TRUE(obj.GetTaggedValue() == JSTaggedValue::Undefined()); thread_->ClearException(); } HWTEST_F_L0(JSNApiTests, NewObjectWithNamedProperties) { LocalScope scope(vm_); const char *keys[1100]; std::string strKeys[1100]; Local<JSValueRef> values[1100]; for (int i = 0; i < 1100; i += (i < 80 ? (i < 10 ? 1 : 80) : 1000)) { for (int j = 0; j <= i; ++j) { strKeys[j] = "TestKey" + std::to_string(i) + "_" + std::to_string(j); std::string strVal("TestValue" + std::to_string(i) + "_" + std::to_string(j)); keys[j] = const_cast<char *>(strKeys[j].c_str()); values[j] = StringRef::NewFromUtf8(vm_, strVal.c_str()); } Local<ObjectRef> object = ObjectRef::NewWithNamedProperties(vm_, i + 1, keys, values); for (int j = 0; j <= i; ++j) { Local<JSValueRef> value1 = object->Get(vm_, StringRef::NewFromUtf8(vm_, keys[j])); EXPECT_TRUE(values[j]->IsStrictEquals(vm_, value1)); } JSHandle<JSObject> obj(JSNApiHelper::ToJSHandle(object)); uint32_t propCount = obj->GetJSHClass()->NumberOfProps(); if (i + 1 > PropertyAttributes::MAX_FAST_PROPS_CAPACITY) { EXPECT_TRUE(propCount == 0); EXPECT_TRUE(obj->GetJSHClass()->IsDictionaryMode()); JSHandle<NameDictionary> dict(thread_, obj->GetProperties()); EXPECT_TRUE(dict->EntriesCount() == i + 1); } else { EXPECT_TRUE(propCount == i + 1); int32_t in_idx = obj->GetJSHClass()->GetNextInlinedPropsIndex(); int32_t nonin_idx = obj->GetJSHClass()->GetNextNonInlinedPropsIndex(); if (i + 1 < JSHClass::DEFAULT_CAPACITY_OF_IN_OBJECTS) { EXPECT_TRUE(in_idx == i + 1); EXPECT_TRUE(nonin_idx == -1); } else { EXPECT_TRUE(in_idx == -1); EXPECT_TRUE(nonin_idx == 0); } } } } HWTEST_F_L0(JSNApiTests, NewObjectWithNamedPropertieNonPureStringKey) { LocalScope scope(vm_); const char *keys[] = { "1", }; Local<JSValueRef> values[] = { StringRef::NewFromUtf8(vm_, "value1"), }; Local<ObjectRef> object = ObjectRef::NewWithNamedProperties(vm_, 2, keys, values); JSHandle<JSTaggedValue> obj = JSNApiHelper::ToJSHandle(object); EXPECT_TRUE(obj.GetTaggedValue() == JSTaggedValue::Undefined()); thread_->ClearException(); } HWTEST_F_L0(JSNApiTests, NewObjectWithNamedPropertiesDuplicate) { LocalScope scope(vm_); const char *keys[] = { "duplicateKey", "simpleKey", "duplicateKey", }; Local<JSValueRef> values[] = { StringRef::NewFromUtf8(vm_, "value1"), StringRef::NewFromUtf8(vm_, "value2"), StringRef::NewFromUtf8(vm_, "value3"), }; Local<ObjectRef> object = ObjectRef::NewWithNamedProperties(vm_, 3, keys, values); JSHandle<JSTaggedValue> obj = JSNApiHelper::ToJSHandle(object); EXPECT_TRUE(obj.GetTaggedValue() == JSTaggedValue::Undefined()); thread_->ClearException(); } } // namespace panda::test