1/* 2 * Copyright (c) 2021 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16#include "ecmascript/base/json_parser.h" 17#include "ecmascript/base/json_helper.h" 18#include "ecmascript/ecma_string.h" 19#include "ecmascript/tests/test_helper.h" 20 21using namespace panda::ecmascript; 22using namespace panda::ecmascript::base; 23 24namespace panda::test { 25class JsonParserTest : public BaseTestWithScope<false> { 26public: 27 using TransformType = base::JsonHelper::TransformType; 28 29 void CheckUnsupportedSendableJson(JSHandle<JSTaggedValue> &result) const 30 { 31 EXPECT_TRUE(result->IsException()); 32 JSHandle<JSTaggedValue> exceptionObj(thread, thread->GetException()); 33 auto messageValue = 34 JSTaggedValue::GetProperty(thread, exceptionObj, thread->GlobalConstants()->GetHandledMessageString()) 35 .GetValue(); 36 EXPECT_EQ(ConvertToString(EcmaString::Cast(messageValue->GetTaggedObject())), 37 MessageString::GetMessageString(GET_MESSAGE_STRING_ID(SendableArrayForJson)).c_str()); 38 } 39 40 bool CheckSendableConstraint(JSTaggedValue value) const 41 { 42 if (!value.IsHeapObject()) { 43 // tagged value always follow sendable constraint. 44 return true; 45 } 46 TaggedObject *obj = value.IsWeak() ? value.GetTaggedWeakRef() : value.GetTaggedObject(); 47 auto *jsHClass = obj->GetClass(); 48 if (!jsHClass->IsJSShared()) { 49 return false; 50 } 51 if (jsHClass->IsExtensible()) { 52 LOG_ECMA(ERROR) << "sendable check failed. obj is extensible"; 53 value.D(); 54 return false; 55 } 56 if (!CheckSendableProps(value, obj)) { 57 return false; 58 } 59 // trace proto chain 60 auto proto = jsHClass->GetPrototype(); 61 if (!proto.IsNull() && !proto.IsJSShared()) { 62 LOG_ECMA(ERROR) << "sendable check failed. proto is not sendable."; 63 value.D(); 64 return false; 65 } 66 return true; 67 } 68 69 bool CheckSendableProps(JSTaggedValue value, TaggedObject *obj) const 70 { 71 auto *jsHClass = obj->GetClass(); 72 auto layoutValue = jsHClass->GetLayout(); 73 if (layoutValue.IsNull()) { 74 return true; 75 } 76 auto *layoutInfo = LayoutInfo::Cast(layoutValue.GetTaggedObject()); 77 auto *jsObj = JSObject::Cast(obj); 78 auto *propsValue = TaggedArray::Cast(jsObj->GetProperties()); 79 if (propsValue->IsDictionaryMode()) { 80 for (int idx = 0; idx < static_cast<int>(jsHClass->NumberOfProps()); idx++) { 81 auto attr = layoutInfo->GetAttr(idx); 82 if (attr.IsInlinedProps()) { 83 // Do not check inline props 84 continue; 85 } 86 if (attr.IsWritable()) { 87 LOG_ECMA(ERROR) << "sendable check failed. supposed to be un-writable. idx: " << idx; 88 value.D(); 89 return false; 90 } 91 auto val = propsValue->Get(thread, idx - jsHClass->GetInlinedProperties()); 92 if (!CheckSendableConstraint(val)) { 93 LOG_ECMA(ERROR) << "sendable check failed. supposed to be sendable. idx: " << idx; 94 value.D(); 95 return false; 96 } 97 } 98 } 99 return true; 100 } 101}; 102 103/** 104 * @tc.name: Parser_001 105 * @tc.desc: Passing in a character of type "uint8_t" check whether the result returned through "ParserUtf8" function 106 * Test without for no Nesting. 107 * @tc.type: FUNC 108 * @tc.require: 109 */ 110HWTEST_F_L0(JsonParserTest, Parser_001) 111{ 112 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); 113 Utf8JsonParser parser(thread, TransformType::NORMAL); 114 // JSON Number 115 JSHandle<JSTaggedValue> handleMsg2(factory->NewFromASCII("1234")); 116 JSHandle<EcmaString> handleStr2(JSTaggedValue::ToString(thread, handleMsg2)); 117 JSHandle<JSTaggedValue> result2 = parser.Parse(handleStr2); 118 EXPECT_EQ(result2->GetNumber(), 1234); 119 // JSON Literal 120 JSHandle<JSTaggedValue> handleMsg3(factory->NewFromASCII("true")); 121 JSHandle<EcmaString> handleStr3(JSTaggedValue::ToString(thread, handleMsg3)); 122 JSHandle<JSTaggedValue> result3 = parser.Parse(handleStr3); 123 EXPECT_EQ(result3.GetTaggedValue(), JSTaggedValue::True()); 124 // JSON Unexpected 125 JSHandle<JSTaggedValue> handleMsg4(factory->NewFromASCII("trus")); 126 JSHandle<EcmaString> handleStr4(JSTaggedValue::ToString(thread, handleMsg4)); 127 JSHandle<JSTaggedValue> result4 = parser.Parse(handleStr4); 128 EXPECT_EQ(result4.GetTaggedValue(), JSTaggedValue::Exception()); 129} 130 131/** 132 * @tc.name: Parser_002 133 * @tc.desc: Passing in a character of type "uint16_t" check whether the result returned through "ParseUtf16" function 134 * Test without for no Nesting. 135 * @tc.type: FUNC 136 * @tc.require: 137 */ 138HWTEST_F_L0(JsonParserTest, Parser_002) 139{ 140 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); 141 Utf16JsonParser parser(thread, TransformType::NORMAL); 142 143 // JSON Number 144 uint16_t array1Utf16[] = {0x31, 0x32, 0x33, 0x34}; // "1234" 145 uint32_t array1Utf16Len = sizeof(array1Utf16) / sizeof(array1Utf16[0]); 146 JSHandle<JSTaggedValue> handleMsg2(factory->NewFromUtf16(&array1Utf16[0], array1Utf16Len)); 147 JSHandle<EcmaString> handleStr2(JSTaggedValue::ToString(thread, handleMsg2)); 148 JSHandle<JSTaggedValue> result2 = parser.Parse(*handleStr2); 149 EXPECT_EQ(result2->GetNumber(), 1234); 150 // JSON Literal 151 uint16_t array2Utf16[] = {0x74, 0x72, 0x75, 0x65}; // "true" 152 uint32_t array2Utf16Len = sizeof(array2Utf16) / sizeof(array2Utf16[0]); 153 JSHandle<JSTaggedValue> handleMsg3(factory->NewFromUtf16(&array2Utf16[0], array2Utf16Len)); 154 JSHandle<EcmaString> handleStr3(JSTaggedValue::ToString(thread, handleMsg3)); 155 JSHandle<JSTaggedValue> result3 = parser.Parse(*handleStr3); 156 EXPECT_EQ(result3.GetTaggedValue(), JSTaggedValue::True()); 157 // JSON String 158 uint16_t array3Utf16[] = {0x22, 0x73, 0x74, 0x72, 0x69, 0x6E, 0X67, 0x22}; // "string" 159 uint32_t array3Utf16Len = sizeof(array3Utf16) / sizeof(array3Utf16[0]); 160 JSHandle<JSTaggedValue> handleMsg4(factory->NewFromUtf16(&array3Utf16[0], array3Utf16Len)); 161 JSHandle<EcmaString> handleStr4(JSTaggedValue::ToString(thread, handleMsg4)); 162 JSHandle<JSTaggedValue> result4 = parser.Parse(*handleStr4); 163 JSHandle<EcmaString> handleEcmaStr(result4); 164 EXPECT_STREQ("string", EcmaStringAccessor(handleEcmaStr).ToCString().c_str()); 165} 166 167/** 168 * @tc.name: Parser_003 169 * @tc.desc: Passing in a character of type "uint8_t" check whether the result returned through "ParserUtf8" function 170 * Test with for Nesting of numbers, strings, objects, arrays, Booleans. 171 * @tc.type: FUNC 172 * @tc.require: 173 */ 174HWTEST_F_L0(JsonParserTest, Parser_003) 175{ 176 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); 177 Utf8JsonParser parser(thread, TransformType::NORMAL); 178 179 JSHandle<JSTaggedValue> handleMsg(factory->NewFromASCII( 180 "\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" 181 "\n,\t\r \nnull\t\r, \ntrue\t\r,123.456\t\r \n]\t\r \n}\t\r \n")); 182 JSHandle<EcmaString> handleStr(JSTaggedValue::ToString(thread, handleMsg)); // JSON Object 183 JSHandle<JSTaggedValue> result = parser.Parse(handleStr); 184 EXPECT_TRUE(result->IsECMAObject()); 185} 186 187/** 188 * @tc.name: Parser_004 189 * @tc.desc: Passing in a character of type "uint8_t" check whether the result returned through "ParserUtf8" function 190 * Test with for Nesting of numbers, strings, arrays. 191 * @tc.type: FUNC 192 * @tc.require: 193 */ 194HWTEST_F_L0(JsonParserTest, Parser_004) 195{ 196 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); 197 JSHandle<JSTaggedValue> lengthKeyHandle = thread->GlobalConstants()->GetHandledLengthString(); 198 Utf8JsonParser parser(thread, TransformType::NORMAL); 199 200 JSHandle<JSTaggedValue> handleMsg(factory->NewFromASCII("[100,2.5,\"abc\"]")); 201 JSHandle<EcmaString> handleStr(JSTaggedValue::ToString(thread, handleMsg)); // JSON Array 202 JSHandle<JSTaggedValue> result = parser.Parse(handleStr); 203 204 JSTaggedValue resultValue(static_cast<JSTaggedType>(result->GetRawData())); 205 EXPECT_TRUE(resultValue.IsECMAObject()); 206 JSHandle<JSObject> valueHandle(thread, resultValue); 207 208 JSHandle<JSTaggedValue> lenResult = 209 JSObject::GetProperty(thread, JSHandle<JSTaggedValue>(valueHandle), lengthKeyHandle).GetValue(); 210 uint32_t length = JSTaggedValue::ToLength(thread, lenResult).ToUint32(); 211 EXPECT_EQ(length, 3U); 212} 213 214/** 215 * @tc.name: Parser_005 216 * @tc.desc: Passing in a character of type "uint8_t" check whether the result returned through "ParserUtf8" function 217 * Test without for Nesting of numbers, strings, objects. 218 * @tc.type: FUNC 219 * @tc.require: 220 */ 221HWTEST_F_L0(JsonParserTest, Parser_005) 222{ 223 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); 224 Utf8JsonParser parser(thread, TransformType::NORMAL); 225 226 JSHandle<JSTaggedValue> handleMsg(factory->NewFromASCII("{\"epf\":100,\"key1\":400}")); 227 JSHandle<EcmaString> handleStr(JSTaggedValue::ToString(thread, handleMsg)); // JSON Object 228 229 JSHandle<JSTaggedValue> result = parser.Parse(handleStr); 230 JSTaggedValue resultValue(static_cast<JSTaggedType>(result->GetRawData())); 231 EXPECT_TRUE(resultValue.IsECMAObject()); 232 233 JSHandle<JSObject> valueHandle(thread, resultValue); 234 JSHandle<TaggedArray> nameList(JSObject::EnumerableOwnNames(thread, valueHandle)); 235 JSHandle<JSArray> nameResult = JSArray::CreateArrayFromList(thread, nameList); 236 237 JSHandle<JSTaggedValue> handleKey(nameResult); 238 JSHandle<JSTaggedValue> lengthKey(factory->NewFromASCII("length")); 239 JSHandle<JSTaggedValue> lenResult = JSObject::GetProperty(thread, handleKey, lengthKey).GetValue(); 240 uint32_t length = JSTaggedValue::ToLength(thread, lenResult).ToUint32(); 241 EXPECT_EQ(length, 2U); 242} 243 244/** 245 * @tc.name: Parser_006 246 * @tc.desc: Try to parse a empty string. 247 * @tc.type: FUNC 248 * @tc.require: 249 */ 250HWTEST_F_L0(JsonParserTest, Parser_006) 251{ 252 Utf8JsonParser parser(thread, TransformType::NORMAL); 253 JSHandle<EcmaString> emptyString(thread->GlobalConstants()->GetHandledEmptyString()); 254 JSHandle<JSTaggedValue> result = parser.Parse(emptyString); 255 EXPECT_TRUE(result->IsException()); 256} 257 258/** 259 * @tc.name: Parser_007 260 * @tc.desc: Try to parse a string containing an empty string. 261 * @tc.type: FUNC 262 * @tc.require: 263 */ 264HWTEST_F_L0(JsonParserTest, Parser_007) 265{ 266 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); 267 Utf8JsonParser parser(thread, TransformType::NORMAL); 268 269 JSHandle<EcmaString> handleStr(factory->NewFromASCII("\"\"")); 270 JSHandle<JSTaggedValue> result = parser.Parse(handleStr); 271 EXPECT_FALSE(result->IsException()); 272} 273 274/** 275 * @tc.name: Parser_008 276 * @tc.desc: Try to parse a string to sendable object. 277 * @tc.type: FUNC 278 * @tc.require: 279 */ 280HWTEST_F_L0(JsonParserTest, Parser_008) 281{ 282 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); 283 Utf8JsonParser parser(thread, TransformType::SENDABLE); 284 JSHandle<JSTaggedValue> handleMsg( 285 factory->NewFromASCII(R"({"innerEntry": {"x":1, "y":"abc", "str": "innerStr"}, "x": 1, "str": "outerStr"})")); 286 JSHandle<EcmaString> handleStr(JSTaggedValue::ToString(thread, handleMsg)); 287 JSHandle<JSTaggedValue> result = parser.Parse(handleStr); 288 result->D(); 289 EXPECT_FALSE(result->IsException()); 290 EXPECT_TRUE(CheckSendableConstraint(result.GetTaggedValue())); 291} 292 293/** 294 * @tc.name: Parser_009 295 * @tc.desc: Try to parse a empty obj json string to sendable object. 296 * @tc.type: FUNC 297 * @tc.require: 298 */ 299HWTEST_F_L0(JsonParserTest, Parser_009) 300{ 301 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); 302 Utf8JsonParser parser(thread, TransformType::SENDABLE); 303 JSHandle<JSTaggedValue> handleMsg(factory->NewFromASCII(R"({})")); 304 JSHandle<EcmaString> handleStr(JSTaggedValue::ToString(thread, handleMsg)); 305 JSHandle<JSTaggedValue> result = parser.Parse(handleStr); 306 result->D(); 307 EXPECT_TRUE(CheckSendableConstraint(result.GetTaggedValue())); 308} 309 310/** 311 * @tc.name: Parser_010 312 * @tc.desc: Try to parse a empty array json string to sendable object. 313 * @tc.type: FUNC 314 * @tc.require: 315 */ 316HWTEST_F_L0(JsonParserTest, Parser_010) 317{ 318 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); 319 Utf8JsonParser parser(thread, TransformType::SENDABLE); 320 JSHandle<JSTaggedValue> handleMsg(factory->NewFromASCII(R"([])")); 321 JSHandle<EcmaString> handleStr(JSTaggedValue::ToString(thread, handleMsg)); 322 JSHandle<JSTaggedValue> result = parser.Parse(handleStr); 323 result->D(); 324 EXPECT_TRUE(CheckSendableConstraint(result.GetTaggedValue())); 325} 326 327/** 328 * @tc.name: Parser_011 329 * @tc.desc: Try to parse a simple array json string to sendable object. 330 * @tc.type: FUNC 331 * @tc.require: 332 */ 333HWTEST_F_L0(JsonParserTest, Parser_011) 334{ 335 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); 336 Utf8JsonParser parser(thread, TransformType::SENDABLE); 337 JSHandle<JSTaggedValue> handleMsg(factory->NewFromASCII(R"([1, 2, 3])")); 338 JSHandle<EcmaString> handleStr(JSTaggedValue::ToString(thread, handleMsg)); 339 JSHandle<JSTaggedValue> result = parser.Parse(handleStr); 340 result->D(); 341 EXPECT_TRUE(CheckSendableConstraint(result.GetTaggedValue())); 342} 343 344/** 345 * @tc.name: Parser_012 346 * @tc.desc: Try to parse a json string with array to sendable object. 347 * @tc.type: FUNC 348 * @tc.require: 349 */ 350HWTEST_F_L0(JsonParserTest, Parser_012) 351{ 352 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); 353 Utf8JsonParser parser(thread, TransformType::SENDABLE); 354 JSHandle<JSTaggedValue> handleMsg( 355 factory->NewFromASCII(R"({"innerEntry": {"array": [1, 2, 3]}, "x": 1, "str": "outerStr"})")); 356 JSHandle<EcmaString> handleStr(JSTaggedValue::ToString(thread, handleMsg)); 357 JSHandle<JSTaggedValue> result = parser.Parse(handleStr); 358 result->D(); 359 EXPECT_TRUE(CheckSendableConstraint(result.GetTaggedValue())); 360} 361} // namespace panda::test 362