* 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/base/json_parser.h"
#include "ecmascript/base/json_helper.h"
#include "ecmascript/ecma_string.h"
#include "ecmascript/ecma_string-inl.h"
#include "ecmascript/tests/test_helper.h"
#include <algorithm>
#include <string>
using namespace panda::ecmascript;
using namespace panda::ecmascript::base;
namespace panda::test {
class JsonParserTest : public BaseTestWithScope<false> {
public:
using TransformType = base::JsonHelper::TransformType;
static inline void FreeExternalStringData([[maybe_unused]] void *data, void *hint)
{
delete[] reinterpret_cast<uint8_t *>(hint);
}
JSHandle<EcmaString> NewExternalUtf8String(const std::string &text)
{
auto *data = new uint8_t[text.size()];
std::copy(text.begin(), text.end(), data);
EcmaString *str = EcmaStringAccessor::CreateFromExternalResource(thread->GetEcmaVM(), data, text.size(),
true, FreeExternalStringData, data);
return JSHandle<EcmaString>(thread, str);
}
JSHandle<EcmaString> NewExternalUtf16String(const std::u16string &text)
{
size_t byteLength = text.size() * sizeof(uint16_t);
auto *storage = new uint8_t[byteLength];
auto *data = reinterpret_cast<uint16_t *>(storage);
std::copy(text.begin(), text.end(), data);
EcmaString *str = EcmaStringAccessor::CreateFromExternalResource(thread->GetEcmaVM(), data, text.size(),
false, FreeExternalStringData, storage);
return JSHandle<EcmaString>(thread, str);
}
JSHandle<EcmaString> NewSlicedString(const JSHandle<EcmaString> &parent, uint32_t start, uint32_t length)
{
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
JSHandle<EcmaString> slicedString(thread,
factory->AllocSlicedStringObject(MemSpaceType::SHARED_OLD_SPACE));
auto *sliced = reinterpret_cast<SlicedEcmaString *>(*slicedString);
sliced->ToSlicedString()->InitLengthAndFlags(length, EcmaStringAccessor(parent).IsUtf8());
sliced->SetParent(thread, parent);
sliced->SetStartIndex(start);
return slicedString;
}
JSHandle<JSTaggedValue> ParseJsonString(const JSHandle<EcmaString> &str)
{
if (EcmaStringAccessor(str).IsUtf8()) {
Utf8JsonParser parser(thread, TransformType::NORMAL);
return parser.Parse(str);
}
Utf16JsonParser parser(thread, TransformType::NORMAL);
return parser.Parse(*str);
}
void ExpectJsonPropertyNumber(const JSHandle<JSTaggedValue> &object, const char *key, int32_t expected)
{
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
JSHandle<JSTaggedValue> keyHandle(factory->NewFromASCII(key));
JSHandle<JSTaggedValue> value = JSTaggedValue::GetProperty(thread, object, keyHandle).GetValue();
ASSERT_TRUE(value->IsNumber());
EXPECT_EQ(value->GetNumber(), expected);
}
void ExpectJsonPropertyNumber(const JSHandle<JSTaggedValue> &object, const JSHandle<EcmaString> &key,
int32_t expected)
{
JSHandle<JSTaggedValue> keyHandle = JSHandle<JSTaggedValue>::Cast(key);
JSHandle<JSTaggedValue> value = JSTaggedValue::GetProperty(thread, object, keyHandle).GetValue();
ASSERT_TRUE(value->IsNumber());
EXPECT_EQ(value->GetNumber(), expected);
}
void ExpectJsonPropertyString(const JSHandle<JSTaggedValue> &object, const char *key, const char *expected)
{
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
JSHandle<JSTaggedValue> keyHandle(factory->NewFromASCII(key));
JSHandle<JSTaggedValue> value = JSTaggedValue::GetProperty(thread, object, keyHandle).GetValue();
ASSERT_TRUE(value->IsString());
JSHandle<EcmaString> stringValue(value);
EXPECT_STREQ(expected, EcmaStringAccessor(stringValue).ToCString(thread).c_str());
}
void ExpectParsedJsonObject(const JSHandle<EcmaString> &str, const char *kind, int32_t value)
{
JSHandle<JSTaggedValue> result = ParseJsonString(str);
ASSERT_FALSE(result->IsException());
ASSERT_TRUE(result->IsECMAObject());
ExpectJsonPropertyString(result, "kind", kind);
ExpectJsonPropertyNumber(result, "value", value);
}
void CheckUnsupportedSendableJson(JSThread *thread, JSHandle<JSTaggedValue> &result) const
{
EXPECT_TRUE(result->IsException());
JSHandle<JSTaggedValue> exceptionObj(thread, thread->GetException());
auto messageValue =
JSTaggedValue::GetProperty(thread, exceptionObj, thread->GlobalConstants()->GetHandledMessageString())
.GetValue();
EXPECT_EQ(ConvertToString(thread, EcmaString::Cast(messageValue->GetTaggedObject())),
MessageString::GetMessageString(GET_MESSAGE_STRING_ID(SendableArrayForJson)).c_str());
}
bool CheckSendableConstraint(const JSThread *thread, JSTaggedValue value) const
{
if (!value.IsHeapObject()) {
return true;
}
TaggedObject *obj = value.IsWeak() ? value.GetTaggedWeakRef() : value.GetTaggedObject();
auto *jsHClass = obj->GetClass();
if (!jsHClass->IsJSShared()) {
return false;
}
if (jsHClass->IsExtensible()) {
LOG_ECMA(ERROR) << "sendable check failed. obj is extensible";
value.D(thread);
return false;
}
if (!CheckSendableProps(thread, value, obj)) {
return false;
}
auto proto = jsHClass->GetPrototype(thread);
if (!proto.IsNull() && !proto.IsJSShared()) {
LOG_ECMA(ERROR) << "sendable check failed. proto is not sendable.";
value.D(thread);
return false;
}
return true;
}
bool CheckSendableProps(const JSThread *thread, JSTaggedValue value, TaggedObject *obj) const
{
auto *jsHClass = obj->GetClass();
auto layoutValue = jsHClass->GetLayout(thread);
if (layoutValue.IsNull()) {
return true;
}
auto *layoutInfo = LayoutInfo::Cast(layoutValue.GetTaggedObject());
auto *jsObj = JSObject::Cast(obj);
auto *propsValue = TaggedArray::Cast(jsObj->GetProperties(thread));
if (propsValue->IsDictionaryMode()) {
for (int idx = 0; idx < static_cast<int>(jsHClass->NumberOfProps()); idx++) {
auto attr = layoutInfo->GetAttr(thread, idx);
if (attr.IsInlinedProps()) {
continue;
}
if (attr.IsWritable()) {
LOG_ECMA(ERROR) << "sendable check failed. supposed to be un-writable. idx: " << idx;
value.D(thread);
return false;
}
auto val = propsValue->Get(thread, idx - jsHClass->GetInlinedProperties());
if (!CheckSendableConstraint(thread, val)) {
LOG_ECMA(ERROR) << "sendable check failed. supposed to be sendable. idx: " << idx;
value.D(thread);
return false;
}
}
}
return true;
}
};
* @tc.name: Parser_001
* @tc.desc: Passing in a character of type "uint8_t" check whether the result returned through "ParserUtf8" function
* Test without for no Nesting.
* @tc.type: FUNC
* @tc.require:
*/
HWTEST_F_L0(JsonParserTest, Parser_001)
{
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
Utf8JsonParser parser(thread, TransformType::NORMAL);
JSHandle<JSTaggedValue> handleMsg2(factory->NewFromASCII("1234"));
JSHandle<EcmaString> handleStr2(JSTaggedValue::ToString(thread, handleMsg2));
JSHandle<JSTaggedValue> result2 = parser.Parse(handleStr2);
EXPECT_EQ(result2->GetNumber(), 1234);
JSHandle<JSTaggedValue> handleMsg3(factory->NewFromASCII("true"));
JSHandle<EcmaString> handleStr3(JSTaggedValue::ToString(thread, handleMsg3));
JSHandle<JSTaggedValue> result3 = parser.Parse(handleStr3);
EXPECT_EQ(result3.GetTaggedValue(), JSTaggedValue::True());
JSHandle<JSTaggedValue> handleMsg4(factory->NewFromASCII("trus"));
JSHandle<EcmaString> handleStr4(JSTaggedValue::ToString(thread, handleMsg4));
JSHandle<JSTaggedValue> result4 = parser.Parse(handleStr4);
EXPECT_EQ(result4.GetTaggedValue(), JSTaggedValue::Exception());
}
* @tc.name: Parser_002
* @tc.desc: Passing in a character of type "uint16_t" check whether the result returned through "ParseUtf16" function
* Test without for no Nesting.
* @tc.type: FUNC
* @tc.require:
*/
HWTEST_F_L0(JsonParserTest, Parser_002)
{
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
Utf16JsonParser parser(thread, TransformType::NORMAL);
uint16_t array1Utf16[] = {0x31, 0x32, 0x33, 0x34};
uint32_t array1Utf16Len = sizeof(array1Utf16) / sizeof(array1Utf16[0]);
JSHandle<JSTaggedValue> handleMsg2(factory->NewFromUtf16(&array1Utf16[0], array1Utf16Len));
JSHandle<EcmaString> handleStr2(JSTaggedValue::ToString(thread, handleMsg2));
JSHandle<JSTaggedValue> result2 = parser.Parse(*handleStr2);
EXPECT_EQ(result2->GetNumber(), 1234);
uint16_t array2Utf16[] = {0x74, 0x72, 0x75, 0x65};
uint32_t array2Utf16Len = sizeof(array2Utf16) / sizeof(array2Utf16[0]);
JSHandle<JSTaggedValue> handleMsg3(factory->NewFromUtf16(&array2Utf16[0], array2Utf16Len));
JSHandle<EcmaString> handleStr3(JSTaggedValue::ToString(thread, handleMsg3));
JSHandle<JSTaggedValue> result3 = parser.Parse(*handleStr3);
EXPECT_EQ(result3.GetTaggedValue(), JSTaggedValue::True());
uint16_t array3Utf16[] = {0x22, 0x73, 0x74, 0x72, 0x69, 0x6E, 0X67, 0x22};
uint32_t array3Utf16Len = sizeof(array3Utf16) / sizeof(array3Utf16[0]);
JSHandle<JSTaggedValue> handleMsg4(factory->NewFromUtf16(&array3Utf16[0], array3Utf16Len));
JSHandle<EcmaString> handleStr4(JSTaggedValue::ToString(thread, handleMsg4));
JSHandle<JSTaggedValue> result4 = parser.Parse(*handleStr4);
JSHandle<EcmaString> handleEcmaStr(result4);
EXPECT_STREQ("string", EcmaStringAccessor(handleEcmaStr).ToCString(thread).c_str());
}
* @tc.name: Parser_003
* @tc.desc: Passing in a character of type "uint8_t" check whether the result returned through "ParserUtf8" function
* Test with for Nesting of numbers, strings, objects, arrays, Booleans.
* @tc.type: FUNC
* @tc.require:
*/
HWTEST_F_L0(JsonParserTest, Parser_003)
{
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
Utf8JsonParser parser(thread, TransformType::NORMAL);
JSHandle<JSTaggedValue> handleMsg(factory->NewFromASCII(
"\t\r \n{\t\r \n \"json\"\t\r\n:\t\r \n{\t\r \n}\t\r \n,\t\r \n \"prop2\"\t\r \n:\t\r \n [\t\r \nfalse\t\r"
"\n,\t\r \nnull\t\r, \ntrue\t\r,123.456\t\r \n]\t\r \n}\t\r \n"));
JSHandle<EcmaString> handleStr(JSTaggedValue::ToString(thread, handleMsg));
JSHandle<JSTaggedValue> result = parser.Parse(handleStr);
EXPECT_TRUE(result->IsECMAObject());
}
* @tc.name: Parser_004
* @tc.desc: Passing in a character of type "uint8_t" check whether the result returned through "ParserUtf8" function
* Test with for Nesting of numbers, strings, arrays.
* @tc.type: FUNC
* @tc.require:
*/
HWTEST_F_L0(JsonParserTest, Parser_004)
{
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
JSHandle<JSTaggedValue> lengthKeyHandle = thread->GlobalConstants()->GetHandledLengthString();
Utf8JsonParser parser(thread, TransformType::NORMAL);
JSHandle<JSTaggedValue> handleMsg(factory->NewFromASCII("[100,2.5,\"abc\"]"));
JSHandle<EcmaString> handleStr(JSTaggedValue::ToString(thread, handleMsg));
JSHandle<JSTaggedValue> result = parser.Parse(handleStr);
JSTaggedValue resultValue(static_cast<JSTaggedType>(result->GetRawData()));
EXPECT_TRUE(resultValue.IsECMAObject());
JSHandle<JSObject> valueHandle(thread, resultValue);
JSHandle<JSTaggedValue> lenResult =
JSObject::GetProperty(thread, JSHandle<JSTaggedValue>(valueHandle), lengthKeyHandle).GetValue();
uint32_t length = JSTaggedValue::ToLength(thread, lenResult).ToUint32();
EXPECT_EQ(length, 3U);
}
* @tc.name: Parser_005
* @tc.desc: Passing in a character of type "uint8_t" check whether the result returned through "ParserUtf8" function
* Test without for Nesting of numbers, strings, objects.
* @tc.type: FUNC
* @tc.require:
*/
HWTEST_F_L0(JsonParserTest, Parser_005)
{
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
Utf8JsonParser parser(thread, TransformType::NORMAL);
JSHandle<JSTaggedValue> handleMsg(factory->NewFromASCII("{\"epf\":100,\"key1\":400}"));
JSHandle<EcmaString> handleStr(JSTaggedValue::ToString(thread, handleMsg));
JSHandle<JSTaggedValue> result = parser.Parse(handleStr);
JSTaggedValue resultValue(static_cast<JSTaggedType>(result->GetRawData()));
EXPECT_TRUE(resultValue.IsECMAObject());
JSHandle<JSObject> valueHandle(thread, resultValue);
JSHandle<TaggedArray> nameList(JSObject::EnumerableOwnNames(thread, valueHandle));
JSHandle<JSArray> nameResult = JSArray::CreateArrayFromList(thread, nameList);
JSHandle<JSTaggedValue> handleKey(nameResult);
JSHandle<JSTaggedValue> lengthKey(factory->NewFromASCII("length"));
JSHandle<JSTaggedValue> lenResult = JSObject::GetProperty(thread, handleKey, lengthKey).GetValue();
uint32_t length = JSTaggedValue::ToLength(thread, lenResult).ToUint32();
EXPECT_EQ(length, 2U);
}
* @tc.name: Parser_006
* @tc.desc: Try to parse a empty string.
* @tc.type: FUNC
* @tc.require:
*/
HWTEST_F_L0(JsonParserTest, Parser_006)
{
Utf8JsonParser parser(thread, TransformType::NORMAL);
JSHandle<EcmaString> emptyString(thread->GlobalConstants()->GetHandledEmptyString());
JSHandle<JSTaggedValue> result = parser.Parse(emptyString);
EXPECT_TRUE(result->IsException());
}
* @tc.name: Parser_007
* @tc.desc: Try to parse a string containing an empty string.
* @tc.type: FUNC
* @tc.require:
*/
HWTEST_F_L0(JsonParserTest, Parser_007)
{
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
Utf8JsonParser parser(thread, TransformType::NORMAL);
JSHandle<EcmaString> handleStr(factory->NewFromASCII("\"\""));
JSHandle<JSTaggedValue> result = parser.Parse(handleStr);
EXPECT_FALSE(result->IsException());
}
* @tc.name: Parser_008
* @tc.desc: Try to parse a string to sendable object.
* @tc.type: FUNC
* @tc.require:
*/
HWTEST_F_L0(JsonParserTest, Parser_008)
{
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
Utf8JsonParser parser(thread, TransformType::SENDABLE);
JSHandle<JSTaggedValue> handleMsg(
factory->NewFromASCII(R"({"innerEntry": {"x":1, "y":"abc", "str": "innerStr"}, "x": 1, "str": "outerStr"})"));
JSHandle<EcmaString> handleStr(JSTaggedValue::ToString(thread, handleMsg));
JSHandle<JSTaggedValue> result = parser.Parse(handleStr);
result->D(thread);
EXPECT_FALSE(result->IsException());
EXPECT_TRUE(CheckSendableConstraint(thread, result.GetTaggedValue()));
}
* @tc.name: Parser_009
* @tc.desc: Try to parse a empty obj json string to sendable object.
* @tc.type: FUNC
* @tc.require:
*/
HWTEST_F_L0(JsonParserTest, Parser_009)
{
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
Utf8JsonParser parser(thread, TransformType::SENDABLE);
JSHandle<JSTaggedValue> handleMsg(factory->NewFromASCII(R"({})"));
JSHandle<EcmaString> handleStr(JSTaggedValue::ToString(thread, handleMsg));
JSHandle<JSTaggedValue> result = parser.Parse(handleStr);
result->D(thread);
EXPECT_TRUE(CheckSendableConstraint(thread, result.GetTaggedValue()));
}
* @tc.name: Parser_010
* @tc.desc: Try to parse a empty array json string to sendable object.
* @tc.type: FUNC
* @tc.require:
*/
HWTEST_F_L0(JsonParserTest, Parser_010)
{
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
Utf8JsonParser parser(thread, TransformType::SENDABLE);
JSHandle<JSTaggedValue> handleMsg(factory->NewFromASCII(R"([])"));
JSHandle<EcmaString> handleStr(JSTaggedValue::ToString(thread, handleMsg));
JSHandle<JSTaggedValue> result = parser.Parse(handleStr);
result->D(thread);
EXPECT_TRUE(CheckSendableConstraint(thread, result.GetTaggedValue()));
}
* @tc.name: Parser_011
* @tc.desc: Try to parse a simple array json string to sendable object.
* @tc.type: FUNC
* @tc.require:
*/
HWTEST_F_L0(JsonParserTest, Parser_011)
{
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
Utf8JsonParser parser(thread, TransformType::SENDABLE);
JSHandle<JSTaggedValue> handleMsg(factory->NewFromASCII(R"([1, 2, 3])"));
JSHandle<EcmaString> handleStr(JSTaggedValue::ToString(thread, handleMsg));
JSHandle<JSTaggedValue> result = parser.Parse(handleStr);
result->D(thread);
EXPECT_TRUE(CheckSendableConstraint(thread, result.GetTaggedValue()));
}
* @tc.name: Parser_012
* @tc.desc: Try to parse a json string with array to sendable object.
* @tc.type: FUNC
* @tc.require:
*/
HWTEST_F_L0(JsonParserTest, Parser_012)
{
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
Utf8JsonParser parser(thread, TransformType::SENDABLE);
JSHandle<JSTaggedValue> handleMsg(
factory->NewFromASCII(R"({"innerEntry": {"array": [1, 2, 3]}, "x": 1, "str": "outerStr"})"));
JSHandle<EcmaString> handleStr(JSTaggedValue::ToString(thread, handleMsg));
JSHandle<JSTaggedValue> result = parser.Parse(handleStr);
result->D(thread);
EXPECT_TRUE(CheckSendableConstraint(thread, result.GetTaggedValue()));
}
* @tc.name: Parser_013
* @tc.desc: Test ParseStringWithBackslash - basic escape sequences with content verification
* @tc.type: FUNC
* @tc.require:
*/
HWTEST_F_L0(JsonParserTest, Parser_013)
{
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
{
Utf8JsonParser parser(thread, TransformType::NORMAL);
JSHandle<JSTaggedValue> handleMsg(factory->NewFromASCII(R"({"key": "hello\nworld"})"));
JSHandle<EcmaString> handleStr(JSTaggedValue::ToString(thread, handleMsg));
JSHandle<JSTaggedValue> result = parser.Parse(handleStr);
EXPECT_FALSE(result->IsException());
JSHandle<JSTaggedValue> keyStr(factory->NewFromASCII("key"));
JSHandle<JSTaggedValue> value = JSObject::GetProperty(thread, result, keyStr).GetValue();
JSHandle<EcmaString> valueStr(JSTaggedValue::ToString(thread, value));
EXPECT_EQ(EcmaStringAccessor(valueStr).GetLength(), 11U);
}
{
Utf8JsonParser parser(thread, TransformType::NORMAL);
JSHandle<JSTaggedValue> handleMsg(factory->NewFromASCII(R"({"key": "hello\tworld"})"));
JSHandle<EcmaString> handleStr(JSTaggedValue::ToString(thread, handleMsg));
JSHandle<JSTaggedValue> result = parser.Parse(handleStr);
EXPECT_FALSE(result->IsException());
JSHandle<JSTaggedValue> keyStr(factory->NewFromASCII("key"));
JSHandle<JSTaggedValue> value = JSObject::GetProperty(thread, result, keyStr).GetValue();
JSHandle<EcmaString> valueStr(JSTaggedValue::ToString(thread, value));
EXPECT_EQ(EcmaStringAccessor(valueStr).GetLength(), 11U);
}
{
Utf8JsonParser parser(thread, TransformType::NORMAL);
JSHandle<JSTaggedValue> handleMsg(factory->NewFromASCII(R"({"key": "hello\\world"})"));
JSHandle<EcmaString> handleStr(JSTaggedValue::ToString(thread, handleMsg));
JSHandle<JSTaggedValue> result = parser.Parse(handleStr);
EXPECT_FALSE(result->IsException());
JSHandle<JSTaggedValue> keyStr(factory->NewFromASCII("key"));
JSHandle<JSTaggedValue> value = JSObject::GetProperty(thread, result, keyStr).GetValue();
JSHandle<EcmaString> valueStr(JSTaggedValue::ToString(thread, value));
EXPECT_EQ(EcmaStringAccessor(valueStr).GetLength(), 11U);
}
{
Utf8JsonParser parser(thread, TransformType::NORMAL);
JSHandle<JSTaggedValue> handleMsg(factory->NewFromASCII(R"({"key": "hello\"world123456"})"));
JSHandle<EcmaString> handleStr(JSTaggedValue::ToString(thread, handleMsg));
JSHandle<JSTaggedValue> result = parser.Parse(handleStr);
EXPECT_FALSE(result->IsException());
JSHandle<JSTaggedValue> keyStr(factory->NewFromASCII("key"));
JSHandle<JSTaggedValue> value = JSObject::GetProperty(thread, result, keyStr).GetValue();
JSHandle<EcmaString> valueStr(JSTaggedValue::ToString(thread, value));
EXPECT_EQ(EcmaStringAccessor(valueStr).GetLength(), 17U);
}
}
* @tc.name: Parser_014
* @tc.desc: Unicode escape sequences with content verification
* @tc.type: FUNC
* @tc.require:
*/
HWTEST_F_L0(JsonParserTest, Parser_014)
{
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
{
Utf8JsonParser parser(thread, TransformType::NORMAL);
JSHandle<JSTaggedValue> handleMsg(factory->NewFromASCII(R"({"key": "\u0041"})"));
JSHandle<EcmaString> handleStr(JSTaggedValue::ToString(thread, handleMsg));
JSHandle<JSTaggedValue> result = parser.Parse(handleStr);
EXPECT_FALSE(result->IsException());
JSHandle<JSTaggedValue> keyStr(factory->NewFromASCII("key"));
JSHandle<JSTaggedValue> value = JSObject::GetProperty(thread, result, keyStr).GetValue();
JSHandle<EcmaString> valueStr(JSTaggedValue::ToString(thread, value));
EXPECT_EQ(EcmaStringAccessor(valueStr).GetLength(), 1U);
EXPECT_STREQ(EcmaStringAccessor(valueStr).ToCString(thread).c_str(), "A");
}
{
Utf8JsonParser parser(thread, TransformType::NORMAL);
JSHandle<JSTaggedValue> handleMsg(factory->NewFromASCII(R"({"key": "\u4e2d\u6587"})"));
JSHandle<EcmaString> handleStr(JSTaggedValue::ToString(thread, handleMsg));
JSHandle<JSTaggedValue> result = parser.Parse(handleStr);
EXPECT_FALSE(result->IsException());
JSHandle<JSTaggedValue> keyStr(factory->NewFromASCII("key"));
JSHandle<JSTaggedValue> value = JSObject::GetProperty(thread, result, keyStr).GetValue();
JSHandle<EcmaString> valueStr(JSTaggedValue::ToString(thread, value));
EXPECT_EQ(EcmaStringAccessor(valueStr).GetLength(), 2U);
std::string expectStr = "中文";
EXPECT_STREQ(EcmaStringAccessor(valueStr).ToCString(thread).c_str(), expectStr.c_str());
}
{
Utf8JsonParser parser(thread, TransformType::NORMAL);
JSHandle<JSTaggedValue> handleMsg(factory->NewFromASCII(R"({"key": "hello\u0041world"})"));
JSHandle<EcmaString> handleStr(JSTaggedValue::ToString(thread, handleMsg));
JSHandle<JSTaggedValue> result = parser.Parse(handleStr);
EXPECT_FALSE(result->IsException());
JSHandle<JSTaggedValue> keyStr(factory->NewFromASCII("key"));
JSHandle<JSTaggedValue> value = JSObject::GetProperty(thread, result, keyStr).GetValue();
JSHandle<EcmaString> valueStr(JSTaggedValue::ToString(thread, value));
EXPECT_EQ(EcmaStringAccessor(valueStr).GetLength(), 11U);
}
{
Utf8JsonParser parser(thread, TransformType::NORMAL);
JSHandle<JSTaggedValue> handleMsg(factory->NewFromASCII(R"({"key": "hello\u0000"})"));
JSHandle<EcmaString> handleStr(JSTaggedValue::ToString(thread, handleMsg));
JSHandle<JSTaggedValue> result = parser.Parse(handleStr);
EXPECT_FALSE(result->IsException());
JSHandle<JSTaggedValue> keyStr(factory->NewFromASCII("key"));
JSHandle<JSTaggedValue> value = JSObject::GetProperty(thread, result, keyStr).GetValue();
JSHandle<EcmaString> valueStr(JSTaggedValue::ToString(thread, value));
EXPECT_EQ(EcmaStringAccessor(valueStr).GetLength(), 6U);
}
}
* @tc.name: Parser_015
* @tc.desc: invalid escape sequences should fail
* @tc.type: FUNC
* @tc.require:
*/
HWTEST_F_L0(JsonParserTest, Parser_015)
{
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
{
Utf8JsonParser parser(thread, TransformType::NORMAL);
JSHandle<JSTaggedValue> handleMsg(factory->NewFromASCII(R"({"key": "hello\xworld"})"));
JSHandle<EcmaString> handleStr(JSTaggedValue::ToString(thread, handleMsg));
JSHandle<JSTaggedValue> result = parser.Parse(handleStr);
EXPECT_TRUE(result->IsException());
}
{
Utf8JsonParser parser(thread, TransformType::NORMAL);
JSHandle<JSTaggedValue> handleMsg(factory->NewFromASCII(R"({"key": "\u004"})"));
JSHandle<EcmaString> handleStr(JSTaggedValue::ToString(thread, handleMsg));
JSHandle<JSTaggedValue> result = parser.Parse(handleStr);
EXPECT_TRUE(result->IsException());
}
}
* @tc.name: Parser_016
* @tc.desc: invalid escape sequences should fail
* @tc.type: FUNC
* @tc.require:
*/
HWTEST_F_L0(JsonParserTest, Parser_016)
{
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
Utf8JsonParser parser(thread, TransformType::NORMAL);
const char* longJson =
R"({"longKey": "\u8fd9\u662f\u4e00\u4e2a\u957f\u5ea6\u8d85\u8fc7\u5341)"
R"(\u516d\u5b57\u7b26\u7684\u6d4b\u8bd5\u5b57\u7b26\u4e32\uff0c\u5305\u542b)"
R"(\u4e2d\u6587"})";
JSHandle<JSTaggedValue> handleMsg(factory->NewFromASCII(longJson));
JSHandle<EcmaString> handleStr(JSTaggedValue::ToString(thread, handleMsg));
JSHandle<JSTaggedValue> result = parser.Parse(handleStr);
EXPECT_FALSE(result->IsException());
JSHandle<JSTaggedValue> keyStr(factory->NewFromASCII("longKey"));
JSHandle<JSTaggedValue> value = JSObject::GetProperty(thread, result, keyStr).GetValue();
JSHandle<EcmaString> valueStr(JSTaggedValue::ToString(thread, value));
EXPECT_GT(EcmaStringAccessor(valueStr).GetLength(), 16U);
std::string expected = "这是一个长度超过十六字符的测试字符串,包含中文";
EXPECT_STREQ(EcmaStringAccessor(valueStr).ToCString(thread).c_str(), expected.c_str());
}
}