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_stringifier.h"
17 #include "ecmascript/js_array.h"
18 #include "ecmascript/tests/test_helper.h"
19 
20 using namespace panda::ecmascript;
21 using namespace panda::ecmascript::base;
22 
23 namespace panda::test {
24 class JsonStringifierTest : public BaseTestWithScope<false> {
25 };
26 
CreateBaseJSObject(JSThread *thread, const CString keyCStr)27 static JSTaggedValue CreateBaseJSObject(JSThread *thread, const CString keyCStr)
28 {
29     EcmaVM *ecmaVM = thread->GetEcmaVM();
30     JSHandle<GlobalEnv> globalEnv = ecmaVM->GetGlobalEnv();
31     ObjectFactory *factory = ecmaVM->GetFactory();
32     JSHandle<JSTaggedValue> objectFunc(globalEnv->GetObjectFunction());
33 
34     JSHandle<JSObject> jsObject(factory->NewJSObjectByConstructor(JSHandle<JSFunction>(objectFunc), objectFunc));
35     EXPECT_TRUE(*jsObject != nullptr);
36 
37     JSHandle<JSTaggedValue> handleKey1(factory->NewFromASCII(&keyCStr[0]));
38     JSHandle<JSTaggedValue> handleValue1(thread, JSTaggedValue(1)); // 1 : test case
39     JSObject::SetProperty(thread, JSHandle<JSTaggedValue>(jsObject), handleKey1, handleValue1);
40 
41     CString str2 = "x";
42     JSHandle<JSTaggedValue> handleKey2(factory->NewFromASCII(str2));
43     JSHandle<JSTaggedValue> handleValue2(thread, JSTaggedValue(3.6)); // 3.6 : test case
44     JSObject::SetProperty(thread, JSHandle<JSTaggedValue>(jsObject), handleKey2, handleValue2);
45 
46     CString str3 = "y";
47     JSHandle<JSTaggedValue> handleKey3(factory->NewFromASCII(str3));
48     JSHandle<JSTaggedValue> handleValue3(factory->NewFromASCII("abc"));
49     JSObject::SetProperty(thread, JSHandle<JSTaggedValue>(jsObject), handleKey3, handleValue3);
50 
51     return jsObject.GetTaggedValue();
52 }
53 
TestForStringfy1([[maybe_unused]] EcmaRuntimeCallInfo *argv)54 static JSTaggedValue TestForStringfy1([[maybe_unused]] EcmaRuntimeCallInfo *argv)
55 {
56     // false: test case
57     return JSTaggedValue(JSTaggedValue::False());
58 }
59 
TestForStringfy2([[maybe_unused]] EcmaRuntimeCallInfo *argv)60 static JSTaggedValue TestForStringfy2([[maybe_unused]] EcmaRuntimeCallInfo *argv)
61 {
62     // 10.12: test case
63     return JSTaggedValue(10.12);
64 }
65 
66 /**
67  * @tc.name: Stringify_001
68  * @tc.desc: Check whether the result returned through "Stringify" function is within expectations
69  *           the first parameter of the ECMAObject,the second parameter is JSFunction,the third parameter
70  *           is Undefined.if the second parameter is JSFunction,the return value is the parameter stringification
71  *           after through "call" function.
72  * @tc.type: FUNC
73  * @tc.require:
74  */
HWTEST_F_L0(JsonStringifierTest, Stringify_001)75 HWTEST_F_L0(JsonStringifierTest, Stringify_001)
76 {
77     ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
78     JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
79 
80     JSHandle<JSTaggedValue> handleObj = JSHandle<JSTaggedValue>(thread, CreateBaseJSObject(thread, "z"));
81     JSHandle<JSFunction> handleFunc1 = factory->NewJSFunction(env, reinterpret_cast<void *>(TestForStringfy1));
82     JSHandle<JSFunction> handleFunc2 = factory->NewJSFunction(env, reinterpret_cast<void *>(TestForStringfy2));
83     JSHandle<JSTaggedValue> handleValue(thread, handleObj.GetTaggedValue());
84     JSHandle<JSTaggedValue> handleReplacer1(thread, handleFunc1.GetTaggedValue());
85     JSHandle<JSTaggedValue> handleReplacer2(thread, handleFunc2.GetTaggedValue());
86     JSHandle<JSTaggedValue> handleGap(thread, JSTaggedValue::Undefined());
87 
88     JsonStringifier stringifier1(thread);
89     JSHandle<JSTaggedValue> resultString1 = stringifier1.Stringify(handleValue, handleReplacer1, handleGap);
90     EXPECT_TRUE(resultString1->IsString());
91     JSHandle<EcmaString> handleEcmaStr1(resultString1);
92     EXPECT_STREQ("false", EcmaStringAccessor(handleEcmaStr1).ToCString().c_str());
93 
94     JsonStringifier stringifier2(thread);
95     JSHandle<JSTaggedValue> resultString2 = stringifier2.Stringify(handleValue, handleReplacer2, handleGap);
96     EXPECT_TRUE(resultString2->IsString());
97     JSHandle<EcmaString> handleEcmaStr2(resultString2);
98     EXPECT_STREQ("10.12", EcmaStringAccessor(handleEcmaStr2).ToCString().c_str());
99 }
100 
101 /**
102  * @tc.name: Stringify_002
103  * @tc.desc: Check whether the result returned through "Stringify" function is within expectations
104  *           the first parameter of the ECMAObject,the second parameter is Undefined,the third parameter
105  *           is Number.This situation will stringize parameters through "SerializeJSONObject" function.
106  * @tc.type: FUNC
107  * @tc.require:
108  */
HWTEST_F_L0(JsonStringifierTest, Stringify_002)109 HWTEST_F_L0(JsonStringifierTest, Stringify_002)
110 {
111     JsonStringifier stringifier(thread);
112 
113     JSHandle<JSTaggedValue> handleObj = JSHandle<JSTaggedValue>(thread, CreateBaseJSObject(thread, "z"));
114     JSHandle<JSTaggedValue> handleValue(thread, handleObj.GetTaggedValue());
115     JSHandle<JSTaggedValue> handleReplacer(thread, JSTaggedValue::Undefined());
116     JSHandle<JSTaggedValue> handleGap(thread, JSTaggedValue(static_cast<int32_t>(10)));
117 
118     JSHandle<JSTaggedValue> resultString = stringifier.Stringify(handleValue, handleReplacer, handleGap);
119     EXPECT_TRUE(resultString->IsString());
120     JSHandle<EcmaString> handleEcmaStr(resultString);
121     EXPECT_STREQ("{\n          \"z\": 1,\n          \"x\": 3.6,\n          \"y\": \"abc\"\n}",
122                                                      EcmaStringAccessor(handleEcmaStr).ToCString().c_str());
123 }
124 
125 /**
126  * @tc.name: Stringify_003
127  * @tc.desc: Check whether the result returned through "Stringify" function is within expectations
128  *           the first parameter of the ECMAObject,the second parameter is Undefined,the third parameter
129  *           is String,This situation will stringize parameters through "SerializeJSONObject" function.
130  * @tc.type: FUNC
131  * @tc.require:
132  */
HWTEST_F_L0(JsonStringifierTest, Stringify_003)133 HWTEST_F_L0(JsonStringifierTest, Stringify_003)
134 {
135     ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
136     JsonStringifier stringifier(thread);
137 
138     JSHandle<JSTaggedValue> handleObj = JSHandle<JSTaggedValue>(thread, CreateBaseJSObject(thread, "z"));
139     JSHandle<JSTaggedValue> handleMsg(factory->NewFromASCII("tttt"));
140     JSHandle<EcmaString> handleStr(JSTaggedValue::ToString(thread, handleMsg));
141 
142     JSHandle<JSTaggedValue> handleValue(thread, handleObj.GetTaggedValue());
143     JSHandle<JSTaggedValue> handleReplacer(thread, JSTaggedValue::Undefined());
144     JSHandle<JSTaggedValue> handleGap(thread, handleStr.GetTaggedValue());
145 
146     JSHandle<JSTaggedValue> resultString = stringifier.Stringify(handleValue, handleReplacer, handleGap);
147     EXPECT_TRUE(resultString->IsString());
148     JSHandle<EcmaString> resultStr =
149         factory->NewFromASCII("{\ntttt\"z\": 1,\ntttt\"x\": 3.6,\ntttt\"y\": \"abc\"\n}");
150     EXPECT_EQ(EcmaStringAccessor::Compare(instance, resultStr, JSHandle<EcmaString>(resultString)), 0);
151 }
152 
153 /**
154  * @tc.name: Stringify_004
155  * @tc.desc: Check whether the result returned through "Stringify" function is within expectations
156  *           the first parameter of the ECMAObject,the second parameter is JSArray,the third parameter
157  *           is String.This situation will stringize parameters through "SerializeJSONObject" function.
158  * @tc.type: FUNC
159  * @tc.require:
160  */
HWTEST_F_L0(JsonStringifierTest, Stringify_004)161 HWTEST_F_L0(JsonStringifierTest, Stringify_004)
162 {
163     ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
164     JsonStringifier stringifier(thread);
165 
166     JSHandle<JSTaggedValue> handleObj1 = JSHandle<JSTaggedValue>(thread, CreateBaseJSObject(thread, "z"));
167 
168     JSArray *handleArr =
169         JSArray::Cast(JSArray::ArrayCreate(thread, JSTaggedNumber(0)).GetTaggedValue().GetTaggedObject());
170     JSHandle<JSObject> handleObj2(thread, handleArr);
171     JSHandle<JSTaggedValue> handleKey0(thread, JSTaggedValue(0));
172     JSHandle<JSTaggedValue> handleValue0(factory->NewFromASCII("z"));
173     JSObject::SetProperty(thread, JSHandle<JSTaggedValue>(handleObj2), handleKey0, handleValue0);
174 
175     JSHandle<JSTaggedValue> handleKey1(thread, JSTaggedValue(1));
176     JSHandle<JSTaggedValue> handleValue1(factory->NewFromASCII("x"));
177     JSObject::SetProperty(thread, JSHandle<JSTaggedValue>(handleObj2), handleKey1, handleValue1);
178 
179     JSHandle<JSTaggedValue> handleMsg(factory->NewFromASCII("tttt"));
180     JSHandle<EcmaString> handleStr(JSTaggedValue::ToString(thread, handleMsg));
181 
182     JSHandle<JSTaggedValue> handleValue(thread, handleObj1.GetTaggedValue());
183     JSHandle<JSTaggedValue> handleReplacer(thread, handleObj2.GetTaggedValue());
184     JSHandle<JSTaggedValue> handleGap(thread, handleStr.GetTaggedValue());
185 
186     JSHandle<JSTaggedValue> resultString = stringifier.Stringify(handleValue, handleReplacer, handleGap);
187     EXPECT_TRUE(resultString->IsString());
188     JSHandle<EcmaString> handleEcmaStr(resultString);
189     EXPECT_STREQ("{\ntttt\"z\": 1,\ntttt\"x\": 3.6\n}", EcmaStringAccessor(handleEcmaStr).ToCString().c_str());
190 }
191 
192 /**
193  * @tc.name: Stringify_005
194  * @tc.desc: Check whether the result returned through "Stringify" function is within expectations
195  *           the first parameter of the ECMAObject,the second parameter is Undefined,the third parameter
196  *           is Undefined.This situation will stringize the first parameter through "SerializeJSONObject" function.
197  * @tc.type: FUNC
198  * @tc.require:
199  */
HWTEST_F_L0(JsonStringifierTest, Stringify_005)200 HWTEST_F_L0(JsonStringifierTest, Stringify_005)
201 {
202     JsonStringifier stringifier(thread);
203     JSHandle<JSTaggedValue> handleObj = JSHandle<JSTaggedValue>(thread, CreateBaseJSObject(thread, "z"));
204 
205     JSHandle<JSTaggedValue> handleValue(thread, handleObj.GetTaggedValue());
206     JSHandle<JSTaggedValue> handleReplacer(thread, JSTaggedValue::Undefined());
207     JSHandle<JSTaggedValue> handleGap(thread, JSTaggedValue::Undefined());
208 
209     JSHandle<JSTaggedValue> resultString = stringifier.Stringify(handleValue, handleReplacer, handleGap);
210     EXPECT_TRUE(resultString->IsString());
211     JSHandle<EcmaString> handleEcmaStr(resultString);
212     EXPECT_STREQ("{\"z\":1,\"x\":3.6,\"y\":\"abc\"}", EcmaStringAccessor(handleEcmaStr).ToCString().c_str());
213 }
214 
215 /**
216  * @tc.name: Stringify_006
217  * @tc.desc: Check whether the result returned through "Stringify" function is within expectations
218  *           the first parameter of the JSArray,the second parameter is Undefined,the third parameter
219  *           is String,This situation will stringize parameters through "SerializeJSArray" function.
220  * @tc.type: FUNC
221  * @tc.require:
222  */
HWTEST_F_L0(JsonStringifierTest, Stringify_006)223 HWTEST_F_L0(JsonStringifierTest, Stringify_006)
224 {
225     ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
226     JsonStringifier stringifier(thread);
227 
228     JSArray *handleArr =
229         JSArray::Cast(JSArray::ArrayCreate(thread, JSTaggedNumber(0)).GetTaggedValue().GetTaggedObject());
230     JSHandle<JSObject> handleObj(thread, handleArr);
231 
232     JSHandle<JSTaggedValue> handleKey0(thread, JSTaggedValue(0));
233     JSHandle<JSTaggedValue> handleValue0(factory->NewFromASCII("json"));
234     JSObject::SetProperty(thread, JSHandle<JSTaggedValue>(handleObj), handleKey0, handleValue0);
235 
236     JSHandle<JSTaggedValue> handleKey1(thread, JSTaggedValue(1));
237     PropertyDescriptor handleDesc(thread, JSHandle<JSTaggedValue>(thread, JSTaggedValue(100)), true, true, true);
238     JSArray::DefineOwnProperty(thread, handleObj, handleKey1, handleDesc);
239 
240     JSHandle<JSTaggedValue> handleKey2(thread, JSTaggedValue(2));
241     JSHandle<JSTaggedValue> handleValue2(factory->NewFromASCII("abc"));
242     JSObject::SetProperty(thread, JSHandle<JSTaggedValue>(handleObj), handleKey2, handleValue2);
243 
244     JSHandle<JSTaggedValue> handleMsg(factory->NewFromASCII("tttt"));
245     JSHandle<EcmaString> handleStr(JSTaggedValue::ToString(thread, handleMsg));
246 
247     JSHandle<JSTaggedValue> handleValue(thread, handleObj.GetTaggedValue());
248     JSHandle<JSTaggedValue> handleReplacer(thread, JSTaggedValue::Undefined());
249     JSHandle<JSTaggedValue> handleGap(thread, handleStr.GetTaggedValue());
250 
251     JSHandle<JSTaggedValue> resultString = stringifier.Stringify(handleValue, handleReplacer, handleGap);
252     EXPECT_TRUE(resultString->IsString());
253     JSHandle<EcmaString> handleEcmaStr(resultString);
254     EXPECT_STREQ("[\ntttt\"json\",\ntttt100,\ntttt\"abc\"\n]", EcmaStringAccessor(handleEcmaStr).ToCString().c_str());
255 }
256 
257 /**
258  * @tc.name: Stringify_007
259  * @tc.desc: Check whether the result returned through "Stringify" function is within expectations
260  *           the first parameter of the JSObject,the second parameter is Undefined,the third parameter
261  *           is Undefined.This situation will stringize the first parameter through "SerializeJSArray" function.
262  * @tc.type: FUNC
263  * @tc.require:
264  */
HWTEST_F_L0(JsonStringifierTest, Stringify_007)265 HWTEST_F_L0(JsonStringifierTest, Stringify_007)
266 {
267     ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
268     JsonStringifier stringifier(thread);
269 
270     JSArray *handleArr =
271         JSArray::Cast(JSArray::ArrayCreate(thread, JSTaggedNumber(0)).GetTaggedValue().GetTaggedObject());
272     JSHandle<JSObject> handleObj(thread, handleArr);
273 
274     JSHandle<JSTaggedValue> handleKey0(thread, JSTaggedValue(0));
275     PropertyDescriptor handleDesc0(thread, JSHandle<JSTaggedValue>(thread, JSTaggedValue(1)), true, true, true);
276     JSArray::DefineOwnProperty(thread, handleObj, handleKey0, handleDesc0);
277 
278     JSHandle<JSTaggedValue> handleKey1(thread, JSTaggedValue(1));
279     PropertyDescriptor handleDesc1(thread, JSHandle<JSTaggedValue>(thread, JSTaggedValue(3.6)), true, true, true);
280     JSArray::DefineOwnProperty(thread, handleObj, handleKey1, handleDesc1);
281 
282     JSHandle<JSTaggedValue> handleKey2(thread, JSTaggedValue(2));
283     JSHandle<JSTaggedValue> handleValue2(factory->NewFromASCII("abc"));
284     JSObject::SetProperty(thread, JSHandle<JSTaggedValue>(handleObj), handleKey2, handleValue2);
285 
286     JSHandle<JSTaggedValue> handleValue(thread, handleObj.GetTaggedValue());
287     JSHandle<JSTaggedValue> handleReplacer(thread, JSTaggedValue::Undefined());
288     JSHandle<JSTaggedValue> handleGap(thread, JSTaggedValue::Undefined());
289 
290     JSHandle<JSTaggedValue> resultString = stringifier.Stringify(handleValue, handleReplacer, handleGap);
291     EXPECT_TRUE(resultString->IsString());
292     JSHandle<EcmaString> handleEcmaStr(resultString);
293     EXPECT_STREQ("[1,3.6,\"abc\"]", EcmaStringAccessor(handleEcmaStr).ToCString().c_str());
294 }
295 
296 /**
297  * @tc.name: Stringify_008
298  * @tc.desc: Check whether the result returned through "Stringify" function is within expectations
299  *           the first parameter of the JSObject,the second parameter is Undefined,the third parameter
300  *           is Undefined.This situation will stringize the first parameter through "SerializePrimitiveRef"
301  *           function.
302  * @tc.type: FUNC
303  * @tc.require:
304  */
HWTEST_F_L0(JsonStringifierTest, Stringify_008)305 HWTEST_F_L0(JsonStringifierTest, Stringify_008)
306 {
307     ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
308     JsonStringifier stringifier(thread);
309 
310     JSHandle<JSTaggedValue> undefined = thread->GlobalConstants()->GetHandledUndefined();
311     JSHandle<JSTaggedValue> handleStr(factory->NewFromASCII("\"\\\b\f\n\r\t"));
312     JSHandle<JSPrimitiveRef> handlePrimitiveRef = factory->NewJSString(handleStr, undefined);
313     JSHandle<JSObject> handleObj(thread, handlePrimitiveRef.GetTaggedValue());
314 
315     JSHandle<JSTaggedValue> handleValue(thread, handleObj.GetTaggedValue());
316     JSHandle<JSTaggedValue> handleReplacer(thread, JSTaggedValue::Undefined());
317     JSHandle<JSTaggedValue> handleGap(thread, JSTaggedValue::Undefined());
318 
319     JSHandle<JSTaggedValue> resultString = stringifier.Stringify(handleValue, handleReplacer, handleGap);
320     EXPECT_TRUE(resultString->IsString());
321     JSHandle<EcmaString> handleEcmaStr(resultString);
322     EXPECT_STREQ("\"\\\"\\\\\\b\\f\\n\\r\\t\"", EcmaStringAccessor(handleEcmaStr).ToCString().c_str());
323 }
324 
Detach(void *param1, void *param2, void *hint, void *detachData)325 static void* Detach(void *param1, void *param2, void *hint, void *detachData)
326 {
327     GTEST_LOG_(INFO) << "detach is running";
328     if (param1 == nullptr && param2 == nullptr) {
329         GTEST_LOG_(INFO) << "detach: two params is nullptr";
330     }
331     if (hint == nullptr && detachData) {
332         GTEST_LOG_(INFO) << "detach: hint is nullptr";
333     }
334     return nullptr;
335 }
336 
Attach([[maybe_unused]] void *enginePointer, [[maybe_unused]] void *buffer, [[maybe_unused]] void *hint, [[maybe_unused]] void *attachData)337 static void* Attach([[maybe_unused]] void *enginePointer, [[maybe_unused]] void *buffer, [[maybe_unused]] void *hint,
338                     [[maybe_unused]] void *attachData)
339 {
340     GTEST_LOG_(INFO) << "attach is running";
341     return nullptr;
342 }
343 
CreateNativeBindingInfo(void* attach, void* detach)344 static panda::JSNApi::NativeBindingInfo* CreateNativeBindingInfo(void* attach, void* detach)
345 {
346     GTEST_LOG_(INFO) << "CreateNativeBindingInfo";
347     auto info = panda::JSNApi::NativeBindingInfo::CreateNewInstance();
348     info->attachFunc = attach;
349     info->detachFunc = detach;
350     return info;
351 }
352 
HWTEST_F_L0(JsonStringifierTest, Stringify_009)353 HWTEST_F_L0(JsonStringifierTest, Stringify_009)
354 {
355     ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
356     JsonStringifier stringifier(thread);
357 
358     EcmaVM *ecmaVM = thread->GetEcmaVM();
359     JSHandle<GlobalEnv> globalEnv = ecmaVM->GetGlobalEnv();
360     JSHandle<JSTaggedValue> objectFunc(globalEnv->GetObjectFunction());
361     JSHandle<JSObject> jsObject(factory->NewJSObjectByConstructor(JSHandle<JSFunction>(objectFunc), objectFunc));
362     EXPECT_TRUE(*jsObject != nullptr);
363 
364     JSHandle<JSTaggedValue> key1(factory->NewFromASCII("key1"));
365     auto info = CreateNativeBindingInfo(reinterpret_cast<void*>(Attach), reinterpret_cast<void*>(Detach));
366     JSHandle<JSTaggedValue> value1(factory->NewJSNativePointer(reinterpret_cast<void*>(info)));
367     JSObject::SetProperty(thread, JSHandle<JSTaggedValue>(jsObject), key1, value1);
368 
369     JSHandle<JSTaggedValue> key2(factory->NewFromASCII("key2"));
370     JSHandle<JSTaggedValue> value2(factory->NewFromASCII("abc"));
371     JSObject::SetProperty(thread, JSHandle<JSTaggedValue>(jsObject), key2, value2);
372 
373     JSHandle<JSTaggedValue> handleValue(thread, jsObject.GetTaggedValue());
374     JSHandle<JSTaggedValue> handleReplacer(thread, JSTaggedValue::Undefined());
375     JSHandle<JSTaggedValue> handleGap(thread, JSTaggedValue::Undefined());
376 
377     JSHandle<JSTaggedValue> resultString = stringifier.Stringify(handleValue, handleReplacer, handleGap);
378     EXPECT_TRUE(resultString->IsString());
379     JSHandle<EcmaString> handleEcmaStr(resultString);
380     EXPECT_STREQ("{\"key1\":{},\"key2\":\"abc\"}", EcmaStringAccessor(handleEcmaStr).ToCString().c_str());
381 }
382 }  // namespace panda::test
383