• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * Copyright (c) 2023 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/*
17 * @tc.name:jsonstringifier
18 * @tc.desc:test JSON.stringify
19 * @tc.type: FUNC
20 * @tc.require: issue#I7DFJC
21 */
22
23try {
24    const v0 = [1, 2, 3, 4]
25    function Foo(a) {
26        Object.defineProperty(this, "ownKeys", { configurable: true, enumerable: true, value: a });
27    }
28    const v1 = new Foo("2060681564", v0, 9.53248718923);
29    const v2 = new Proxy({}, v1);
30    JSON.stringify(v2);
31    assert_unreachable();
32} catch (e) {
33  assert_equal(true,true);
34}
35
36var obj = {
37    2147483648: 2289
38}
39assert_equal(JSON.stringify(obj),'{"2147483648":2289}');
40
41const a = new Uint32Array(0x10);
42let  b = a.__proto__;
43b[1073741823] = {}
44assert_equal(JSON.stringify(a),'{"0":0,"1":0,"2":0,"3":0,"4":0,"5":0,"6":0,"7":0,"8":0,"9":0,"10":0,"11":0,"12":0,"13":0,"14":0,"15":0}')
45
46let o = {
47    get g() {
48        this[1225] |= 4294967295;
49        return 9;
50    },
51    "f1":1,
52    "f2":1,
53    "f3":1,
54    "f4":1,
55    "f5":1,
56    "f6":1,
57    "f7":1,
58    "f8":1,
59}
60assert_equal(JSON.stringify(o),'{"g":9,"f1":1,"f2":1,"f3":1,"f4":1,"f5":1,"f6":1,"f7":1,"f8":1}')
61let o2 = {
62    get g() {
63        delete this.f1;
64        return 8;
65    },
66    "f1":1,
67    "f2":1,
68}
69assert_equal(JSON.stringify(o2),'{"g":8,"f2":1}')
70var handler2 = {
71    get:function(target,name) {
72        delete parent2.c;
73        return name.toUpperCase();
74    },
75}
76var proxy2 = new Proxy({},handler2);
77var parent2 = {a:proxy2,c:"remove"};
78assert_equal(JSON.stringify(parent2),'{"a":{}}')
79
80var obj={
81    get 1() {
82        delete this['2'];
83    },
84    2:2,
85    3:3,
86}
87assert_equal(JSON.stringify(obj),'{"3":3}')
88
89var List = undefined;
90var LinkedList = undefined;
91if (globalThis["ArkPrivate"] != undefined) {
92    List = ArkPrivate.Load(ArkPrivate.List);
93    let list = new List();
94    list.add({"f1": 1});
95    list.add({"f2": 2});
96    print(JSON.stringify(list));
97
98    LinkedList = ArkPrivate.Load(ArkPrivate.LinkedList);
99    let linkList = new LinkedList();
100    linkList.add({"f3": 3});
101    linkList.add({"f4": 4});
102    print(JSON.stringify(linkList));
103}
104
105var v6="123456789\u0000";
106assert_equal(JSON.stringify([{}]),'[{}]')
107assert_equal(JSON.stringify([String]),'[null]')
108assert_equal(JSON.stringify(v6),'"123456789\\u0000"')
109
110
111var handler2 = {
112  get: function(target, name) {
113    delete parent2.c;
114    return name.toUpperCase();
115  }
116}
117var proxy2 = new Proxy({}, handler2);
118var parent2 = { a: "delete", b: proxy2, c: "remove" };
119assert_equal(JSON.stringify(parent2),'{"a":"delete","b":{}}')
120parent2.c = "remove";  // Revert side effect.
121assert_equal(JSON.stringify(parent2),'{"a":"delete","b":{}}')
122Reflect.defineProperty(globalThis,"c",{
123    get:()=>{
124        delete this["d"];
125        return "c";
126    },
127    enumerable:true,
128});
129Reflect.set(globalThis,"d","d");
130JSON.stringify(globalThis);
131
132let str1="\uD83D";
133let str2="\uDE0E";
134let str3="\uDE0E\"测试";
135let str4=new String("\uDE0E\"测试2")
136let str=str1+str2
137obj={};
138obj[str1]=str1;
139obj[str2]=str2;
140obj[str3]=str3;
141obj[str4]=str4;
142obj[str]=str
143assert_equal(JSON.stringify(obj),'{"\\ud83d":"\\ud83d","\\ude0e":"\\ude0e","\\ude0e\\"测试":"\\ude0e\\"测试","\\ude0e\\"测试2":"\\ude0e\\"测试2","��":"��"}')
144
145assert_equal(JSON.stringify(str),'"��"')
146assert_equal(JSON.stringify(str1),'"\\ud83d"')
147assert_equal(JSON.stringify(str2),'"\\ude0e"')
148assert_equal(JSON.stringify(str3),'"\\ude0e\\"测试"')
149assert_equal(JSON.stringify(str4),'"\\ude0e\\"测试2"')
150
151{
152  var actual = [];
153  var test_obj = {o: false};
154  var replaced = {o: false, replaced: true};
155
156  function replacer(key, value) {
157      actual.push({ holder: this, key, value });
158      if (actual.length === 1) return replaced;
159      if (key === "o") return true;
160      return value;
161  }
162  assert_equal(`{"o":true,"replaced":true}` == JSON.stringify(test_obj, replacer),true);
163  const expect = [
164      {
165        holder: { "": { o: false } },
166        key: "",
167        value: { o: false }
168      },
169      {
170        holder: { o: false, replaced: true },
171        key: "o",
172        value: false
173      },
174      {
175        holder: { o: false, replaced: true },
176        key: "replaced",
177        value: true
178      }
179    ];
180  assert_equal(JSON.stringify(expect) == JSON.stringify(actual),true);
181  assert_equal(actual[0].holder[""] == test_obj,true);
182};
183{
184  var actual = [];
185  var test_obj = {o: false, toJSON };
186  var nested = { toJSON: nestedToJSON };
187  var toJSON1 = {o: false, toJSON1: true }
188  var replaced = {o: false, replaced: true, nested };
189  var toJSON2 = { toJSON2: true };
190
191  function toJSON(key, value) {
192    return toJSON1;
193  }
194  function nestedToJSON(key, value) {
195    return toJSON2;
196  }
197  function replacer(key, value) {
198      actual.push({ holder: this, key, value });
199      if (actual.length === 1) return replaced;
200      if (key === "o") return true;
201      return value;
202  }
203  assert_equal(`{"o":true,"replaced":true,"nested":{"toJSON2":true}}` ==
204            JSON.stringify(test_obj, replacer),true);
205  const expect = [
206      {
207        holder: { "": { o: false, toJSON: toJSON } },
208        key: "",
209        value: { o: false, toJSON1: true }
210      },
211      {
212        holder: { o: false, replaced: true, nested: { toJSON: nestedToJSON } },
213        key: "o",
214        value: false
215      },
216      {
217        holder: { o: false, replaced: true, nested: { toJSON: nestedToJSON } },
218        key: "replaced",
219        value: true
220      },
221      {
222        holder: { o: false, replaced: true, nested: { toJSON: nestedToJSON } },
223        key: "nested",
224        value: { toJSON2: true }
225      },
226      {
227        holder: { toJSON2: true },
228        key: "toJSON2",
229        value: true
230      }
231  ];
232  assert_equal(JSON.stringify(expect) == JSON.stringify(actual),true);
233  assert_equal(actual[0].holder[""] == test_obj,true);
234};
235let obj1 = {
236  get a(){
237      this[102400] = 1;
238      return "a";
239  },
240  b:"b",
241}
242Object.keys(obj1);
243assert_equal(JSON.stringify(obj1),'{"a":"a","b":"b"}');
244
245try {
246  let loop = {};
247  loop.obj = loop;
248  JSON.stringify(loop);
249  assert_unreachable();
250} catch (err) {
251  assert_equal(err.name,'TypeError');
252  assert_equal(err.message.includes("circular structure"),true);
253}
254
255const specialString = '"Hello\nWorld\\tThis is a test string with special characters: \u00A9 \u00AE "';
256const nestedObj = {
257  level1: {
258    level2: {
259      level3: {
260        message: specialString,
261        number: 42,
262        truthy: true,
263        anotherObj: {
264          key: 'value'
265        },
266        array: [1, 'two', false, { nested: 'object' }]
267      }
268    }
269  }
270};
271assert_equal((JSON.stringify(nestedObj, null, 2)).substring(2, 5), '  "');
272assert_equal((JSON.stringify(nestedObj, null, " ")).substring(2, 4), ' "');
273
274try {
275    let arkPrivate = globalThis.ArkPrivate;
276    var List = arkPrivate.Load(arkPrivate.List);
277    const v10 = new List();
278    v10.add(v10);
279    JSON.stringify(v10);
280    assert_unreachable();
281} catch (err) {
282    assert_equal("Caught an error: "+ err, "Caught an error: TypeError: stack contains value, usually caused by circular structure");
283}
284
285const testspaceobj = {
286  name: "abc",
287  age: 123,
288  city: "Shanghai"
289};
290const testspaceobjAssert = JSON.stringify(testspaceobj, null, Infinity);
291assert_equal(JSON.stringify(testspaceobj, null, Infinity),testspaceobjAssert);
292
293{
294    let obj = {};
295    let tmp = obj;
296    for (let i = 0; i < 5000; i++) {
297        tmp.name = {};
298        tmp = tmp.name;
299    }
300    try {
301        let res = JSON.stringify(obj);
302        assert_unreachable();
303    } catch (error) {
304        assert_equal(error instanceof RangeError, true);
305    }
306}
307
308{
309  let obj = {};
310  for (let i = 0; i < 9; i++) {
311      obj["k" + i] = "value" + i;
312  }
313  let exceptStr1 = '{"k0":"value0","k1":"value1","k2":"value2","k3":"value3","k4":"value4","k5":"value5","k6":"value6","k7":"value7","k8":"value8"}';
314  assert_equal(JSON.stringify(obj), exceptStr1);
315
316  for (let i = 9; i < 20; i++) {
317      obj["k" + i] = "value" + i;
318  }
319  let exceptStr2 = '{"k0":"value0","k1":"value1","k2":"value2","k3":"value3","k4":"value4","k5":"value5","k6":"value6","k7":"value7","k8":"value8","k9":"value9","k10":"value10","k11":"value11","k12":"value12","k13":"value13","k14":"value14","k15":"value15","k16":"value16","k17":"value17","k18":"value18","k19":"value19"}';
320  assert_equal(JSON.stringify(obj), exceptStr2);
321}
322
323{
324  // undefined, function, symbol
325  let obj = {
326    a: undefined,
327    b: function() {},
328    c: Symbol("test"),
329    d: 123,
330    e: "string"
331  };
332  assert_equal(JSON.stringify(obj), '{"d":123,"e":"string"}');
333  assert_equal(JSON.stringify([undefined, function(){}, Symbol("test")]), '[null,null,null]');
334}
335
336{
337  // special numbers
338  let obj = {
339    nan: NaN,
340    inf: Infinity,
341    ninf: -Infinity
342  };
343  assert_equal(JSON.stringify(obj), '{"nan":null,"inf":null,"ninf":null}');
344}
345
346{
347  // control characters
348  let obj = {
349    str: "Line1\nLine2\tTabbed\"Quote\"\\Backslash"
350  };
351  assert_equal(JSON.stringify(obj), '{"str":"Line1\\nLine2\\tTabbed\\"Quote\\"\\\\Backslash"}');
352}
353
354{
355  // deep string
356  let obj = {a: {b: {c: {d: {e: {f: "deep"}}}}}};
357  assert_equal(JSON.stringify(obj), '{"a":{"b":{"c":{"d":{"e":{"f":"deep"}}}}}}');
358}
359
360{
361  // replace
362  let obj = {
363    a: 1,
364    b: 2,
365    c: 3
366  };
367  assert_equal(JSON.stringify(obj, ["a", "c"]), '{"a":1,"c":3}');
368}
369
370
371{
372  // repalce
373  let obj = { a: 1, b: 2, c: 3 };
374  function replacer(key, value) {
375    if (value === 2) return undefined;
376    return value;
377  }
378  assert_equal(JSON.stringify(obj, replacer), '{"a":1,"c":3}');
379}
380
381{
382  // space
383  let obj = { a: 1, b: { c: 2 } };
384  let expected = `{
385  "a": 1,
386  "b": {
387    "c": 2
388  }
389}`;
390  assert_equal(JSON.stringify(obj, null, 2), expected);
391}
392
393{
394  // sparse array
395  let arr = [1,,3];
396  assert_equal(JSON.stringify(arr), '[1,null,3]');
397}
398
399{
400  // BigInt
401  try {
402    let obj = { big: 10n };
403    JSON.stringify(obj);
404    assert_unreachable();
405  } catch (err) {
406    assert_equal(err instanceof TypeError, true);
407  }
408}
409
410{
411  // Chinese characters
412  let str = "你好,世界";
413  assert_equal(JSON.stringify(str), '"你好,世界"');
414}
415
416{
417  // Emoji characters
418  let smile = "��";
419  assert_equal(JSON.stringify(smile), '"��"');
420}
421
422{
423  // Emoji characters
424  let emoji_str = "������";
425  assert_equal(JSON.stringify(emoji_str), '"������"');
426}
427
428{
429  // Chinese and Emoji
430  let mixed = "测试一下��ok";
431  assert_equal(JSON.stringify(mixed), '"测试一下��ok"');
432}
433
434{
435  // alone high surrogate
436  let lone_high = "\uD83D";
437  assert_equal(JSON.stringify(lone_high), '"\\ud83d"');
438}
439
440{
441  // alone low surrogate
442  let lone_low = "\uDE0E";
443  assert_equal(JSON.stringify(lone_low), '"\\ude0e"');
444}
445
446{
447  // wrong order of high and low surrogate
448  let invalid_surrogate = "\uDE0E\uD83D";
449  assert_equal(JSON.stringify(invalid_surrogate), '"\\ude0e\\ud83d"');
450}
451
452{
453  // right pair of high and low surrogate
454  let valid_surrogate = "\uD83D\uDE0E";
455  assert_equal(JSON.stringify(valid_surrogate), '"��"');
456}
457
458test_end();