Files
ark_js_runtime/ecmascript/napi/test/jsnapi_tests.cpp
T
xiongluo 2e3d07b336 Fix long gc duration problem in photos app
Add handle scope to avoid the large number of root nodes.

Remove unnecessary handles in the critical path.

Adjust the parameters in gc to avoid multiple consecutive Old GCs.

Signed-off-by: xiongluo <xiongluo@huawei.com>
2022-04-10 20:45:15 -10:00

880 lines
35 KiB
C++

/*
* Copyright (c) 2021 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 "ecmascript/tests/test_helper.h"
#include <cstddef>
#include "ecmascript/builtins/builtins_function.h"
#include "ecmascript/ecma_vm.h"
#include "ecmascript/global_env.h"
#include "ecmascript/js_thread.h"
#include "ecmascript/napi/include/jsnapi.h"
#include "ecmascript/napi/jsnapi_helper.h"
#include "ecmascript/object_factory.h"
using namespace panda;
using namespace panda::ecmascript;
namespace panda::test {
using BuiltinsFunction = ecmascript::builtins::BuiltinsFunction;
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_);
}
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 ThreadCheck(const EcmaVM *vm)
{
EXPECT_TRUE(vm->GetJSThread()->GetThreadId() != JSThread::GetCurrentThreadId());
}
HWTEST_F_L0(JSNApiTests, GetGlobalObject)
{
LocalScope scope(vm_);
Local<ObjectRef> globalObject = JSNApi::GetGlobalObject(vm_);
ASSERT_FALSE(globalObject.IsEmpty());
ASSERT_TRUE(globalObject->IsObject());
}
HWTEST_F_L0(JSNApiTests, ThreadIdCheck)
{
EXPECT_TRUE(vm_->GetJSThread()->GetThreadId() == JSThread::GetCurrentThreadId());
#if defined(ECMASCRIPT_ENABLE_THREAD_CHECK) && !ECMASCRIPT_ENABLE_THREAD_CHECK
std::thread testThread(ThreadCheck, vm_);
testThread.join();
#endif
}
HWTEST_F_L0(JSNApiTests, RegisterFunction)
{
LocalScope scope(vm_);
Local<FunctionRef> callback = FunctionRef::New(vm_, FunctionCallback);
ASSERT_TRUE(!callback.IsEmpty());
std::vector<Local<JSValueRef>> arguments;
arguments.emplace_back(JSValueRef::Undefined(vm_));
Local<JSValueRef> result =
callback->Call(vm_, JSValueRef::Undefined(vm_), arguments.data(), arguments.size());
ASSERT_TRUE(result->IsArray(vm_));
Local<ArrayRef> array(result);
ASSERT_EQ(static_cast<uint64_t>(array->Length(vm_)), arguments.size());
}
HWTEST_F_L0(JSNApiTests, GetProperty)
{
LocalScope scope(vm_);
Local<ObjectRef> globalObject = JSNApi::GetGlobalObject(vm_);
ASSERT_FALSE(globalObject.IsEmpty());
ASSERT_TRUE(globalObject->IsObject());
Local<ObjectRef> key = StringRef::NewFromUtf8(vm_, "Number");
Local<ObjectRef> property = globalObject->Get(vm_, key);
ASSERT_TRUE(property->IsFunction());
}
HWTEST_F_L0(JSNApiTests, SetProperty)
{
LocalScope scope(vm_);
Local<ObjectRef> globalObject = JSNApi::GetGlobalObject(vm_);
ASSERT_FALSE(globalObject.IsEmpty());
ASSERT_TRUE(globalObject->IsObject());
Local<ArrayRef> property = ArrayRef::New(vm_, 3); // 3 : length
ASSERT_TRUE(property->IsArray(vm_));
ASSERT_EQ(property->Length(vm_), 3); // 3 : test case of input
Local<ObjectRef> key = StringRef::NewFromUtf8(vm_, "Test");
bool result = globalObject->Set(vm_, key, property);
ASSERT_TRUE(result);
Local<ObjectRef> propertyGet = globalObject->Get(vm_, key);
ASSERT_TRUE(propertyGet->IsArray(vm_));
ASSERT_EQ(Local<ArrayRef>(propertyGet)->Length(vm_), 3); // 3 : test case of input
}
HWTEST_F_L0(JSNApiTests, JsonParser)
{
LocalScope scope(vm_);
Local<ObjectRef> globalObject = JSNApi::GetGlobalObject(vm_);
ASSERT_FALSE(globalObject.IsEmpty());
ASSERT_TRUE(globalObject->IsObject());
const char *const test{R"({"orientation": "portrait"})"};
Local<ObjectRef> jsonString = StringRef::NewFromUtf8(vm_, test);
Local<JSValueRef> result = JSON::Parse(vm_, jsonString);
ASSERT_TRUE(result->IsObject());
Local<ObjectRef> keyString = StringRef::NewFromUtf8(vm_, "orientation");
Local<JSValueRef> property = Local<ObjectRef>(result)->Get(vm_, keyString);
ASSERT_TRUE(property->IsString());
}
HWTEST_F_L0(JSNApiTests, StrictEqual)
{
LocalScope scope(vm_);
Local<StringRef> origin = StringRef::NewFromUtf8(vm_, "1");
Local<StringRef> target1 = StringRef::NewFromUtf8(vm_, "1");
Local<NumberRef> target = NumberRef::New(vm_, 1);
ASSERT_FALSE(origin->IsStrictEquals(vm_, target));
ASSERT_TRUE(origin->IsStrictEquals(vm_, target1));
}
HWTEST_F_L0(JSNApiTests, InstanceOf)
{
LocalScope scope(vm_);
Local<FunctionRef> target = FunctionRef::New(vm_, nullptr);
Local<ArrayRef> origin = ArrayRef::New(vm_, 1);
ASSERT_FALSE(origin->InstanceOf(vm_, target));
}
HWTEST_F_L0(JSNApiTests, TypeOf)
{
LocalScope scope(vm_);
Local<StringRef> origin = StringRef::NewFromUtf8(vm_, "1");
Local<StringRef> typeString = origin->Typeof(vm_);
ASSERT_EQ(typeString->ToString(), "string");
Local<NumberRef> target = NumberRef::New(vm_, 1);
typeString = target->Typeof(vm_);
ASSERT_EQ(typeString->ToString(), "number");
}
HWTEST_F_L0(JSNApiTests, Symbol)
{
LocalScope scope(vm_);
Local<StringRef> description = StringRef::NewFromUtf8(vm_, "test");
Local<SymbolRef> symbol = SymbolRef::New(vm_, description);
ASSERT_FALSE(description->IsSymbol());
ASSERT_TRUE(symbol->IsSymbol());
}
HWTEST_F_L0(JSNApiTests, StringUtf8_001)
{
LocalScope scope(vm_);
std::string test = "Hello world";
Local<StringRef> testString = StringRef::NewFromUtf8(vm_, test.c_str());
EXPECT_EQ(testString->Utf8Length(), 12); // 12 : length of testString("Hello World")
char buffer[12]; // 12 : length of testString
EXPECT_EQ(testString->WriteUtf8(buffer, 12), 12); // 12 : length of testString("Hello World")
std::string res(buffer);
ASSERT_EQ(res, test);
}
HWTEST_F_L0(JSNApiTests, StringUtf8_002)
{
LocalScope scope(vm_);
std::string test = "";
Local<StringRef> testString = StringRef::NewFromUtf8(vm_, test.c_str());
EXPECT_EQ(testString->Utf8Length(), 4); // 4 : length of testString("年")
char buffer[4]; // 4 : length of testString
EXPECT_EQ(testString->WriteUtf8(buffer, 4), 4); // 4 : length of testString("年")
std::string res(buffer);
ASSERT_EQ(res, test);
}
HWTEST_F_L0(JSNApiTests, ToType)
{
LocalScope scope(vm_);
Local<StringRef> toString = StringRef::NewFromUtf8(vm_, "-123.3");
Local<JSValueRef> toValue(toString);
ASSERT_EQ(toString->ToNumber(vm_)->Value(), -123.3); // -123 : test case of input
ASSERT_EQ(toString->ToBoolean(vm_)->Value(), true);
ASSERT_EQ(toValue->ToString(vm_)->ToString(), "-123.3");
ASSERT_TRUE(toValue->ToObject(vm_)->IsObject());
}
HWTEST_F_L0(JSNApiTests, TypeValue)
{
LocalScope scope(vm_);
Local<StringRef> toString = StringRef::NewFromUtf8(vm_, "-123");
Local<JSValueRef> toValue(toString);
ASSERT_EQ(toString->Int32Value(vm_), -123); // -123 : test case of input
ASSERT_EQ(toString->BooleaValue(), true);
ASSERT_EQ(toString->Uint32Value(vm_), 4294967173U); // 4294967173 : test case of input
ASSERT_EQ(toString->IntegerValue(vm_), -123); // -123 : test case of input
}
HWTEST_F_L0(JSNApiTests, DefineProperty)
{
LocalScope scope(vm_);
Local<ObjectRef> object = ObjectRef::New(vm_);
Local<JSValueRef> key = StringRef::NewFromUtf8(vm_, "TestKey");
Local<JSValueRef> value = ObjectRef::New(vm_);
PropertyAttribute attribute(value, true, true, true);
ASSERT_TRUE(object->DefineProperty(vm_, key, attribute));
Local<JSValueRef> value1 = object->Get(vm_, key);
ASSERT_TRUE(value->IsStrictEquals(vm_, value1));
}
HWTEST_F_L0(JSNApiTests, HasProperty)
{
LocalScope scope(vm_);
Local<ObjectRef> object = ObjectRef::New(vm_);
Local<JSValueRef> key = StringRef::NewFromUtf8(vm_, "TestKey");
Local<JSValueRef> value = ObjectRef::New(vm_);
PropertyAttribute attribute(value, true, true, true);
ASSERT_TRUE(object->DefineProperty(vm_, key, attribute));
ASSERT_TRUE(object->Has(vm_, key));
}
HWTEST_F_L0(JSNApiTests, DeleteProperty)
{
LocalScope scope(vm_);
Local<ObjectRef> object = ObjectRef::New(vm_);
Local<JSValueRef> key = StringRef::NewFromUtf8(vm_, "TestKey");
Local<JSValueRef> value = ObjectRef::New(vm_);
PropertyAttribute attribute(value, true, true, true);
ASSERT_TRUE(object->DefineProperty(vm_, key, attribute));
ASSERT_TRUE(object->Delete(vm_, key));
ASSERT_FALSE(object->Has(vm_, key));
}
HWTEST_F_L0(JSNApiTests, GetProtoType)
{
LocalScope scope(vm_);
Local<FunctionRef> function = FunctionRef::New(vm_, nullptr);
Local<JSValueRef> protoType = function->GetPrototype(vm_);
ASSERT_TRUE(protoType->IsObject());
Local<FunctionRef> object = ObjectRef::New(vm_);
protoType = object->GetPrototype(vm_);
ASSERT_TRUE(protoType->IsObject());
}
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());
}
HWTEST_F_L0(JSNApiTests, PromiseCatch)
{
LocalScope scope(vm_);
Local<PromiseCapabilityRef> capability = PromiseCapabilityRef::New(vm_);
Local<PromiseRef> promise = capability->GetPromise(vm_);
Local<FunctionRef> reject = FunctionRef::New(vm_, RejectCallback);
Local<PromiseRef> catchPromise = promise->Catch(vm_, reject);
ASSERT_TRUE(promise->IsPromise());
ASSERT_TRUE(catchPromise->IsPromise());
Local<StringRef> reason = StringRef::NewFromUtf8(vm_, "Reject");
ASSERT_TRUE(capability->Reject(vm_, reason));
vm_->ExecutePromisePendingJob();
}
void CheckResolve(JsiRuntimeCallInfo* info)
{
ASSERT_EQ(info->GetArgsNumber(), 1U);
Local<JSValueRef> value = info->GetCallArgRef(0);
ASSERT_TRUE(value->IsNumber());
ASSERT_EQ(Local<NumberRef>(value)->Value(), 300.3); // 300.3 : test case of input
}
Local<JSValueRef> ResolvedCallback(JsiRuntimeCallInfo* info)
{
LocalScope scope(info->GetVM());
CheckResolve(info);
return JSValueRef::Undefined(info->GetVM());
}
HWTEST_F_L0(JSNApiTests, PromiseThen)
{
LocalScope scope(vm_);
Local<PromiseCapabilityRef> capability = PromiseCapabilityRef::New(vm_);
Local<PromiseRef> promise = capability->GetPromise(vm_);
Local<FunctionRef> resolve = FunctionRef::New(vm_, ResolvedCallback);
Local<FunctionRef> reject = FunctionRef::New(vm_, RejectCallback);
Local<PromiseRef> thenPromise = promise->Then(vm_, resolve, reject);
ASSERT_TRUE(promise->IsPromise());
ASSERT_TRUE(thenPromise->IsPromise());
Local<StringRef> value = NumberRef::New(vm_, 300.3); // 300.3 : test case of input
ASSERT_TRUE(capability->Resolve(vm_, value));
vm_->ExecutePromisePendingJob();
}
HWTEST_F_L0(JSNApiTests, Constructor)
{
LocalScope scope(vm_);
Local<ObjectRef> object = JSNApi::GetGlobalObject(vm_);
Local<StringRef> key = StringRef::NewFromUtf8(vm_, "Number");
Local<FunctionRef> numberConstructor = object->Get(vm_, key);
Local<JSValueRef> argv[1];
argv[0] = NumberRef::New(vm_, 1.3); // 1.3 : test case of input
Local<JSValueRef> result = numberConstructor->Constructor(vm_, argv, 1);
ASSERT_TRUE(result->IsObject());
ASSERT_EQ(result->ToNumber(vm_)->Value(), 1.3); // 1.3 : size of arguments
}
HWTEST_F_L0(JSNApiTests, ArrayBuffer)
{
LocalScope scope(vm_);
const int32_t length = 15;
Local<ArrayBufferRef> arrayBuffer = ArrayBufferRef::New(vm_, length);
ASSERT_TRUE(arrayBuffer->IsArrayBuffer());
ASSERT_EQ(arrayBuffer->ByteLength(vm_), length);
ASSERT_NE(arrayBuffer->GetBuffer(), nullptr);
JSNApi::TriggerGC(vm_);
}
HWTEST_F_L0(JSNApiTests, ArrayBufferWithBuffer)
{
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);
}
JSNApi::TriggerGC(vm_, JSNApi::TRIGGER_GC_TYPE::FULL_GC);
ASSERT_TRUE(isFree);
}
HWTEST_F_L0(JSNApiTests, DataView)
{
LocalScope scope(vm_);
const int32_t length = 15;
Local<ArrayBufferRef> arrayBuffer = ArrayBufferRef::New(vm_, length);
JSNApi::TriggerGC(vm_);
ASSERT_TRUE(arrayBuffer->IsArrayBuffer());
// 5 : offset of byte, 7 : length
Local<DataViewRef> dataView = DataViewRef::New(vm_, arrayBuffer, 5, 7);
ASSERT_TRUE(dataView->IsDataView());
ASSERT_EQ(dataView->GetArrayBuffer(vm_)->GetBuffer(), arrayBuffer->GetBuffer());
ASSERT_EQ(dataView->ByteLength(), 7U); // 7 : size of arguments
ASSERT_EQ(dataView->ByteOffset(), 5U); // 5 : size of arguments
// 5 : offset of byte, 11 : length
dataView = DataViewRef::New(vm_, arrayBuffer, 5, 11);
ASSERT_TRUE(dataView->IsException());
}
HWTEST_F_L0(JSNApiTests, Int8Array)
{
LocalScope scope(vm_);
const int32_t length = 15;
Local<ArrayBufferRef> arrayBuffer = ArrayBufferRef::New(vm_, length);
ASSERT_TRUE(arrayBuffer->IsArrayBuffer());
// 5 : offset of byte, 6 : length
Local<Int8ArrayRef> typedArray = Int8ArrayRef::New(vm_, arrayBuffer, 5, 6);
ASSERT_TRUE(typedArray->IsInt8Array());
ASSERT_EQ(typedArray->ByteLength(vm_), 6); // 6 : length of bytes
ASSERT_EQ(typedArray->ByteOffset(vm_), 5); // 5 : offset of byte
ASSERT_EQ(typedArray->ArrayLength(vm_), 6); // 6 : length of array
ASSERT_EQ(typedArray->GetArrayBuffer(vm_)->GetBuffer(), arrayBuffer->GetBuffer());
}
HWTEST_F_L0(JSNApiTests, Uint8Array)
{
LocalScope scope(vm_);
const int32_t length = 15;
Local<ArrayBufferRef> arrayBuffer = ArrayBufferRef::New(vm_, length);
ASSERT_TRUE(arrayBuffer->IsArrayBuffer());
// 5 : offset of byte, 6 : length
Local<Uint8ArrayRef> typedArray = Uint8ArrayRef::New(vm_, arrayBuffer, 5, 6);
ASSERT_TRUE(typedArray->IsUint8Array());
ASSERT_EQ(typedArray->ByteLength(vm_), 6); // 6 : length of bytes
ASSERT_EQ(typedArray->ByteOffset(vm_), 5); // 5 : offset of byte
ASSERT_EQ(typedArray->ArrayLength(vm_), 6); // 6 : length of array
ASSERT_EQ(typedArray->GetArrayBuffer(vm_)->GetBuffer(), arrayBuffer->GetBuffer());
}
HWTEST_F_L0(JSNApiTests, Uint8ClampedArray)
{
LocalScope scope(vm_);
const int32_t length = 15;
Local<ArrayBufferRef> arrayBuffer = ArrayBufferRef::New(vm_, length);
ASSERT_TRUE(arrayBuffer->IsArrayBuffer());
// 5 : offset of byte, 6 : length
Local<Uint8ClampedArrayRef> typedArray = Uint8ClampedArrayRef::New(vm_, arrayBuffer, 5, 6);
ASSERT_TRUE(typedArray->IsUint8ClampedArray());
ASSERT_EQ(typedArray->ByteLength(vm_), 6); // 6 : length of bytes
ASSERT_EQ(typedArray->ByteOffset(vm_), 5); // 5 : offset of byte
ASSERT_EQ(typedArray->ArrayLength(vm_), 6); // 6 : length of array
ASSERT_EQ(typedArray->GetArrayBuffer(vm_)->GetBuffer(), arrayBuffer->GetBuffer());
}
HWTEST_F_L0(JSNApiTests, Int16Array)
{
LocalScope scope(vm_);
const int32_t length = 30;
Local<ArrayBufferRef> arrayBuffer = ArrayBufferRef::New(vm_, length);
ASSERT_TRUE(arrayBuffer->IsArrayBuffer());
// 4 : offset of byte, 6 : length
Local<Int16ArrayRef> typedArray = Int16ArrayRef::New(vm_, arrayBuffer, 4, 6);
ASSERT_TRUE(typedArray->IsInt16Array());
ASSERT_EQ(typedArray->ByteLength(vm_), 12); // 12 : length of bytes
ASSERT_EQ(typedArray->ByteOffset(vm_), 4); // 4 : offset of byte
ASSERT_EQ(typedArray->ArrayLength(vm_), 6); // 6 : length of array
ASSERT_EQ(typedArray->GetArrayBuffer(vm_)->GetBuffer(), arrayBuffer->GetBuffer());
}
HWTEST_F_L0(JSNApiTests, Uint16Array)
{
LocalScope scope(vm_);
const int32_t length = 30;
Local<ArrayBufferRef> arrayBuffer = ArrayBufferRef::New(vm_, length);
ASSERT_TRUE(arrayBuffer->IsArrayBuffer());
// 4 : offset of byte, 6 : length
Local<Uint16ArrayRef> typedArray = Uint16ArrayRef::New(vm_, arrayBuffer, 4, 6);
ASSERT_TRUE(typedArray->IsUint16Array());
ASSERT_EQ(typedArray->ByteLength(vm_), 12); // 12 : length of bytes
ASSERT_EQ(typedArray->ByteOffset(vm_), 4); // 4 : offset of byte
ASSERT_EQ(typedArray->ArrayLength(vm_), 6); // 6 : length of array
ASSERT_EQ(typedArray->GetArrayBuffer(vm_)->GetBuffer(), arrayBuffer->GetBuffer());
}
HWTEST_F_L0(JSNApiTests, Uint32Array)
{
LocalScope scope(vm_);
const int32_t length = 30;
Local<ArrayBufferRef> arrayBuffer = ArrayBufferRef::New(vm_, length);
ASSERT_TRUE(arrayBuffer->IsArrayBuffer());
// 4 : offset of byte, 6 : length
Local<Uint32ArrayRef> typedArray = Uint32ArrayRef::New(vm_, arrayBuffer, 4, 6);
ASSERT_TRUE(typedArray->IsUint32Array());
ASSERT_EQ(typedArray->ByteLength(vm_), 24); // 24 : length of bytes
ASSERT_EQ(typedArray->ByteOffset(vm_), 4); // 4 : offset of byte
ASSERT_EQ(typedArray->ArrayLength(vm_), 6); // 6 : length of array
ASSERT_EQ(typedArray->GetArrayBuffer(vm_)->GetBuffer(), arrayBuffer->GetBuffer());
}
HWTEST_F_L0(JSNApiTests, Int32Array)
{
LocalScope scope(vm_);
const int32_t length = 30;
Local<ArrayBufferRef> arrayBuffer = ArrayBufferRef::New(vm_, length);
ASSERT_TRUE(arrayBuffer->IsArrayBuffer());
// 4 : offset of byte, 6 : length
Local<Int32ArrayRef> typedArray = Int32ArrayRef::New(vm_, arrayBuffer, 4, 6);
ASSERT_TRUE(typedArray->IsInt32Array());
ASSERT_EQ(typedArray->ByteLength(vm_), 24); // 24 : length of bytes
ASSERT_EQ(typedArray->ByteOffset(vm_), 4); // 4 : offset of byte
ASSERT_EQ(typedArray->ArrayLength(vm_), 6); // 6 : length of array
ASSERT_EQ(typedArray->GetArrayBuffer(vm_)->GetBuffer(), arrayBuffer->GetBuffer());
}
HWTEST_F_L0(JSNApiTests, Float32Array)
{
LocalScope scope(vm_);
const int32_t length = 30;
Local<ArrayBufferRef> arrayBuffer = ArrayBufferRef::New(vm_, length);
ASSERT_TRUE(arrayBuffer->IsArrayBuffer());
// 4 : offset of byte, 6 : length
Local<Float32ArrayRef> typedArray = Float32ArrayRef::New(vm_, arrayBuffer, 4, 6);
ASSERT_TRUE(typedArray->IsFloat32Array());
ASSERT_EQ(typedArray->ByteLength(vm_), 24); // 24 : length of bytes
ASSERT_EQ(typedArray->ByteOffset(vm_), 4); // 4 : offset of byte
ASSERT_EQ(typedArray->ArrayLength(vm_), 6); // 6 : length of array
ASSERT_EQ(typedArray->GetArrayBuffer(vm_)->GetBuffer(), arrayBuffer->GetBuffer());
}
HWTEST_F_L0(JSNApiTests, Float64Array)
{
LocalScope scope(vm_);
const int32_t length = 57;
Local<ArrayBufferRef> arrayBuffer = ArrayBufferRef::New(vm_, length);
ASSERT_TRUE(arrayBuffer->IsArrayBuffer());
// 8 : offset of byte, 6 : length
Local<Float64ArrayRef> typedArray = Float64ArrayRef::New(vm_, arrayBuffer, 8, 6);
ASSERT_TRUE(typedArray->IsFloat64Array());
ASSERT_EQ(typedArray->ByteLength(vm_), 48); // 48 : length of bytes
ASSERT_EQ(typedArray->ByteOffset(vm_), 8); // 8 : offset of byte
ASSERT_EQ(typedArray->ArrayLength(vm_), 6); // 6 : length of array
ASSERT_EQ(typedArray->GetArrayBuffer(vm_)->GetBuffer(), arrayBuffer->GetBuffer());
}
HWTEST_F_L0(JSNApiTests, BigInt64Array)
{
LocalScope scope(vm_);
const int32_t length = 57;
Local<ArrayBufferRef> arrayBuffer = ArrayBufferRef::New(vm_, length);
ASSERT_TRUE(arrayBuffer->IsArrayBuffer());
// 8 : offset of byte, 6 : length
Local<BigInt64ArrayRef> typedArray = BigInt64ArrayRef::New(vm_, arrayBuffer, 8, 6);
ASSERT_TRUE(typedArray->IsBigInt64Array());
ASSERT_EQ(typedArray->ByteLength(vm_), 48); // 48 : length of bytes
ASSERT_EQ(typedArray->ByteOffset(vm_), 8); // 8 : offset of byte
ASSERT_EQ(typedArray->ArrayLength(vm_), 6); // 6 : length of array
ASSERT_EQ(typedArray->GetArrayBuffer(vm_)->GetBuffer(), arrayBuffer->GetBuffer());
}
HWTEST_F_L0(JSNApiTests, BigUint64Array)
{
LocalScope scope(vm_);
const int32_t length = 57;
Local<ArrayBufferRef> arrayBuffer = ArrayBufferRef::New(vm_, length);
ASSERT_TRUE(arrayBuffer->IsArrayBuffer());
// 8 : offset of byte, 6 : length
Local<BigUint64ArrayRef> typedArray = BigUint64ArrayRef::New(vm_, arrayBuffer, 8, 6);
ASSERT_TRUE(typedArray->IsBigUint64Array());
ASSERT_EQ(typedArray->ByteLength(vm_), 48); // 48 : length of bytes
ASSERT_EQ(typedArray->ByteOffset(vm_), 8); // 8 : offset of byte
ASSERT_EQ(typedArray->ArrayLength(vm_), 6); // 6 : length of array
ASSERT_EQ(typedArray->GetArrayBuffer(vm_)->GetBuffer(), arrayBuffer->GetBuffer());
}
HWTEST_F_L0(JSNApiTests, Error)
{
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(thread_->HasPendingException());
}
HWTEST_F_L0(JSNApiTests, RangeError)
{
LocalScope scope(vm_);
Local<StringRef> message = StringRef::NewFromUtf8(vm_, "ErrorTest");
Local<JSValueRef> error = Exception::RangeError(vm_, message);
ASSERT_TRUE(error->IsError());
JSNApi::ThrowException(vm_, error);
ASSERT_TRUE(thread_->HasPendingException());
}
HWTEST_F_L0(JSNApiTests, TypeError)
{
LocalScope scope(vm_);
Local<StringRef> message = StringRef::NewFromUtf8(vm_, "ErrorTest");
Local<JSValueRef> error = Exception::TypeError(vm_, message);
ASSERT_TRUE(error->IsError());
JSNApi::ThrowException(vm_, error);
ASSERT_TRUE(thread_->HasPendingException());
}
HWTEST_F_L0(JSNApiTests, ReferenceError)
{
LocalScope scope(vm_);
Local<StringRef> message = StringRef::NewFromUtf8(vm_, "ErrorTest");
Local<JSValueRef> error = Exception::ReferenceError(vm_, message);
ASSERT_TRUE(error->IsError());
JSNApi::ThrowException(vm_, error);
ASSERT_TRUE(thread_->HasPendingException());
}
HWTEST_F_L0(JSNApiTests, SyntaxError)
{
LocalScope scope(vm_);
Local<StringRef> message = StringRef::NewFromUtf8(vm_, "ErrorTest");
Local<JSValueRef> error = Exception::SyntaxError(vm_, message);
ASSERT_TRUE(error->IsError());
JSNApi::ThrowException(vm_, error);
ASSERT_TRUE(thread_->HasPendingException());
}
HWTEST_F_L0(JSNApiTests, InheritPrototype_001)
{
LocalScope scope(vm_);
JSHandle<GlobalEnv> env = vm_->GetGlobalEnv();
// new with Builtins::Set Prototype
JSHandle<JSTaggedValue> set = env->GetBuiltinsSetFunction();
Local<FunctionRef> setLocal = JSNApiHelper::ToLocal<FunctionRef>(set);
// new with Builtins::Map Prototype
JSHandle<JSTaggedValue> map = env->GetBuiltinsMapFunction();
Local<FunctionRef> mapLocal = JSNApiHelper::ToLocal<FunctionRef>(map);
JSHandle<JSTaggedValue> setPrototype(thread_, JSHandle<JSFunction>::Cast(set)->GetFunctionPrototype());
JSHandle<JSTaggedValue> mapPrototype(thread_, JSHandle<JSFunction>::Cast(map)->GetFunctionPrototype());
JSHandle<JSTaggedValue> mapPrototypeProto(thread_, JSTaggedValue::GetPrototype(thread_, mapPrototype));
bool same = JSTaggedValue::SameValue(setPrototype, mapPrototypeProto);
// before inherit, map.Prototype.__proto__ should be different from set.Prototype
ASSERT_FALSE(same);
// before inherit, map.__proto__ should be different from set
JSHandle<JSTaggedValue> mapProto(thread_, JSTaggedValue::GetPrototype(thread_, map));
bool same1 = JSTaggedValue::SameValue(set, mapProto);
ASSERT_FALSE(same1);
// Set property to Set Function
auto factory = vm_->GetFactory();
JSHandle<JSTaggedValue> defaultString = thread_->GlobalConstants()->GetHandledDefaultString();
PropertyDescriptor desc = PropertyDescriptor(thread_, defaultString);
bool success = JSObject::DefineOwnProperty(thread_, JSHandle<JSObject>::Cast(set), defaultString, desc);
ASSERT_TRUE(success);
JSHandle<JSTaggedValue> property1String(thread_, factory->NewFromASCII("property1").GetTaggedValue());
JSHandle<JSTaggedValue> func = env->GetTypedArrayFunction();
PropertyDescriptor desc1 = PropertyDescriptor(thread_, func);
bool success1 = JSObject::DefineOwnProperty(thread_, JSHandle<JSObject>::Cast(set), property1String, desc1);
ASSERT_TRUE(success1);
mapLocal->Inherit(vm_, setLocal);
JSHandle<JSTaggedValue> sonHandle = JSNApiHelper::ToJSHandle(mapLocal);
JSHandle<JSTaggedValue> sonPrototype(thread_, JSHandle<JSFunction>::Cast(sonHandle)->GetFunctionPrototype());
JSHandle<JSTaggedValue> sonPrototypeProto(thread_, JSTaggedValue::GetPrototype(thread_, sonPrototype));
bool same2 = JSTaggedValue::SameValue(setPrototype, sonPrototypeProto);
ASSERT_TRUE(same2);
JSHandle<JSTaggedValue> sonProto(thread_, JSTaggedValue::GetPrototype(thread_, map));
bool same3 = JSTaggedValue::SameValue(set, sonProto);
ASSERT_TRUE(same3);
// son = new Son(), Son() inherit from Parent(), Test whether son.InstanceOf(Parent) is true
JSHandle<JSObject> sonObj = factory->NewJSObjectByConstructor(JSHandle<JSFunction>::Cast(sonHandle), sonHandle);
bool isInstance = JSObject::InstanceOf(thread_, JSHandle<JSTaggedValue>::Cast(sonObj), set);
ASSERT_TRUE(isInstance);
// Test whether son Function can access to property of parent Function
OperationResult res = JSObject::GetProperty(thread_, JSHandle<JSObject>::Cast(sonHandle), defaultString);
bool same4 = JSTaggedValue::SameValue(defaultString, res.GetValue());
ASSERT_TRUE(same4);
OperationResult res1 = JSObject::GetProperty(thread_, JSHandle<JSObject>::Cast(sonHandle), property1String);
bool same5 = JSTaggedValue::SameValue(func, res1.GetValue());
ASSERT_TRUE(same5);
// new with empty Function Constructor
Local<FunctionRef> son1 = FunctionRef::New(vm_, FunctionCallback, nullptr);
son1->Inherit(vm_, mapLocal);
JSHandle<JSFunction> son1Handle = JSHandle<JSFunction>::Cast(JSNApiHelper::ToJSHandle(son1));
ASSERT_TRUE(son1Handle->HasFunctionPrototype());
}
HWTEST_F_L0(JSNApiTests, InheritPrototype_002)
{
LocalScope scope(vm_);
JSHandle<GlobalEnv> env = vm_->GetGlobalEnv();
// new with Builtins::weakSet Prototype
JSHandle<JSTaggedValue> weakSet = env->GetBuiltinsWeakSetFunction();
Local<FunctionRef> weakSetLocal = JSNApiHelper::ToLocal<FunctionRef>(weakSet);
// new with Builtins::weakMap Prototype
JSHandle<JSTaggedValue> weakMap = env->GetBuiltinsWeakMapFunction();
Local<FunctionRef> weakMapLocal = JSNApiHelper::ToLocal<FunctionRef>(weakMap);
weakMapLocal->Inherit(vm_, weakSetLocal);
auto factory = vm_->GetFactory();
JSHandle<JSTaggedValue> property1String(thread_, factory->NewFromASCII("property1").GetTaggedValue());
JSHandle<JSTaggedValue> func = env->GetArrayFunction();
PropertyDescriptor desc1 = PropertyDescriptor(thread_, func);
bool success1 = JSObject::DefineOwnProperty(thread_, JSHandle<JSObject>::Cast(weakMap), property1String, desc1);
ASSERT_TRUE(success1);
JSHandle<JSTaggedValue> sonHandle = JSNApiHelper::ToJSHandle(weakMapLocal);
JSHandle<JSObject> sonObj =
factory->NewJSObjectByConstructor(JSHandle<JSFunction>::Cast(sonHandle), sonHandle);
JSHandle<JSTaggedValue> fatherHandle = JSNApiHelper::ToJSHandle(weakSetLocal);
JSHandle<JSObject> fatherObj =
factory->NewJSObjectByConstructor(JSHandle<JSFunction>::Cast(fatherHandle), fatherHandle);
JSHandle<JSTaggedValue> sonMethod =
JSObject::GetMethod(thread_, JSHandle<JSTaggedValue>(sonObj), property1String);
JSHandle<JSTaggedValue> fatherMethod =
JSObject::GetMethod(thread_, JSHandle<JSTaggedValue>(fatherObj), property1String);
bool same = JSTaggedValue::SameValue(sonMethod, fatherMethod);
ASSERT_TRUE(same);
}
HWTEST_F_L0(JSNApiTests, InheritPrototype_003)
{
LocalScope scope(vm_);
JSHandle<GlobalEnv> env = vm_->GetGlobalEnv();
auto factory = vm_->GetFactory();
JSMethod *invokeSelf =
vm_->GetMethodForNativeFunction(reinterpret_cast<void *>(BuiltinsFunction::FunctionPrototypeInvokeSelf));
// father type
JSHandle<JSHClass> protoDynclass = JSHandle<JSHClass>::Cast(env->GetFunctionClassWithProto());
JSHandle<JSFunction> protoFunc = factory->NewJSFunctionByDynClass(invokeSelf, protoDynclass);
Local<FunctionRef> protoLocal = JSNApiHelper::ToLocal<FunctionRef>(JSHandle<JSTaggedValue>(protoFunc));
// son type
JSHandle<JSHClass> noProtoDynclass = JSHandle<JSHClass>::Cast(env->GetFunctionClassWithoutProto());
JSHandle<JSFunction> noProtoFunc = factory->NewJSFunctionByDynClass(invokeSelf, noProtoDynclass);
Local<FunctionRef> noProtoLocal = JSNApiHelper::ToLocal<FunctionRef>(JSHandle<JSTaggedValue>(noProtoFunc));
JSHandle<JSFunction> sonHandle = JSHandle<JSFunction>::Cast(JSNApiHelper::ToJSHandle(noProtoLocal));
EXPECT_FALSE(sonHandle->HasFunctionPrototype());
JSHandle<JSTaggedValue> defaultString = thread_->GlobalConstants()->GetHandledDefaultString();
PropertyDescriptor desc = PropertyDescriptor(thread_, defaultString);
JSObject::DefineOwnProperty(thread_, JSHandle<JSObject>::Cast(protoFunc), defaultString, desc);
noProtoLocal->Inherit(vm_, protoLocal);
JSHandle<JSFunction> son1Handle = JSHandle<JSFunction>::Cast(JSNApiHelper::ToJSHandle(noProtoLocal));
EXPECT_TRUE(son1Handle->HasFunctionPrototype());
OperationResult res = JSObject::GetProperty(thread_, JSHandle<JSObject>::Cast(son1Handle), defaultString);
EXPECT_EQ(JSTaggedValue::SameValue(defaultString, res.GetValue()), true);
JSHandle<JSTaggedValue> propertyString(thread_, factory->NewFromASCII("property").GetTaggedValue());
JSHandle<JSTaggedValue> func = env->GetArrayFunction();
PropertyDescriptor desc1 = PropertyDescriptor(thread_, func);
JSObject::DefineOwnProperty(thread_, JSHandle<JSObject>::Cast(protoFunc), propertyString, desc1);
OperationResult res1 = JSObject::GetProperty(thread_, JSHandle<JSObject>::Cast(son1Handle), propertyString);
EXPECT_EQ(JSTaggedValue::SameValue(func, res1.GetValue()), true);
}
HWTEST_F_L0(JSNApiTests, InheritPrototype_004)
{
LocalScope scope(vm_);
JSHandle<GlobalEnv> env = vm_->GetGlobalEnv();
auto factory = vm_->GetFactory();
JSHandle<JSTaggedValue> weakSet = env->GetBuiltinsWeakSetFunction();
JSHandle<JSTaggedValue> deleteString(factory->NewFromASCII("delete"));
JSHandle<JSTaggedValue> addString(factory->NewFromASCII("add"));
JSHandle<JSTaggedValue> defaultString = thread_->GlobalConstants()->GetHandledDefaultString();
JSHandle<JSTaggedValue> deleteMethod = JSObject::GetMethod(thread_, weakSet, deleteString);
JSHandle<JSTaggedValue> addMethod = JSObject::GetMethod(thread_, weakSet, addString);
JSMethod *invokeSelf =
vm_->GetMethodForNativeFunction(reinterpret_cast<void *>(BuiltinsFunction::FunctionPrototypeInvokeSelf));
JSMethod *ctor = vm_->GetMethodForNativeFunction(reinterpret_cast<void *>(BuiltinsFunction::FunctionConstructor));
JSHandle<JSHClass> protoDynclass = JSHandle<JSHClass>::Cast(env->GetFunctionClassWithProto());
JSHandle<JSFunction> funcFuncPrototype = factory->NewJSFunctionByDynClass(invokeSelf, protoDynclass);
// add method in funcPrototype
PropertyDescriptor desc = PropertyDescriptor(thread_, deleteMethod);
JSObject::DefineOwnProperty(thread_, JSHandle<JSObject>::Cast(funcFuncPrototype), deleteString, desc);
JSHandle<JSTaggedValue> funcFuncPrototypeValue(funcFuncPrototype);
JSHandle<JSHClass> funcFuncProtoIntanceDynclass =
factory->NewEcmaDynClass(JSFunction::SIZE, JSType::JS_FUNCTION, funcFuncPrototypeValue);
// new with NewJSFunctionByDynClass::function DynClass
JSHandle<JSFunction> protoFunc =
factory->NewJSFunctionByDynClass(ctor, funcFuncProtoIntanceDynclass, FunctionKind::BUILTIN_CONSTRUCTOR);
EXPECT_TRUE(*protoFunc != nullptr);
// add method in funcnction
PropertyDescriptor desc1 = PropertyDescriptor(thread_, addMethod);
JSObject::DefineOwnProperty(thread_, JSHandle<JSObject>::Cast(protoFunc), addString, desc1);
JSObject::DefineOwnProperty(thread_, JSHandle<JSObject>::Cast(protoFunc), deleteString, desc);
// father type
Local<FunctionRef> protoLocal = JSNApiHelper::ToLocal<FunctionRef>(JSHandle<JSTaggedValue>(protoFunc));
JSHandle<JSHClass> noProtoDynclass = JSHandle<JSHClass>::Cast(env->GetFunctionClassWithoutProto());
JSHandle<JSFunction> funcFuncNoProtoPrototype = factory->NewJSFunctionByDynClass(invokeSelf, noProtoDynclass);
JSHandle<JSTaggedValue> funcFuncNoProtoPrototypeValue(funcFuncNoProtoPrototype);
JSHandle<JSHClass> funcFuncNoProtoProtoIntanceDynclass =
factory->NewEcmaDynClass(JSFunction::SIZE, JSType::JS_FUNCTION, funcFuncNoProtoPrototypeValue);
// new with NewJSFunctionByDynClass::function DynClass
JSHandle<JSFunction> noProtoFunc =
factory->NewJSFunctionByDynClass(ctor, funcFuncNoProtoProtoIntanceDynclass, FunctionKind::BUILTIN_CONSTRUCTOR);
EXPECT_TRUE(*noProtoFunc != nullptr);
// set property that has same key with fater type
PropertyDescriptor desc2 = PropertyDescriptor(thread_, defaultString);
JSObject::DefineOwnProperty(thread_, JSHandle<JSObject>::Cast(noProtoFunc), addString, desc2);
// son type
Local<FunctionRef> noProtoLocal = JSNApiHelper::ToLocal<FunctionRef>(JSHandle<JSTaggedValue>(noProtoFunc));
noProtoLocal->Inherit(vm_, protoLocal);
JSHandle<JSFunction> sonHandle = JSHandle<JSFunction>::Cast(JSNApiHelper::ToJSHandle(noProtoLocal));
OperationResult res = JSObject::GetProperty(thread_, JSHandle<JSObject>::Cast(sonHandle), deleteString);
EXPECT_EQ(JSTaggedValue::SameValue(deleteMethod, res.GetValue()), true);
// test if the property value changed after inherit
OperationResult res1 = JSObject::GetProperty(thread_, JSHandle<JSObject>::Cast(sonHandle), addString);
EXPECT_EQ(JSTaggedValue::SameValue(defaultString, res1.GetValue()), true);
}
HWTEST_F_L0(JSNApiTests, ClassFunction)
{
LocalScope scope(vm_);
Local<FunctionRef> cls = FunctionRef::NewClassFunction(vm_, nullptr, nullptr, nullptr);
JSHandle<JSTaggedValue> clsObj = JSNApiHelper::ToJSHandle(Local<JSValueRef>(cls));
ASSERT_TRUE(clsObj->IsClassConstructor());
JSTaggedValue accessor = JSHandle<JSFunction>(clsObj)->GetPropertyInlinedProps(
JSFunction::CLASS_PROTOTYPE_INLINE_PROPERTY_INDEX);
ASSERT_TRUE(accessor.IsInternalAccessor());
}
} // namespace panda::test