/* * 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 #include "ecmascript/builtins/builtins_arraybuffer.h" #include "ecmascript/ecma_language_context.h" #include "ecmascript/ecma_vm.h" #include "ecmascript/global_env.h" #include "ecmascript/js_array.h" #include "ecmascript/js_arraybuffer.h" #include "ecmascript/js_hclass.h" #include "ecmascript/js_regexp.h" #include "ecmascript/js_serializer.h" #include "ecmascript/js_set.h" #include "ecmascript/js_thread.h" #include "ecmascript/js_typed_array.h" #include "ecmascript/linked_hash_table-inl.h" #include "ecmascript/object_factory.h" #include "ecmascript/tests/test_helper.h" using namespace panda::ecmascript; using namespace testing::ext; using namespace panda::ecmascript::builtins; namespace panda::test { class JSDeserializerTest { public: JSDeserializerTest() : ecmaVm(nullptr), scope(nullptr), thread(nullptr) {} void Init() { RuntimeOptions options; options.SetShouldLoadBootPandaFiles(false); options.SetShouldInitializeIntrinsics(false); options.SetBootIntrinsicSpaces({"ecmascript"}); options.SetBootClassSpaces({"ecmascript"}); options.SetRuntimeType("ecmascript"); ecmaVm = EcmaVM::Create(options); EXPECT_TRUE(ecmaVm != nullptr) << "Cannot create Runtime"; thread = ecmaVm->GetJSThread(); scope = new EcmaHandleScope(thread); thread->SetIsEcmaInterpreter(true); ecmaVm->GetFactory()->SetTriggerGc(true); } void Destroy() { delete scope; scope = nullptr; ecmaVm->GetFactory()->SetTriggerGc(false); thread->ClearException(); [[maybe_unused]] bool success = EcmaVM::Destroy(ecmaVm); EXPECT_TRUE(success) << "Cannot destroy Runtime"; } void JSSpecialValueTest(std::pair data) { Init(); JSHandle jsTrue(thread, JSTaggedValue::True()); JSHandle jsFalse(thread, JSTaggedValue::False()); JSHandle jsUndefined(thread, JSTaggedValue::Undefined()); JSHandle jsNull(thread, JSTaggedValue::Null()); JSHandle jsHole(thread, JSTaggedValue::Hole()); JSDeserializer deserializer(thread, data.first, data.second); JSHandle retTrue = deserializer.DeserializeJSTaggedValue(); EXPECT_TRUE(JSTaggedValue::SameValue(jsTrue, retTrue)) << "Not same value for JS_TRUE"; JSHandle retFalse = deserializer.DeserializeJSTaggedValue(); EXPECT_TRUE(JSTaggedValue::SameValue(jsFalse, retFalse)) << "Not same value for JS_FALSE"; JSHandle retUndefined = deserializer.DeserializeJSTaggedValue(); JSHandle retNull = deserializer.DeserializeJSTaggedValue(); JSHandle retHole = deserializer.DeserializeJSTaggedValue(); EXPECT_TRUE(JSTaggedValue::SameValue(jsUndefined, retUndefined)) << "Not same value for JS_UNDEFINED"; EXPECT_TRUE(JSTaggedValue::SameValue(jsNull, retNull)) << "Not same value for JS_NULL"; EXPECT_TRUE(JSTaggedValue::SameValue(jsHole, retHole)) << "Not same value for JS_HOLE"; Destroy(); } void JSPlainObjectTest(std::pair data) { Init(); JSDeserializer deserializer(thread, data.first, data.second); JSHandle objValue1 = deserializer.DeserializeJSTaggedValue(); JSHandle objValue2 = deserializer.DeserializeJSTaggedValue(); JSHandle retObj1 = JSHandle::Cast(objValue1); JSHandle retObj2 = JSHandle::Cast(objValue2); EXPECT_FALSE(retObj1.IsEmpty()); EXPECT_FALSE(retObj2.IsEmpty()); JSHandle array1 = JSObject::GetOwnPropertyKeys(thread, retObj1); int length1 = array1->GetLength(); EXPECT_EQ(length1, 4); // 4 : test case double sum1 = 0.0; for (int i = 0; i < length1; i++) { JSHandle key(thread, array1->Get(i)); double a = JSObject::GetProperty(thread, JSHandle(retObj1), key).GetValue()->GetNumber(); sum1 += a; } EXPECT_EQ(sum1, 10); // 10 : test case JSHandle array2 = JSObject::GetOwnPropertyKeys(thread, retObj2); int length2 = array2->GetLength(); EXPECT_EQ(length2, 4); // 4 : test case double sum2 = 0.0; for (int i = 0; i < length2; i++) { JSHandle key(thread, array2->Get(i)); double a = JSObject::GetProperty(thread, JSHandle(retObj2), key).GetValue()->GetNumber(); sum2 += a; } EXPECT_EQ(sum2, 26); // 26 : test case Destroy(); } void DescriptionTest(std::pair data) { Init(); ObjectFactory *factory = ecmaVm->GetFactory(); JSHandle key1(factory->NewFromCanBeCompressString("x")); JSHandle key2(thread->GetEcmaVM()->GetFactory()->NewFromCanBeCompressString("y")); JSHandle value1(thread, JSTaggedValue(1)); JSHandle value2(thread, JSTaggedValue(2)); // 2 : test case JSDeserializer deserializer(thread, data.first, data.second); JSHandle objValue = deserializer.DeserializeJSTaggedValue(); JSHandle retObj = JSHandle::Cast(objValue); PropertyDescriptor desc3(thread); PropertyDescriptor desc4(thread); JSHandle array1 = JSObject::GetOwnPropertyKeys(thread, retObj); JSHandle retKey1(thread, array1->Get(0)); JSHandle retKey2(thread, array1->Get(1)); JSObject::GetOwnProperty(thread, retObj, retKey1, desc3); JSObject::GetOwnProperty(thread, retObj, retKey2, desc4); EXPECT_EQ(key1.GetTaggedValue().GetRawData(), retKey1.GetTaggedValue().GetRawData()); EXPECT_EQ(desc3.GetValue().GetTaggedValue().GetRawData(), value1.GetTaggedValue().GetRawData()); EXPECT_TRUE(desc3.IsWritable()); EXPECT_FALSE(desc3.IsEnumerable()); EXPECT_TRUE(desc3.IsConfigurable()); EXPECT_EQ(desc4.GetValue().GetTaggedValue().GetRawData(), value2.GetTaggedValue().GetRawData()); EXPECT_FALSE(desc4.IsWritable()); EXPECT_TRUE(desc4.IsEnumerable()); EXPECT_FALSE(desc4.IsConfigurable()); Destroy(); } void JSSetTest(std::pair data) { Init(); ObjectFactory *factory = ecmaVm->GetFactory(); JSHandle value1(thread, JSTaggedValue(7)); // 7 : test case JSHandle value2(thread, JSTaggedValue(9)); // 9 : test case JSHandle value3(factory->NewFromCanBeCompressString("x")); JSHandle value4(factory->NewFromCanBeCompressString("y")); JSDeserializer deserializer(thread, data.first, data.second); JSHandle setValue = deserializer.DeserializeJSTaggedValue(); EXPECT_TRUE(!setValue.IsEmpty()); JSHandle retSet = JSHandle::Cast(setValue); JSHandle array = JSObject::GetOwnPropertyKeys(thread, JSHandle::Cast(retSet)); int propertyLength = array->GetLength(); EXPECT_EQ(propertyLength, 2); // 2 : test case int sum = 0; for (int i = 0; i < propertyLength; i++) { JSHandle key(thread, array->Get(i)); double a = JSObject::GetProperty(thread, JSHandle(retSet), key).GetValue()->GetNumber(); sum += a; } EXPECT_EQ(sum, 16); // 16 : test case EXPECT_EQ(retSet->GetSize(), 4); // 4 : test case EXPECT_TRUE(retSet->Has(value1.GetTaggedValue())); EXPECT_TRUE(retSet->Has(value2.GetTaggedValue())); EXPECT_TRUE(retSet->Has(value3.GetTaggedValue())); EXPECT_TRUE(retSet->Has(value4.GetTaggedValue())); Destroy(); } void JSArrayTest(std::pair data) { Init(); JSDeserializer deserializer(thread, data.first, data.second); JSHandle arrayValue = deserializer.DeserializeJSTaggedValue(); EXPECT_TRUE(!arrayValue.IsEmpty()); JSHandle retArray = JSHandle::Cast(arrayValue); JSHandle keyArray = JSObject::GetOwnPropertyKeys(thread, JSHandle(retArray)); int propertyLength = keyArray->GetLength(); EXPECT_EQ(propertyLength, 23); // 23 : test case int sum = 0; for (int i = 0; i < propertyLength; i++) { JSHandle key(thread, keyArray->Get(i)); double a = JSObject::GetProperty(thread, JSHandle(retArray), key).GetValue()->GetNumber(); sum += a; } EXPECT_EQ(sum, 226); // 226 : test case // test get value from array for (int i = 0; i < 20; i++) { // 20 : test case JSHandle value = JSArray::FastGetPropertyByValue(thread, arrayValue, i); EXPECT_EQ(i, value.GetTaggedValue().GetInt()); } Destroy(); } void ObjectsPropertyReferenceTest(std::pair data) { Init(); JSDeserializer deserializer(thread, data.first, data.second); JSHandle objValue1 = deserializer.DeserializeJSTaggedValue(); JSHandle objValue2 = deserializer.DeserializeJSTaggedValue(); EXPECT_TRUE(!objValue1.IsEmpty()) << "[Empty] Deserialize obj1 fail"; EXPECT_TRUE(!objValue2.IsEmpty()) << "[Empty] Deserialize obj2 fail"; Destroy(); } void EcmaStringTest(std::pair data) { Init(); const char *rawStr = "this is a test ecmaString"; JSHandle ecmaString = thread->GetEcmaVM()->GetFactory()->NewFromCanBeCompressString(rawStr); JSDeserializer deserializer(thread, data.first, data.second); JSHandle res = deserializer.DeserializeJSTaggedValue(); EXPECT_TRUE(!res.IsEmpty()) << "[Empty] Deserialize ecmaString fail"; EXPECT_TRUE(res->IsString()) << "[NotString] Deserialize ecmaString fail"; JSHandle resEcmaString = JSHandle::Cast(res); EXPECT_TRUE(ecmaString->GetHashcode() == resEcmaString->GetHashcode()) << "Not same HashCode"; EXPECT_TRUE(EcmaString::StringsAreEqual(*ecmaString, *resEcmaString)) << "Not same EcmaString"; Destroy(); } void Int32Test(std::pair data) { Init(); int32_t a = 64; int32_t min = -2147483648; int32_t b = -63; JSDeserializer deserializer(thread, data.first, data.second); JSHandle resA = deserializer.DeserializeJSTaggedValue(); JSHandle resMin = deserializer.DeserializeJSTaggedValue(); JSHandle resB = deserializer.DeserializeJSTaggedValue(); EXPECT_TRUE(!resA.IsEmpty() && !resMin.IsEmpty() && !resB.IsEmpty()) << "[Empty] Deserialize Int32 fail"; EXPECT_TRUE(resA->IsInt() && resMin->IsInt() && resB->IsInt()) << "[NotInt] Deserialize Int32 fail"; EXPECT_TRUE(JSTaggedValue::ToInt32(thread, resA) == a) << "Not Same Value"; EXPECT_TRUE(JSTaggedValue::ToInt32(thread, resMin) == min) << "Not Same Value"; EXPECT_TRUE(JSTaggedValue::ToInt32(thread, resB) == b) << "Not Same Value"; Destroy(); } void DoubleTest(std::pair data) { Init(); double a = 3.1415926535; double b = -3.1415926535; JSDeserializer deserializer(thread, data.first, data.second); JSHandle resA = deserializer.DeserializeJSTaggedValue(); JSHandle resB = deserializer.DeserializeJSTaggedValue(); EXPECT_TRUE(!resA.IsEmpty() && !resB.IsEmpty()) << "[Empty] Deserialize double fail"; EXPECT_TRUE(resA->IsDouble() && resB->IsDouble()) << "[NotInt] Deserialize double fail"; EXPECT_TRUE(resA->GetDouble() == a) << "Not Same Value"; EXPECT_TRUE(resB->GetDouble() == b) << "Not Same Value"; Destroy(); } void JSDateTest(std::pair data) { Init(); double tm = 28 * 60 * 60 * 1000; // 28 * 60 * 60 * 1000 : test case JSDeserializer deserializer(thread, data.first, data.second); JSHandle res = deserializer.DeserializeJSTaggedValue(); EXPECT_TRUE(!res.IsEmpty()) << "[Empty] Deserialize JSDate fail"; EXPECT_TRUE(res->IsDate()) << "[NotJSDate] Deserialize JSDate fail"; JSHandle resDate = JSHandle(res); EXPECT_TRUE(resDate->GetTimeValue() == JSTaggedValue(tm)) << "Not Same Time Value"; Destroy(); } void JSMapTest(std::pair data, const JSHandle &originMap) { Init(); JSDeserializer deserializer(thread, data.first, data.second); JSHandle res = deserializer.DeserializeJSTaggedValue(); EXPECT_TRUE(!res.IsEmpty()) << "[Empty] Deserialize JSMap fail"; EXPECT_TRUE(res->IsJSMap()) << "[NotJSMap] Deserialize JSMap fail"; JSHandle resMap = JSHandle::Cast(res); EXPECT_TRUE(originMap->GetSize() == resMap->GetSize()) << "the map size Not equal"; uint32_t resSize = resMap->GetSize(); for (uint32_t i = 0; i < resSize; i++) { JSHandle resKey(thread, resMap->GetKey(i)); JSHandle resValue(thread, resMap->GetValue(i)); JSHandle key(thread, originMap->GetKey(i)); JSHandle value(thread, originMap->GetValue(i)); JSHandle resKeyStr = JSHandle::Cast(resKey); JSHandle keyStr = JSHandle::Cast(key); EXPECT_TRUE(EcmaString::StringsAreEqual(*resKeyStr, *keyStr)) << "Not same map key"; EXPECT_TRUE(JSTaggedValue::ToInt32(thread, resValue) == JSTaggedValue::ToInt32(thread, value)) << "Not same map value"; } Destroy(); } void JSArrayBufferTest(std::pair data, const JSHandle &originArrayBuffer, int32_t byteLength, const char *msg) { Init(); JSDeserializer deserializer(thread, data.first, data.second); JSHandle res = deserializer.DeserializeJSTaggedValue(); EXPECT_TRUE(!res.IsEmpty()) << "[Empty] Deserialize JSArrayBuffer fail"; EXPECT_TRUE(res->IsArrayBuffer()) << "[NotJSArrayBuffer] Deserialize JSArrayBuffer fail"; JSHandle resJSArrayBuffer = JSHandle::Cast(res); JSTaggedValue resTaggedLength = resJSArrayBuffer->GetArrayBufferByteLength(); int32_t resByteLength = static_cast(resTaggedLength.GetInt()); EXPECT_TRUE(resByteLength == byteLength) << "Not Same ByteLength"; // 10 : test case JSHandle bufferData(thread, originArrayBuffer->GetArrayBufferData()); auto np = JSHandle::Cast(bufferData); void *buffer = np->GetExternalPointer(); ASSERT_NE(buffer, nullptr); JSHandle resBufferData(thread, resJSArrayBuffer->GetArrayBufferData()); JSHandle resNp = JSHandle::Cast(resBufferData); void *resBuffer = resNp->GetExternalPointer(); ASSERT_NE(resBuffer, nullptr); for (int32_t i = 0; i < resByteLength; i++) { EXPECT_TRUE(static_cast(resBuffer)[i] == static_cast(buffer)[i]) << "Not Same Buffer"; } if (msg != nullptr) { if (memcpy_s(resBuffer, byteLength, msg, byteLength) != EOK) { EXPECT_TRUE(false) << " memcpy error!"; } } Destroy(); } void JSRegexpTest(std::pair data) { Init(); JSHandle pattern = thread->GetEcmaVM()->GetFactory()->NewFromCanBeCompressString("key2"); JSHandle flags = thread->GetEcmaVM()->GetFactory()->NewFromCanBeCompressString("i"); char buffer[] = "1234567"; // use char buffer to simulate byteCodeBuffer uint32_t bufferSize = 7; JSDeserializer deserializer(thread, data.first, data.second); JSHandle res = deserializer.DeserializeJSTaggedValue(); EXPECT_TRUE(!res.IsEmpty()) << "[Empty] Deserialize JSRegExp fail"; EXPECT_TRUE(res->IsJSRegExp()) << "[NotJSRegexp] Deserialize JSRegExp fail"; JSHandle resJSRegexp(res); uint32_t resBufferSize = static_cast(resJSRegexp->GetLength().GetInt()); EXPECT_TRUE(resBufferSize == bufferSize) << "Not Same Length"; JSHandle originalSource(thread, resJSRegexp->GetOriginalSource()); EXPECT_TRUE(originalSource->IsString()); JSHandle originalFlags(thread, resJSRegexp->GetOriginalFlags()); EXPECT_TRUE(originalFlags->IsString()); EXPECT_TRUE(EcmaString::StringsAreEqual(*JSHandle(originalSource), *pattern)); EXPECT_TRUE(EcmaString::StringsAreEqual(*JSHandle(originalFlags), *flags)); JSHandle resBufferData(thread, resJSRegexp->GetByteCodeBuffer()); JSHandle resNp = JSHandle::Cast(resBufferData); void *resBuffer = resNp->GetExternalPointer(); ASSERT_NE(resBuffer, nullptr); for (uint32_t i = 0; i < resBufferSize; i++) { EXPECT_TRUE(static_cast(resBuffer)[i] == buffer[i]) << "Not Same ByteCode"; } Destroy(); } void TypedArrayTest(std::pair data, const JSHandle &originTypedArray) { Init(); JSHandle originTypedArrayName(thread, originTypedArray->GetTypedArrayName()); JSDeserializer deserializer(thread, data.first, data.second); JSHandle res = deserializer.DeserializeJSTaggedValue(); EXPECT_TRUE(!res.IsEmpty()) << "[Empty] Deserialize TypedArray fail"; EXPECT_TRUE(res->IsJSInt8Array()) << "[NotJSInt8Array] Deserialize TypedArray fail"; JSHandle resJSInt8Array = JSHandle::Cast(res); JSHandle typedArrayName(thread, resJSInt8Array->GetTypedArrayName()); JSTaggedValue byteLength = resJSInt8Array->GetByteLength(); JSTaggedValue byteOffset = resJSInt8Array->GetByteOffset(); JSTaggedValue arrayLength = resJSInt8Array->GetArrayLength(); JSHandle viewedArrayBuffer(thread, resJSInt8Array->GetViewedArrayBuffer()); EXPECT_TRUE(typedArrayName->IsString()); EXPECT_TRUE(EcmaString::StringsAreEqual(*JSHandle(typedArrayName), *JSHandle(originTypedArrayName))); EXPECT_TRUE(byteLength.GetInt() == originTypedArray->GetByteLength().GetInt()) << "Not Same ByteLength"; EXPECT_TRUE(byteOffset.GetInt() == originTypedArray->GetByteOffset().GetInt()) << "Not Same ByteOffset"; EXPECT_TRUE(arrayLength.GetInt() == originTypedArray->GetArrayLength().GetInt()) << "Not Same ArrayLength"; // check arrayBuffer JSHandle resJSArrayBuffer(viewedArrayBuffer); JSHandle originArrayBuffer(thread, originTypedArray->GetViewedArrayBuffer()); JSTaggedValue resTaggedLength = resJSArrayBuffer->GetArrayBufferByteLength(); JSTaggedValue originTaggedLength = originArrayBuffer->GetArrayBufferByteLength(); EXPECT_TRUE(resTaggedLength.GetInt() == originTaggedLength.GetInt()) << "Not same viewedBuffer length"; JSHandle bufferData(thread, originArrayBuffer->GetArrayBufferData()); JSHandle np = JSHandle::Cast(bufferData); void *buffer = np->GetExternalPointer(); JSHandle resBufferData(thread, resJSArrayBuffer->GetArrayBufferData()); JSHandle resNp = JSHandle::Cast(resBufferData); void *resBuffer = resNp->GetExternalPointer(); for (int32_t i = 0; i < resTaggedLength.GetInt(); i++) { EXPECT_TRUE(static_cast(resBuffer)[i] == static_cast(buffer)[i]) << "Not same viewedBuffer"; } Destroy(); } private: EcmaVM *ecmaVm = nullptr; EcmaHandleScope *scope = nullptr; JSThread *thread = nullptr; }; class JSSerializerTest : public testing::Test { public: static void SetUpTestCase() { GTEST_LOG_(INFO) << "SetUpTestCase"; } static void TearDownTestCase() { GTEST_LOG_(INFO) << "TearDownCase"; } void SetUp() override { TestHelper::CreateEcmaVMWithScope(instance, thread, scope); ecmaVm = EcmaVM::Cast(instance); } void TearDown() override { TestHelper::DestroyEcmaVMWithScope(instance, scope); } JSThread *thread {nullptr}; PandaVM *instance {nullptr}; EcmaVM *ecmaVm {nullptr}; EcmaHandleScope *scope {nullptr}; }; HWTEST_F_L0(JSSerializerTest, SerializeJSSpecialValue) { JSSerializer *serializer = new JSSerializer(thread); JSHandle jsTrue(thread, JSTaggedValue::True()); JSHandle jsFalse(thread, JSTaggedValue::False()); JSHandle jsUndefined(thread, JSTaggedValue::Undefined()); JSHandle jsNull(thread, JSTaggedValue::Null()); JSHandle jsHole(thread, JSTaggedValue::Hole()); serializer->SerializeJSTaggedValue(jsTrue); serializer->SerializeJSTaggedValue(jsFalse); serializer->SerializeJSTaggedValue(jsUndefined); serializer->SerializeJSTaggedValue(jsNull); serializer->SerializeJSTaggedValue(jsHole); std::pair data = serializer->ReleaseBuffer(); JSDeserializerTest jsDeserializerTest; std::thread t1(&JSDeserializerTest::JSSpecialValueTest, jsDeserializerTest, data); t1.join(); }; HWTEST_F_L0(JSSerializerTest, SerializeJSPlainObject) { ObjectFactory *factory = ecmaVm->GetFactory(); JSHandle obj1 = factory->NewEmptyJSObject(); JSHandle obj2 = factory->NewEmptyJSObject(); JSHandle key1(factory->NewFromCanBeCompressString("2")); JSHandle key2(factory->NewFromCanBeCompressString("3")); JSHandle key3(factory->NewFromCanBeCompressString("x")); JSHandle key4(factory->NewFromCanBeCompressString("y")); JSHandle key5(factory->NewFromCanBeCompressString("a")); JSHandle key6(factory->NewFromCanBeCompressString("b")); JSHandle key7(factory->NewFromCanBeCompressString("5")); JSHandle key8(factory->NewFromCanBeCompressString("6")); JSHandle value1(thread, JSTaggedValue(1)); JSHandle value2(thread, JSTaggedValue(2)); JSHandle value3(thread, JSTaggedValue(3)); JSHandle value4(thread, JSTaggedValue(4)); JSHandle value5(thread, JSTaggedValue(5)); JSHandle value6(thread, JSTaggedValue(6)); JSHandle value7(thread, JSTaggedValue(7)); JSHandle value8(thread, JSTaggedValue(8)); JSObject::SetProperty(thread, JSHandle(obj1), key1, value1); JSObject::SetProperty(thread, JSHandle(obj1), key2, value2); JSObject::SetProperty(thread, JSHandle(obj1), key3, value3); JSObject::SetProperty(thread, JSHandle(obj1), key4, value4); JSObject::SetProperty(thread, JSHandle(obj2), key5, value5); JSObject::SetProperty(thread, JSHandle(obj2), key6, value6); JSObject::SetProperty(thread, JSHandle(obj2), key7, value7); JSObject::SetProperty(thread, JSHandle(obj2), key8, value8); JSSerializer *serializer = new JSSerializer(thread); bool success1 = serializer->SerializeJSTaggedValue(JSHandle::Cast(obj1)); bool success2 = serializer->SerializeJSTaggedValue(JSHandle::Cast(obj2)); EXPECT_TRUE(success1); EXPECT_TRUE(success2); std::pair data = serializer->ReleaseBuffer(); JSDeserializerTest jsDeserializerTest; std::thread t1(&JSDeserializerTest::JSPlainObjectTest, jsDeserializerTest, data); t1.join(); }; HWTEST_F_L0(JSSerializerTest, TestSerializeDescription) { ObjectFactory *factory = ecmaVm->GetFactory(); JSHandle obj = factory->NewEmptyJSObject(); JSHandle key1(factory->NewFromCanBeCompressString("x")); JSHandle key2(thread->GetEcmaVM()->GetFactory()->NewFromCanBeCompressString("y")); PropertyDescriptor desc1(thread); JSHandle value1(thread, JSTaggedValue(1)); desc1.SetValue(value1); desc1.SetWritable(true); desc1.SetEnumerable(false); desc1.SetConfigurable(true); JSObject::DefineOwnProperty(thread, obj, key1, desc1); PropertyDescriptor desc2(thread); JSHandle value2(thread, JSTaggedValue(2)); desc2.SetValue(value2); desc2.SetWritable(false); desc2.SetEnumerable(true); desc2.SetConfigurable(false); JSObject::DefineOwnProperty(thread, obj, key2, desc2); JSSerializer *serializer = new JSSerializer(thread); bool success = serializer->SerializeJSTaggedValue(JSHandle::Cast(obj)); EXPECT_TRUE(success); std::pair data = serializer->ReleaseBuffer(); JSDeserializerTest jsDeserializerTest; std::thread t1(&JSDeserializerTest::DescriptionTest, jsDeserializerTest, data); t1.join(); }; HWTEST_F_L0(JSSerializerTest, TestSerializeJSSet) { ObjectFactory *factory = ecmaVm->GetFactory(); JSHandle env = thread->GetEcmaVM()->GetGlobalEnv(); JSHandle constructor = env->GetBuiltinsSetFunction(); JSHandle set = JSHandle::Cast(factory->NewJSObjectByConstructor(JSHandle(constructor), constructor)); JSTaggedValue linkedSet = LinkedHashSet::Create(thread); set->SetLinkedSet(thread, linkedSet); // set property to set JSHandle value1(thread, JSTaggedValue(7)); JSHandle value2(thread, JSTaggedValue(9)); JSHandle value3(factory->NewFromCanBeCompressString("x")); JSHandle value4(factory->NewFromCanBeCompressString("y")); JSSet::Add(thread, set, value1); JSSet::Add(thread, set, value2); JSSet::Add(thread, set, value3); JSSet::Add(thread, set, value4); // set property to object JSHandle key1(factory->NewFromCanBeCompressString("5")); JSHandle key2(factory->NewFromCanBeCompressString("6")); JSObject::SetProperty(thread, JSHandle(set), key1, value1); JSObject::SetProperty(thread, JSHandle(set), key2, value2); JSSerializer *serializer = new JSSerializer(thread); bool success = serializer->SerializeJSTaggedValue(JSHandle::Cast(set)); EXPECT_TRUE(success); std::pair data = serializer->ReleaseBuffer(); JSDeserializerTest jsDeserializerTest; std::thread t1(&JSDeserializerTest::JSSetTest, jsDeserializerTest, data); t1.join(); }; HWTEST_F_L0(JSSerializerTest, TestSerializeJSArray) { ObjectFactory *factory = ecmaVm->GetFactory(); JSHandle array = factory->NewJSArray(); // set property to object JSHandle key1(factory->NewFromCanBeCompressString("abasd")); JSHandle key2(factory->NewFromCanBeCompressString("qweqwedasd")); JSHandle value1(thread, JSTaggedValue(7)); JSHandle value2(thread, JSTaggedValue(9)); JSObject::SetProperty(thread, JSHandle(array), key1, value1); JSObject::SetProperty(thread, JSHandle(array), key2, value2); // set value to array array->SetArrayLength(thread, 20); for (int i = 0; i < 20; i++) { JSHandle data(thread, JSTaggedValue(i)); JSArray::FastSetPropertyByValue(thread, JSHandle::Cast(array), i, data); } JSSerializer *serializer = new JSSerializer(thread); bool success = serializer->SerializeJSTaggedValue(JSHandle::Cast(array)); EXPECT_TRUE(success); std::pair data = serializer->ReleaseBuffer(); JSDeserializerTest jsDeserializerTest; std::thread t1(&JSDeserializerTest::JSArrayTest, jsDeserializerTest, data); t1.join(); }; // Test the situation that Objects' properties stores values that reference with each other HWTEST_F_L0(JSSerializerTest, TestObjectsPropertyReference) { ObjectFactory *factory = ecmaVm->GetFactory(); JSHandle obj1 = factory->NewEmptyJSObject(); JSHandle obj2 = factory->NewEmptyJSObject(); [[maybe_unused]] JSHandle obj3 = factory->NewEmptyJSObject(); JSHandle key1(factory->NewFromCanBeCompressString("abc")); JSHandle key2(factory->NewFromCanBeCompressString("def")); JSHandle key3(factory->NewFromCanBeCompressString("dgsdgf")); JSHandle key4(factory->NewFromCanBeCompressString("qwjhrf")); JSHandle value3(thread, JSTaggedValue(10)); JSHandle value4(thread, JSTaggedValue(5)); // set property to obj1 JSObject::SetProperty(thread, JSHandle::Cast(obj1), key1, JSHandle::Cast(obj2)); JSObject::SetProperty(thread, JSHandle::Cast(obj1), key3, value3); // set property to obj2 JSObject::SetProperty(thread, JSHandle::Cast(obj2), key2, JSHandle::Cast(obj1)); JSObject::SetProperty(thread, JSHandle::Cast(obj2), key4, value4); JSSerializer *serializer = new JSSerializer(thread); bool success1 = serializer->SerializeJSTaggedValue(JSHandle::Cast(obj1)); bool success2 = serializer->SerializeJSTaggedValue(JSHandle::Cast(obj1)); EXPECT_TRUE(success1) << "Serialize obj1 fail"; EXPECT_TRUE(success2) << "Serialize obj2 fail"; std::pair data = serializer->ReleaseBuffer(); JSDeserializerTest jsDeserializerTest; std::thread t1(&JSDeserializerTest::ObjectsPropertyReferenceTest, jsDeserializerTest, data); t1.join(); }; HWTEST_F_L0(JSSerializerTest, SerializeEcmaString) { const char *rawStr = "this is a test ecmaString"; JSHandle ecmaString = thread->GetEcmaVM()->GetFactory()->NewFromCanBeCompressString(rawStr); JSSerializer *serializer = new JSSerializer(thread); bool success = serializer->SerializeJSTaggedValue(JSHandle(ecmaString)); EXPECT_TRUE(success) << "Serialize EcmaString fail"; std::pair data = serializer->ReleaseBuffer(); JSDeserializerTest jsDeserializerTest; std::thread t1(&JSDeserializerTest::EcmaStringTest, jsDeserializerTest, data); t1.join(); }; HWTEST_F_L0(JSSerializerTest, SerializeInt32_t) { JSSerializer *serializer = new JSSerializer(thread); int32_t a = 64, min = -2147483648, b = -63; JSTaggedValue aTag(a), minTag(min), bTag(b); bool success1 = serializer->SerializeJSTaggedValue(JSHandle(thread, aTag)); bool success2 = serializer->SerializeJSTaggedValue(JSHandle(thread, minTag)); bool success3 = serializer->SerializeJSTaggedValue(JSHandle(thread, bTag)); EXPECT_TRUE(success1 && success2 && success3) << "Serialize Int32 fail"; std::pair data = serializer->ReleaseBuffer(); JSDeserializerTest jsDeserializerTest; std::thread t1(&JSDeserializerTest::Int32Test, jsDeserializerTest, data); t1.join(); }; HWTEST_F_L0(JSSerializerTest, SerializeDouble) { JSSerializer *serializer = new JSSerializer(thread); double a = 3.1415926535, b = -3.1415926535; JSTaggedValue aTag(a), bTag(b); bool success1 = serializer->SerializeJSTaggedValue(JSHandle(thread, aTag)); bool success2 = serializer->SerializeJSTaggedValue(JSHandle(thread, bTag)); EXPECT_TRUE(success1 && success2) << "Serialize Double fail"; std::pair data = serializer->ReleaseBuffer(); JSDeserializerTest jsDeserializerTest; std::thread t1(&JSDeserializerTest::DoubleTest, jsDeserializerTest, data); t1.join(); }; JSDate *JSDateCreate(EcmaVM *ecmaVM) { ObjectFactory *factory = ecmaVM->GetFactory(); JSHandle globalEnv = ecmaVM->GetGlobalEnv(); JSHandle dateFunction = globalEnv->GetDateFunction(); JSHandle dateObject = JSHandle::Cast(factory->NewJSObjectByConstructor(JSHandle(dateFunction), dateFunction)); return *dateObject; } HWTEST_F_L0(JSSerializerTest, SerializeDate) { double tm = 28 * 60 * 60 * 1000; JSHandle jsDate(thread, JSDateCreate(ecmaVm)); jsDate->SetTimeValue(thread, JSTaggedValue(tm)); JSSerializer *serializer = new JSSerializer(thread); bool success = serializer->SerializeJSTaggedValue(JSHandle::Cast(jsDate)); EXPECT_TRUE(success) << "Serialize JSDate fail"; std::pair data = serializer->ReleaseBuffer(); JSDeserializerTest jsDeserializerTest; std::thread t1(&JSDeserializerTest::JSDateTest, jsDeserializerTest, data); t1.join(); }; JSMap *CreateMap(JSThread *thread) { ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); JSHandle env = thread->GetEcmaVM()->GetGlobalEnv(); JSHandle constructor = env->GetBuiltinsMapFunction(); JSHandle map = JSHandle::Cast(factory->NewJSObjectByConstructor(JSHandle(constructor), constructor)); JSTaggedValue linkedMap = LinkedHashMap::Create(thread); map->SetLinkedMap(thread, linkedMap); return *map; } HWTEST_F_L0(JSSerializerTest, SerializeJSMap) { JSHandle map(thread, CreateMap(thread)); ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); JSHandle key1(factory->NewFromCanBeCompressString("3")); JSHandle value1(thread, JSTaggedValue(12345)); JSMap::Set(thread, map, key1, value1); JSHandle key2(factory->NewFromCanBeCompressString("key1")); JSHandle value2(thread, JSTaggedValue(34567)); JSMap::Set(thread, map, key2, value2); JSSerializer *serializer = new JSSerializer(thread); bool success = serializer->SerializeJSTaggedValue(JSHandle::Cast(map)); EXPECT_TRUE(success) << "Serialize JSMap fail"; std::pair data = serializer->ReleaseBuffer(); JSDeserializerTest jsDeserializerTest; std::thread t1(&JSDeserializerTest::JSMapTest, jsDeserializerTest, data, map); t1.join(); }; JSArrayBuffer *CreateJSArrayBuffer(JSThread *thread) { ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); JSHandle env = thread->GetEcmaVM()->GetGlobalEnv(); JSHandle target = env->GetArrayBufferFunction(); JSHandle jsArrayBuffer = JSHandle::Cast(factory->NewJSObjectByConstructor(JSHandle(target), target)); return *jsArrayBuffer; } HWTEST_F_L0(JSSerializerTest, SerializeJSArrayBuffer) { JSHandle jsArrayBuffer(thread, CreateJSArrayBuffer(thread)); int32_t byteLength = 10; thread->GetEcmaVM()->GetFactory()->NewJSArrayBufferData(jsArrayBuffer, byteLength); jsArrayBuffer->SetArrayBufferByteLength(thread, JSTaggedValue(static_cast(byteLength))); JSHandle obj = JSHandle(jsArrayBuffer); BuiltinsArrayBuffer::SetValueInBuffer(obj.GetTaggedValue(), 1, DataViewType::UINT8, JSTaggedNumber(7), true); BuiltinsArrayBuffer::SetValueInBuffer(obj.GetTaggedValue(), 3, DataViewType::UINT8, JSTaggedNumber(17), true); JSSerializer *serializer = new JSSerializer(thread); bool success = serializer->SerializeJSTaggedValue(JSHandle::Cast(jsArrayBuffer)); EXPECT_TRUE(success) << "Serialize JSArrayBuffer fail"; std::pair data = serializer->ReleaseBuffer(); JSDeserializerTest jsDeserializerTest; std::thread t1(&JSDeserializerTest::JSArrayBufferTest, jsDeserializerTest, data, jsArrayBuffer, 10, nullptr); t1.join(); }; HWTEST_F_L0(JSSerializerTest, SerializeJSArrayBufferShared) { std::string msg = "hello world"; int msgBufferLen = msg.length() + 1; char* msgBuffer = new char[msgBufferLen] { 0 }; if (memcpy_s(msgBuffer, msgBufferLen, msg.c_str(), msgBufferLen) != EOK) { delete[] msgBuffer; EXPECT_TRUE(false) << " memcpy error"; } ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); JSHandle jsArrayBuffer = factory->NewJSArrayBuffer(msgBuffer, msgBufferLen, nullptr, nullptr); JSSerializer *serializer = new JSSerializer(thread); bool success = serializer->SerializeJSTaggedValue(JSHandle::Cast(jsArrayBuffer)); EXPECT_TRUE(success) << "Serialize JSArrayBuffer fail"; std::pair data = serializer->ReleaseBuffer(); JSDeserializerTest jsDeserializerTest; std::thread t1(&JSDeserializerTest::JSArrayBufferTest, jsDeserializerTest, data, jsArrayBuffer, 12, nullptr); t1.join(); }; HWTEST_F_L0(JSSerializerTest, SerializeJSArrayBufferShared2) { std::string msg = "hello world"; int msgBufferLen = msg.length() + 1; char* msgBuffer = new char[msgBufferLen] { 0 }; if (memcpy_s(msgBuffer, msgBufferLen, msg.c_str(), msgBufferLen) != EOK) { delete[] msgBuffer; EXPECT_TRUE(false) << " memcpy error"; } ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); JSHandle jsArrayBuffer = factory->NewJSArrayBuffer(msgBuffer, msgBufferLen, nullptr, nullptr, true); JSSerializer *serializer = new JSSerializer(thread); bool success = serializer->SerializeJSTaggedValue(JSHandle::Cast(jsArrayBuffer)); EXPECT_TRUE(success) << "Serialize JSArrayBuffer fail"; std::pair data = serializer->ReleaseBuffer(); JSDeserializerTest jsDeserializerTest; std::string changeStr = "world hello"; std::thread t1(&JSDeserializerTest::JSArrayBufferTest, jsDeserializerTest, data, jsArrayBuffer, 12, changeStr.c_str()); t1.join(); EXPECT_TRUE(strcmp(msgBuffer, "world hello") == 0) << "Serialize JSArrayBuffer fail"; }; HWTEST_F_L0(JSSerializerTest, SerializeJSRegExp) { ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); JSHandle env = thread->GetEcmaVM()->GetGlobalEnv(); JSHandle target = env->GetRegExpFunction(); JSHandle jsRegexp = JSHandle::Cast(factory->NewJSObjectByConstructor(JSHandle(target), target)); JSHandle pattern = thread->GetEcmaVM()->GetFactory()->NewFromCanBeCompressString("key2"); JSHandle flags = thread->GetEcmaVM()->GetFactory()->NewFromCanBeCompressString("i"); char buffer[] = "1234567"; // use char to simulate bytecode uint32_t bufferSize = 7; factory->NewJSRegExpByteCodeData(jsRegexp, static_cast(buffer), bufferSize); jsRegexp->SetOriginalSource(thread, JSHandle(pattern)); jsRegexp->SetOriginalFlags(thread, JSHandle(flags)); JSSerializer *serializer = new JSSerializer(thread); bool success = serializer->SerializeJSTaggedValue(JSHandle::Cast(jsRegexp)); EXPECT_TRUE(success) << "Serialize JSRegExp fail"; std::pair data = serializer->ReleaseBuffer(); JSDeserializerTest jsDeserializerTest; std::thread t1(&JSDeserializerTest::JSRegexpTest, jsDeserializerTest, data); t1.join(); }; JSArrayBuffer *CreateTestJSArrayBuffer(JSThread *thread) { JSHandle jsArrayBuffer(thread, CreateJSArrayBuffer(thread)); int32_t byteLength = 10; thread->GetEcmaVM()->GetFactory()->NewJSArrayBufferData(jsArrayBuffer, byteLength); jsArrayBuffer->SetArrayBufferByteLength(thread, JSTaggedValue(static_cast(byteLength))); JSHandle obj = JSHandle(jsArrayBuffer); // 7 : test case BuiltinsArrayBuffer::SetValueInBuffer(obj.GetTaggedValue(), 1, DataViewType::UINT8, JSTaggedNumber(7), true); // 3, 17 : test case BuiltinsArrayBuffer::SetValueInBuffer(obj.GetTaggedValue(), 3, DataViewType::UINT8, JSTaggedNumber(17), true); return *jsArrayBuffer; } HWTEST_F_L0(JSSerializerTest, SerializeJSTypedArray) { ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); JSHandle env = thread->GetEcmaVM()->GetGlobalEnv(); JSHandle target = env->GetInt8ArrayFunction(); JSHandle int8Array = JSHandle::Cast(factory->NewJSObjectByConstructor(JSHandle(target), target)); JSHandle viewedArrayBuffer(thread, CreateTestJSArrayBuffer(thread)); int8Array->SetViewedArrayBuffer(thread, viewedArrayBuffer); int byteLength = 10; int byteOffset = 0; int arrayLength = (byteLength - byteOffset) / (sizeof(int8_t)); int8Array->SetByteLength(thread, JSTaggedValue(byteLength)); int8Array->SetByteOffset(thread, JSTaggedValue(byteOffset)); int8Array->SetTypedArrayName(thread, thread->GlobalConstants()->GetInt8ArrayString()); int8Array->SetArrayLength(thread, JSTaggedValue(arrayLength)); JSSerializer *serializer = new JSSerializer(thread); bool success = serializer->SerializeJSTaggedValue(JSHandle::Cast(int8Array)); EXPECT_TRUE(success); std::pair data = serializer->ReleaseBuffer(); JSDeserializerTest jsDeserializerTest; std::thread t1(&JSDeserializerTest::TypedArrayTest, jsDeserializerTest, data, int8Array); t1.join(); }; // not support function HWTEST_F_L0(JSSerializerTest, SerializeObjectWithFunction) { ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); JSHandle env = thread->GetEcmaVM()->GetGlobalEnv(); JSHandle function = env->GetRegExpFunction(); EXPECT_TRUE(function->IsJSFunction()); JSHandle key(factory->NewFromCanBeCompressString("2")); JSHandle obj = factory->NewEmptyJSObject(); JSObject::SetProperty(thread, JSHandle(obj), key, function); JSSerializer *serializer = new JSSerializer(thread); bool success = serializer->SerializeJSTaggedValue(JSHandle(obj)); EXPECT_FALSE(success); std::pair data = serializer->ReleaseBuffer(); JSDeserializer deserializer(thread, data.first, data.second); JSHandle ret = deserializer.DeserializeJSTaggedValue(); EXPECT_TRUE(ret.IsEmpty()); }; // not support symbol HWTEST_F_L0(JSSerializerTest, SerializeSymbolWithProperty) { ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); JSHandle jsSymbol = factory->NewJSSymbol(); JSHandle key1(factory->NewFromCanBeCompressString("2")); JSHandle key2(factory->NewFromCanBeCompressString("x")); JSHandle value1(thread, JSTaggedValue(1)); JSHandle value2(thread, JSTaggedValue(8)); JSObject::SetProperty(thread, JSHandle(jsSymbol), key1, value1); JSObject::SetProperty(thread, JSHandle(jsSymbol), key2, value2); JSSerializer *serializer = new JSSerializer(thread); bool success = serializer->SerializeJSTaggedValue(JSHandle(jsSymbol)); EXPECT_FALSE(success); std::pair data = serializer->ReleaseBuffer(); JSDeserializer deserializer(thread, data.first, data.second); JSHandle ret = deserializer.DeserializeJSTaggedValue(); EXPECT_TRUE(ret.IsEmpty()); }; } // namespace panda::test