1 /*
2 * Copyright (c) 2024 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
21 using namespace panda::ecmascript;
22 using namespace panda::ecmascript::base;
23
24 namespace panda::test {
25 class AsonParserTest : public BaseTestWithScope<false> {
26 public:
27 using TransformType = base::JsonHelper::TransformType;
28
CheckSendableConstraint(JSTaggedValue value) const29 bool CheckSendableConstraint(JSTaggedValue value) const
30 {
31 if (!value.IsHeapObject()) {
32 // tagged value always follow sendable constraint.
33 return true;
34 }
35 TaggedObject *obj = value.IsWeak() ? value.GetTaggedWeakRef() : value.GetTaggedObject();
36 auto *jsHClass = obj->GetClass();
37 if (!jsHClass->IsJSShared()) {
38 return false;
39 }
40 if (jsHClass->IsExtensible()) {
41 LOG_ECMA(ERROR) << "sendable check failed. obj is extensible";
42 value.D();
43 return false;
44 }
45 if (!CheckSendableProps(value, obj)) {
46 return false;
47 }
48 // trace proto chain
49 auto proto = jsHClass->GetPrototype();
50 if (!proto.IsNull() && !proto.IsJSShared()) {
51 LOG_ECMA(ERROR) << "sendable check failed. proto is not sendable.";
52 value.D();
53 return false;
54 }
55 return true;
56 }
57
CheckSendableProps(JSTaggedValue value,TaggedObject * obj) const58 bool CheckSendableProps(JSTaggedValue value, TaggedObject *obj) const
59 {
60 auto *jsHClass = obj->GetClass();
61 auto layoutValue = jsHClass->GetLayout();
62 if (layoutValue.IsNull()) {
63 return true;
64 }
65 auto *layoutInfo = LayoutInfo::Cast(layoutValue.GetTaggedObject());
66 auto *jsObj = JSObject::Cast(obj);
67 auto *propsValue = TaggedArray::Cast(jsObj->GetProperties());
68 if (propsValue->IsDictionaryMode()) {
69 for (int idx = 0; idx < static_cast<int>(jsHClass->NumberOfProps()); idx++) {
70 auto attr = layoutInfo->GetAttr(idx);
71 if (attr.IsInlinedProps()) {
72 // Do not check inline props
73 continue;
74 }
75 if (attr.IsWritable()) {
76 LOG_ECMA(ERROR) << "sendable check failed. supposed to be un-writable. idx: " << idx;
77 value.D();
78 return false;
79 }
80 auto val = propsValue->Get(thread, idx - jsHClass->GetInlinedProperties());
81 if (!CheckSendableConstraint(val)) {
82 LOG_ECMA(ERROR) << "sendable check failed. supposed to be sendable. idx: " << idx;
83 value.D();
84 return false;
85 }
86 }
87 }
88 return true;
89 }
90 };
91
HWTEST_F_L0(AsonParserTest,Parser_001)92 HWTEST_F_L0(AsonParserTest, Parser_001)
93 {
94 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
95 Utf8JsonParser parser(thread, TransformType::SENDABLE);
96 // JSON Number
97 JSHandle<JSTaggedValue> handleMsg2(factory->NewFromASCII("1234"));
98 JSHandle<EcmaString> handleStr2(JSTaggedValue::ToString(thread, handleMsg2));
99 JSHandle<JSTaggedValue> result2 = parser.Parse(handleStr2);
100 EXPECT_EQ(result2->GetNumber(), 1234);
101 // JSON Literal
102 JSHandle<JSTaggedValue> handleMsg3(factory->NewFromASCII("true"));
103 JSHandle<EcmaString> handleStr3(JSTaggedValue::ToString(thread, handleMsg3));
104 JSHandle<JSTaggedValue> result3 = parser.Parse(handleStr3);
105 EXPECT_EQ(result3.GetTaggedValue(), JSTaggedValue::True());
106 // JSON LiteraF
107 JSHandle<JSTaggedValue> handleMsg4(factory->NewFromASCII("false"));
108 JSHandle<EcmaString> handleStr4(JSTaggedValue::ToString(thread, handleMsg4));
109 JSHandle<JSTaggedValue> result4 = parser.Parse(handleStr4);
110 EXPECT_EQ(result4.GetTaggedValue(), JSTaggedValue::False());
111 // JSON Unexpected
112 JSHandle<JSTaggedValue> handleMsg5(factory->NewFromASCII("trus"));
113 JSHandle<EcmaString> handleStr5(JSTaggedValue::ToString(thread, handleMsg5));
114 JSHandle<JSTaggedValue> result5 = parser.Parse(handleStr5);
115 EXPECT_EQ(result5.GetTaggedValue(), JSTaggedValue::Exception());
116 }
117
HWTEST_F_L0(AsonParserTest,Parser_002)118 HWTEST_F_L0(AsonParserTest, Parser_002)
119 {
120 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
121 Utf16JsonParser parser(thread, TransformType::SENDABLE);
122
123 // JSON Number
124 uint16_t array1Utf16[] = {0x31, 0x32, 0x33, 0x34}; // "1234"
125 uint32_t array1Utf16Len = sizeof(array1Utf16) / sizeof(array1Utf16[0]);
126 JSHandle<JSTaggedValue> handleMsg2(factory->NewFromUtf16(&array1Utf16[0], array1Utf16Len));
127 JSHandle<EcmaString> handleStr2(JSTaggedValue::ToString(thread, handleMsg2));
128 JSHandle<JSTaggedValue> result2 = parser.Parse(*handleStr2);
129 EXPECT_EQ(result2->GetNumber(), 1234);
130 // JSON Literal
131 uint16_t array2Utf16[] = {0x74, 0x72, 0x75, 0x65}; // "true"
132 uint32_t array2Utf16Len = sizeof(array2Utf16) / sizeof(array2Utf16[0]);
133 JSHandle<JSTaggedValue> handleMsg3(factory->NewFromUtf16(&array2Utf16[0], array2Utf16Len));
134 JSHandle<EcmaString> handleStr3(JSTaggedValue::ToString(thread, handleMsg3));
135 JSHandle<JSTaggedValue> result3 = parser.Parse(*handleStr3);
136 EXPECT_EQ(result3.GetTaggedValue(), JSTaggedValue::True());
137 // JSON String
138 uint16_t array3Utf16[] = {0x22, 0x73, 0x74, 0x72, 0x69, 0x6E, 0X67, 0x22}; // "string"
139 uint32_t array3Utf16Len = sizeof(array3Utf16) / sizeof(array3Utf16[0]);
140 JSHandle<JSTaggedValue> handleMsg4(factory->NewFromUtf16(&array3Utf16[0], array3Utf16Len));
141 JSHandle<EcmaString> handleStr4(JSTaggedValue::ToString(thread, handleMsg4));
142 JSHandle<JSTaggedValue> result4 = parser.Parse(*handleStr4);
143 JSHandle<EcmaString> handleEcmaStr(result4);
144 EXPECT_STREQ("string", EcmaStringAccessor(handleEcmaStr).ToCString().c_str());
145 }
146
HWTEST_F_L0(AsonParserTest,Parser_003)147 HWTEST_F_L0(AsonParserTest, Parser_003)
148 {
149 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
150 Utf8JsonParser parser(thread, TransformType::SENDABLE);
151 JSHandle<JSTaggedValue> handleMsg(factory->NewFromASCII(
152 "\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"
153 "\n,\t\r \nnull\t\r, \ntrue\t\r,123.456\t\r \n]\t\r \n}\t\r \n"));
154 JSHandle<EcmaString> handleStr(JSTaggedValue::ToString(thread, handleMsg)); // JSON Object
155 JSHandle<JSTaggedValue> result = parser.Parse(handleStr);
156 result->D();
157 EXPECT_TRUE(CheckSendableConstraint(result.GetTaggedValue()));
158 }
159
HWTEST_F_L0(AsonParserTest,Parser_004)160 HWTEST_F_L0(AsonParserTest, Parser_004)
161 {
162 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
163 Utf8JsonParser parser(thread, TransformType::SENDABLE);
164 JSHandle<JSTaggedValue> handleMsg(factory->NewFromASCII("[100,2.5,\"abc\"]"));
165 JSHandle<EcmaString> handleStr(JSTaggedValue::ToString(thread, handleMsg)); // JSON Array
166 JSHandle<JSTaggedValue> result = parser.Parse(handleStr);
167 result->D();
168 EXPECT_TRUE(CheckSendableConstraint(result.GetTaggedValue()));
169 }
170
HWTEST_F_L0(AsonParserTest,Parser_005)171 HWTEST_F_L0(AsonParserTest, Parser_005)
172 {
173 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
174 Utf8JsonParser parser(thread, TransformType::SENDABLE);
175 JSHandle<JSTaggedValue> handleMsg(factory->NewFromASCII("{\"epf\":100,\"key1\":400}"));
176 JSHandle<EcmaString> handleStr(JSTaggedValue::ToString(thread, handleMsg));
177 JSHandle<JSTaggedValue> result = parser.Parse(handleStr);
178 EXPECT_TRUE(CheckSendableConstraint(result.GetTaggedValue()));
179 }
180
HWTEST_F_L0(AsonParserTest,Parser_006)181 HWTEST_F_L0(AsonParserTest, Parser_006)
182 {
183 Utf8JsonParser parser(thread, TransformType::SENDABLE);
184 JSHandle<EcmaString> emptyString(thread->GlobalConstants()->GetHandledEmptyString());
185 JSHandle<JSTaggedValue> result = parser.Parse(emptyString);
186 EXPECT_TRUE(result->IsException());
187 }
188
HWTEST_F_L0(AsonParserTest,Parser_007)189 HWTEST_F_L0(AsonParserTest, Parser_007)
190 {
191 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
192 Utf8JsonParser parser(thread, TransformType::SENDABLE);
193
194 JSHandle<EcmaString> handleStr(factory->NewFromASCII("\"\""));
195 JSHandle<JSTaggedValue> result = parser.Parse(handleStr);
196 EXPECT_FALSE(result->IsException());
197 }
198
HWTEST_F_L0(AsonParserTest,Parser_008)199 HWTEST_F_L0(AsonParserTest, Parser_008)
200 {
201 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
202 Utf8JsonParser parser(thread, TransformType::SENDABLE);
203 JSHandle<JSTaggedValue> handleMsg(
204 factory->NewFromASCII(R"({"innerEntry": {"x":1, "y":"abc", "str": "innerStr"}, "x": 1, "str": "outerStr"})"));
205 JSHandle<EcmaString> handleStr(JSTaggedValue::ToString(thread, handleMsg));
206 JSHandle<JSTaggedValue> result = parser.Parse(handleStr);
207 result->D();
208 EXPECT_FALSE(result->IsException());
209 EXPECT_TRUE(CheckSendableConstraint(result.GetTaggedValue()));
210 }
211
HWTEST_F_L0(AsonParserTest,Parser_009)212 HWTEST_F_L0(AsonParserTest, Parser_009)
213 {
214 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
215 Utf8JsonParser parser(thread, TransformType::SENDABLE);
216 JSHandle<JSTaggedValue> handleMsg(factory->NewFromASCII(R"({})"));
217 JSHandle<EcmaString> handleStr(JSTaggedValue::ToString(thread, handleMsg));
218 JSHandle<JSTaggedValue> result = parser.Parse(handleStr);
219 result->D();
220 EXPECT_TRUE(CheckSendableConstraint(result.GetTaggedValue()));
221 }
222
HWTEST_F_L0(AsonParserTest,Parser_010)223 HWTEST_F_L0(AsonParserTest, Parser_010)
224 {
225 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
226 Utf8JsonParser parser(thread, TransformType::SENDABLE);
227 JSHandle<JSTaggedValue> handleMsg(factory->NewFromASCII(R"([])"));
228 JSHandle<EcmaString> handleStr(JSTaggedValue::ToString(thread, handleMsg));
229 JSHandle<JSTaggedValue> result = parser.Parse(handleStr);
230 result->D();
231 EXPECT_TRUE(CheckSendableConstraint(result.GetTaggedValue()));
232 }
233
HWTEST_F_L0(AsonParserTest,Parser_011)234 HWTEST_F_L0(AsonParserTest, Parser_011)
235 {
236 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
237 Utf8JsonParser parser(thread, TransformType::SENDABLE);
238 JSHandle<JSTaggedValue> handleMsg(factory->NewFromASCII(R"([1, 2, 3])"));
239 JSHandle<EcmaString> handleStr(JSTaggedValue::ToString(thread, handleMsg));
240 JSHandle<JSTaggedValue> result = parser.Parse(handleStr);
241 result->D();
242 EXPECT_TRUE(CheckSendableConstraint(result.GetTaggedValue()));
243 }
244
HWTEST_F_L0(AsonParserTest,Parser_012)245 HWTEST_F_L0(AsonParserTest, Parser_012)
246 {
247 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
248 Utf8JsonParser parser(thread, TransformType::SENDABLE);
249 JSHandle<JSTaggedValue> handleMsg(
250 factory->NewFromASCII(R"({"innerEntry": {"array": [1, 2, 3]}, "x": 1, "str": "outerStr"})"));
251 JSHandle<EcmaString> handleStr(JSTaggedValue::ToString(thread, handleMsg));
252 JSHandle<JSTaggedValue> result = parser.Parse(handleStr);
253 result->D();
254 EXPECT_TRUE(CheckSendableConstraint(result.GetTaggedValue()));
255 }
256
HWTEST_F_L0(AsonParserTest,Parser_013)257 HWTEST_F_L0(AsonParserTest, Parser_013)
258 {
259 JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
260 JSMutableHandle<JSFunction> constructor(thread, JSTaggedValue::Undefined());
261 constructor.Update(env->GetSObjectFunction());
262 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
263 JSHandle<JSObject> root = factory->NewJSObjectByConstructor(constructor);
264 JSHandle<JSTaggedValue> rootName(factory->GetEmptyString());
265 JSHandle<JSTaggedValue> result;
266 JSHandle<JSTaggedValue> undefined = JSHandle<JSTaggedValue>(thread, JSTaggedValue::Undefined());
267 result = Internalize::InternalizeJsonProperty(thread, root, rootName, undefined, TransformType::SENDABLE);
268 ASSERT_TRUE(!result->IsUndefined());
269 }
270 } // namespace panda::test
271