1425bb815Sopenharmony_ci// Copyright JS Foundation and other contributors, http://js.foundation
2425bb815Sopenharmony_ci//
3425bb815Sopenharmony_ci// Licensed under the Apache License, Version 2.0 (the "License");
4425bb815Sopenharmony_ci// you may not use this file except in compliance with the License.
5425bb815Sopenharmony_ci// You may obtain a copy of the License at
6425bb815Sopenharmony_ci//
7425bb815Sopenharmony_ci//     http://www.apache.org/licenses/LICENSE-2.0
8425bb815Sopenharmony_ci//
9425bb815Sopenharmony_ci// Unless required by applicable law or agreed to in writing, software
10425bb815Sopenharmony_ci// distributed under the License is distributed on an "AS IS" BASIS
11425bb815Sopenharmony_ci// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12425bb815Sopenharmony_ci// See the License for the specific language governing permissions and
13425bb815Sopenharmony_ci// limitations under the License.
14425bb815Sopenharmony_ci
15425bb815Sopenharmony_ci// This test will not pass on FLOAT32 due to precision issues
16425bb815Sopenharmony_ci
17425bb815Sopenharmony_ci// Checking primitve types
18425bb815Sopenharmony_civar str;
19425bb815Sopenharmony_civar result;
20425bb815Sopenharmony_civar log;
21425bb815Sopenharmony_ci
22425bb815Sopenharmony_cifunction check_parse_error (str)
23425bb815Sopenharmony_ci{
24425bb815Sopenharmony_ci  try {
25425bb815Sopenharmony_ci    JSON.parse (str);
26425bb815Sopenharmony_ci    // Should throw a parse error.
27425bb815Sopenharmony_ci    assert (false);
28425bb815Sopenharmony_ci  } catch (e) {
29425bb815Sopenharmony_ci  }
30425bb815Sopenharmony_ci}
31425bb815Sopenharmony_ci
32425bb815Sopenharmony_cistr = ' null ';
33425bb815Sopenharmony_ciassert (JSON.parse (str) === null);
34425bb815Sopenharmony_cistr = 'true';
35425bb815Sopenharmony_ciassert (JSON.parse (str) === true);
36425bb815Sopenharmony_cistr = 'false';
37425bb815Sopenharmony_ciassert (JSON.parse (str) === false);
38425bb815Sopenharmony_cistr = '-32.5e002';
39425bb815Sopenharmony_ciassert (JSON.parse (str) == -3250);
40425bb815Sopenharmony_cistr = '"str"';
41425bb815Sopenharmony_ciassert (JSON.parse (str) == "str");
42425bb815Sopenharmony_cistr = '"\\b\\f\\n\\t\\r"'
43425bb815Sopenharmony_ciassert (JSON.parse (str) === "\b\f\n\t\r");
44425bb815Sopenharmony_ci/* Note: \u is parsed by the lexer, \\u is by the JSON parser. */
45425bb815Sopenharmony_cistr = '"\\u0000\\u001f"';
46425bb815Sopenharmony_ciassert (JSON.parse (str) === "\x00\x1f");
47425bb815Sopenharmony_cistr = '"\\ud801\\udc00\\ud801\udc00\ud801\\udc00\ud801\udc00"';
48425bb815Sopenharmony_ciassert (JSON.parse (str) === "\ud801\udc00\ud801\udc00\ud801\udc00\ud801\udc00");
49425bb815Sopenharmony_ci/* These surrogates do not form a valid surrogate pairs. */
50425bb815Sopenharmony_cistr = '"\\ud801,\\udc00,\\ud801,\udc00,\ud801,\\udc00,\ud801,\udc00"';
51425bb815Sopenharmony_ciassert (JSON.parse (str) === "\ud801,\udc00,\ud801,\udc00,\ud801,\udc00,\ud801,\udc00");
52425bb815Sopenharmony_ci
53425bb815Sopenharmony_cicheck_parse_error ('undefined');
54425bb815Sopenharmony_cicheck_parse_error ('falses');
55425bb815Sopenharmony_cicheck_parse_error ('+5');
56425bb815Sopenharmony_cicheck_parse_error ('5.');
57425bb815Sopenharmony_cicheck_parse_error ('01');
58425bb815Sopenharmony_cicheck_parse_error ('0x1');
59425bb815Sopenharmony_cicheck_parse_error ('0e-');
60425bb815Sopenharmony_cicheck_parse_error ('3e+a');
61425bb815Sopenharmony_cicheck_parse_error ('55e4,');
62425bb815Sopenharmony_cicheck_parse_error ('5 true');
63425bb815Sopenharmony_cicheck_parse_error ("'str'");
64425bb815Sopenharmony_cicheck_parse_error ('\x00');
65425bb815Sopenharmony_cicheck_parse_error ('"\x00"');
66425bb815Sopenharmony_cicheck_parse_error ('"\x1f"');
67425bb815Sopenharmony_ci
68425bb815Sopenharmony_ci// Checking objects
69425bb815Sopenharmony_cistr = ' { "x": 0, "yy": null, "zzz": { "A": 4.0, "BB": { "1": 63e-1 }, "CCC" : false } } ';
70425bb815Sopenharmony_ciresult = JSON.parse (str);
71425bb815Sopenharmony_ciassert (typeof result == "object");
72425bb815Sopenharmony_ciassert (result.x === 0);
73425bb815Sopenharmony_ciassert (result.yy === null);
74425bb815Sopenharmony_ciassert (typeof result.zzz == "object");
75425bb815Sopenharmony_ciassert (result.zzz.A === 4);
76425bb815Sopenharmony_ciassert (typeof result.zzz.BB == "object");
77425bb815Sopenharmony_ciassert (result.zzz.BB["1"] === 6.3);
78425bb815Sopenharmony_ciassert (result.zzz.CCC === false);
79425bb815Sopenharmony_ci
80425bb815Sopenharmony_cicheck_parse_error ('{');
81425bb815Sopenharmony_cicheck_parse_error ('{{{}');
82425bb815Sopenharmony_cicheck_parse_error ('{x:5}');
83425bb815Sopenharmony_cicheck_parse_error ('{true:4}');
84425bb815Sopenharmony_cicheck_parse_error ('{"x":5 "y":6}');
85425bb815Sopenharmony_cicheck_parse_error ('{"x":5,"y":6,}');
86425bb815Sopenharmony_cicheck_parse_error ('{"x":5,,"y":6}');
87425bb815Sopenharmony_ci
88425bb815Sopenharmony_ci// Checking arrays
89425bb815Sopenharmony_cistr = '[{"x":[]},[[]],{}, [ null ] ]';
90425bb815Sopenharmony_ciresult = JSON.parse (str);
91425bb815Sopenharmony_ciassert (result.length === 4);
92425bb815Sopenharmony_ciassert (typeof result === "object");
93425bb815Sopenharmony_ciassert (typeof result[0] === "object");
94425bb815Sopenharmony_ciassert (typeof result[0].x === "object");
95425bb815Sopenharmony_ciassert (result[0].x.length === 0);
96425bb815Sopenharmony_ciassert (result[1].length === 1);
97425bb815Sopenharmony_ciassert (result[1][0].length === 0);
98425bb815Sopenharmony_ciassert (typeof result[2] === "object");
99425bb815Sopenharmony_ciassert (result[3].length === 1);
100425bb815Sopenharmony_ciassert (result[3][0] === null);
101425bb815Sopenharmony_ci
102425bb815Sopenharmony_cicheck_parse_error ('[');
103425bb815Sopenharmony_cicheck_parse_error ('[[[]');
104425bb815Sopenharmony_cicheck_parse_error ('[ true null ]');
105425bb815Sopenharmony_cicheck_parse_error ('[1,,2]');
106425bb815Sopenharmony_cicheck_parse_error ('[1,2,]');
107425bb815Sopenharmony_cicheck_parse_error ('[1] [2]');
108425bb815Sopenharmony_ci
109425bb815Sopenharmony_ci// Checking parse with different primitive types
110425bb815Sopenharmony_ci
111425bb815Sopenharmony_ciassert (JSON.parse (null) == null);
112425bb815Sopenharmony_ciassert (JSON.parse (true) == true);
113425bb815Sopenharmony_ciassert (JSON.parse (3) == 3);
114425bb815Sopenharmony_ci
115425bb815Sopenharmony_citry {
116425bb815Sopenharmony_ci  JSON.parse (undefined);
117425bb815Sopenharmony_ci  // Should not be reached.
118425bb815Sopenharmony_ci  assert (false);
119425bb815Sopenharmony_ci} catch (e) {
120425bb815Sopenharmony_ci  assert (e instanceof SyntaxError);
121425bb815Sopenharmony_ci}
122425bb815Sopenharmony_ci
123425bb815Sopenharmony_ci// Checking parse with different object types
124425bb815Sopenharmony_ci
125425bb815Sopenharmony_ciobject = { toString: function() { return false; } };
126425bb815Sopenharmony_ciassert (JSON.parse (object) == false);
127425bb815Sopenharmony_ci
128425bb815Sopenharmony_ciobject = {"a": 3, "b": "foo"};
129425bb815Sopenharmony_citry {
130425bb815Sopenharmony_ci  JSON.parse (object);
131425bb815Sopenharmony_ci  // Should not be reached.
132425bb815Sopenharmony_ci  assert (false);
133425bb815Sopenharmony_ci} catch (e) {
134425bb815Sopenharmony_ci  assert (e instanceof SyntaxError);
135425bb815Sopenharmony_ci}
136425bb815Sopenharmony_ci
137425bb815Sopenharmony_ciarray = [3, "foo"];
138425bb815Sopenharmony_citry {
139425bb815Sopenharmony_ci  JSON.parse (array);
140425bb815Sopenharmony_ci  // Should not be reached.
141425bb815Sopenharmony_ci  assert (false);
142425bb815Sopenharmony_ci} catch (e) {
143425bb815Sopenharmony_ci  assert (e instanceof SyntaxError);
144425bb815Sopenharmony_ci}
145425bb815Sopenharmony_ci
146425bb815Sopenharmony_ciassert (JSON.parse (new Number (3)) == 3);
147425bb815Sopenharmony_ciassert (JSON.parse (new Boolean (true)) == true);
148425bb815Sopenharmony_ci
149425bb815Sopenharmony_ciobject = new String ('{"a": 3, "b": "foo"}');
150425bb815Sopenharmony_ciresult = JSON.parse (object);
151425bb815Sopenharmony_ci
152425bb815Sopenharmony_ciassert (result.a == 3);
153425bb815Sopenharmony_ciassert (result.b == "foo");
154425bb815Sopenharmony_ci
155425bb815Sopenharmony_ci// Checking reviver
156425bb815Sopenharmony_ci
157425bb815Sopenharmony_cifunction toStringReviver(k, v)
158425bb815Sopenharmony_ci{
159425bb815Sopenharmony_ci  log += "<" + k + ">:" + (typeof v == "number" ? v : "(obj)") + ", ";
160425bb815Sopenharmony_ci  return v;
161425bb815Sopenharmony_ci}
162425bb815Sopenharmony_ci
163425bb815Sopenharmony_cistr = '{ "a":1, "b":2, "c": { "d":4, "e": { "f":6 } } }';
164425bb815Sopenharmony_cilog = "";
165425bb815Sopenharmony_ciJSON.parse (str, toStringReviver);
166425bb815Sopenharmony_ciassert (log === "<a>:1, <b>:2, <d>:4, <f>:6, <e>:(obj), <c>:(obj), <>:(obj), ");
167425bb815Sopenharmony_ci
168425bb815Sopenharmony_cistr = '[ 32, 47, 33 ]';
169425bb815Sopenharmony_cilog = "";
170425bb815Sopenharmony_ciJSON.parse (str, toStringReviver);
171425bb815Sopenharmony_ciassert (log === "<0>:32, <1>:47, <2>:33, <>:(obj), ");
172425bb815Sopenharmony_ci
173425bb815Sopenharmony_ci// Defining properties multiple times
174425bb815Sopenharmony_ci
175425bb815Sopenharmony_cistr = ' { "a":1, "b":2, "a":3 } ';
176425bb815Sopenharmony_cilog = "";
177425bb815Sopenharmony_ciJSON.parse (str, toStringReviver);
178425bb815Sopenharmony_ciassert (log === "<a>:3, <b>:2, <>:(obj), ");
179425bb815Sopenharmony_ci
180425bb815Sopenharmony_cistr = ' { "a":1, "b":2, "b":3 } ';
181425bb815Sopenharmony_cilog = "";
182425bb815Sopenharmony_ciJSON.parse (str, toStringReviver);
183425bb815Sopenharmony_ciassert (log === "<a>:1, <b>:3, <>:(obj), ");
184425bb815Sopenharmony_ci
185425bb815Sopenharmony_cistr = ' { "a":1, "b":{}, "b":[], "a":2, "b":3, "c":4 } ';
186425bb815Sopenharmony_cilog = "";
187425bb815Sopenharmony_ciJSON.parse (str, toStringReviver);
188425bb815Sopenharmony_ciassert (log === "<a>:2, <b>:3, <c>:4, <>:(obj), ");
189425bb815Sopenharmony_ci
190425bb815Sopenharmony_ci// Changing property value
191425bb815Sopenharmony_ci
192425bb815Sopenharmony_cistr = ' { "a":1, "b":2, "c":3 } ';
193425bb815Sopenharmony_ciresult = JSON.parse (str, function (k, v) {
194425bb815Sopenharmony_ci  if (k == "a")
195425bb815Sopenharmony_ci  {
196425bb815Sopenharmony_ci    return 8;
197425bb815Sopenharmony_ci  }
198425bb815Sopenharmony_ci  if (k == "b")
199425bb815Sopenharmony_ci  {
200425bb815Sopenharmony_ci    return 9;
201425bb815Sopenharmony_ci  }
202425bb815Sopenharmony_ci  if (k == "c")
203425bb815Sopenharmony_ci  {
204425bb815Sopenharmony_ci    return void 0;
205425bb815Sopenharmony_ci  }
206425bb815Sopenharmony_ci  return v;
207425bb815Sopenharmony_ci});
208425bb815Sopenharmony_ci
209425bb815Sopenharmony_ciassert (result.a === 8);
210425bb815Sopenharmony_ciassert (result.b === 9);
211425bb815Sopenharmony_ciassert (result.c === void 0);
212425bb815Sopenharmony_ci
213425bb815Sopenharmony_ci// Adding / deleting properties
214425bb815Sopenharmony_ci
215425bb815Sopenharmony_cistr = ' { "a":1, "b":2 } ';
216425bb815Sopenharmony_cilog = "";
217425bb815Sopenharmony_ciresult = JSON.parse (str, function (k, v) {
218425bb815Sopenharmony_ci  if (k == "a")
219425bb815Sopenharmony_ci  {
220425bb815Sopenharmony_ci    // Deleted properties must still be enumerated.
221425bb815Sopenharmony_ci    delete this["b"];
222425bb815Sopenharmony_ci    // New properties must not be enumerated.
223425bb815Sopenharmony_ci    this.c = 4;
224425bb815Sopenharmony_ci  }
225425bb815Sopenharmony_ci  if (k != "")
226425bb815Sopenharmony_ci  {
227425bb815Sopenharmony_ci    log += "<" + k + ">:" + v + " ";
228425bb815Sopenharmony_ci  }
229425bb815Sopenharmony_ci  return v;
230425bb815Sopenharmony_ci});
231425bb815Sopenharmony_ci
232425bb815Sopenharmony_ciassert (log === "<a>:1 <b>:undefined ");
233425bb815Sopenharmony_ciassert (result.a === 1);
234425bb815Sopenharmony_ciassert (result.b === void 0);
235425bb815Sopenharmony_ciassert (result.c === 4);
236425bb815Sopenharmony_ci
237425bb815Sopenharmony_ci// Changing properties to accessors
238425bb815Sopenharmony_ci
239425bb815Sopenharmony_cistr = ' { "a":1, "b":2, "c":3 } ';
240425bb815Sopenharmony_cilog = "";
241425bb815Sopenharmony_ciJSON.parse (str, function (k, v) {
242425bb815Sopenharmony_ci  if (k == "a")
243425bb815Sopenharmony_ci  {
244425bb815Sopenharmony_ci    Object.defineProperty(this, "b", {
245425bb815Sopenharmony_ci      enumerable: true,
246425bb815Sopenharmony_ci      configurable: true,
247425bb815Sopenharmony_ci      get: function() { return 12; }
248425bb815Sopenharmony_ci    });
249425bb815Sopenharmony_ci    Object.defineProperty(this, "c", {
250425bb815Sopenharmony_ci      enumerable: true,
251425bb815Sopenharmony_ci      configurable: true,
252425bb815Sopenharmony_ci      set: function(val) { }
253425bb815Sopenharmony_ci    });
254425bb815Sopenharmony_ci  }
255425bb815Sopenharmony_ci  if (k != "")
256425bb815Sopenharmony_ci  {
257425bb815Sopenharmony_ci    log += "<" + k + ">:" + v + " ";
258425bb815Sopenharmony_ci  }
259425bb815Sopenharmony_ci  return v;
260425bb815Sopenharmony_ci});
261425bb815Sopenharmony_ciassert (log === "<a>:1 <b>:12 <c>:undefined ");
262425bb815Sopenharmony_ci
263425bb815Sopenharmony_ci// Forcing extra walk steps
264425bb815Sopenharmony_ci
265425bb815Sopenharmony_cistr = ' { "a":1, "b":2 } ';
266425bb815Sopenharmony_cilog = "";
267425bb815Sopenharmony_ciJSON.parse (str, function (k, v) {
268425bb815Sopenharmony_ci  if (k == "a")
269425bb815Sopenharmony_ci  {
270425bb815Sopenharmony_ci     this.b = { x:3, y:4 };
271425bb815Sopenharmony_ci  }
272425bb815Sopenharmony_ci  if (k != "")
273425bb815Sopenharmony_ci  {
274425bb815Sopenharmony_ci    log += "<" + k + ">:" + v + " ";
275425bb815Sopenharmony_ci  }
276425bb815Sopenharmony_ci  return v;
277425bb815Sopenharmony_ci});
278425bb815Sopenharmony_ciassert (log === "<a>:1 <x>:3 <y>:4 <b>:[object Object] ");
279425bb815Sopenharmony_ci
280425bb815Sopenharmony_ci// Setting a property to read-only, and change its value.
281425bb815Sopenharmony_ci
282425bb815Sopenharmony_cistr = ' { "a":1, "b":2 } ';
283425bb815Sopenharmony_ciresult = JSON.parse (str, function (k, v) {
284425bb815Sopenharmony_ci  if (k == "a")
285425bb815Sopenharmony_ci  {
286425bb815Sopenharmony_ci    Object.defineProperty(this, "b", {
287425bb815Sopenharmony_ci      enumerable: true,
288425bb815Sopenharmony_ci      // FIXME: Should work with configurable: true.
289425bb815Sopenharmony_ci      configurable: false,
290425bb815Sopenharmony_ci      writable: false,
291425bb815Sopenharmony_ci      value: 2
292425bb815Sopenharmony_ci    });
293425bb815Sopenharmony_ci    return 8;
294425bb815Sopenharmony_ci  }
295425bb815Sopenharmony_ci  if (k == "b")
296425bb815Sopenharmony_ci  {
297425bb815Sopenharmony_ci    return 9;
298425bb815Sopenharmony_ci  }
299425bb815Sopenharmony_ci  return v;
300425bb815Sopenharmony_ci});
301425bb815Sopenharmony_ci
302425bb815Sopenharmony_ciassert (result.a === 8);
303425bb815Sopenharmony_ciassert (result.b === 2);
304425bb815Sopenharmony_ci
305425bb815Sopenharmony_ci// Throw error in the reviver
306425bb815Sopenharmony_ci
307425bb815Sopenharmony_citry {
308425bb815Sopenharmony_ci  str = ' { "a":1, "b":2 } ';
309425bb815Sopenharmony_ci  result = JSON.parse (str, function (k, v) { throw new ReferenceError("error"); } );
310425bb815Sopenharmony_ci  assert(false);
311425bb815Sopenharmony_ci} catch (e) {
312425bb815Sopenharmony_ci  assert (e.message === "error");
313425bb815Sopenharmony_ci  assert (e instanceof ReferenceError);
314425bb815Sopenharmony_ci}
315425bb815Sopenharmony_ci
316425bb815Sopenharmony_ci// Throw error in a getter
317425bb815Sopenharmony_ci
318425bb815Sopenharmony_citry {
319425bb815Sopenharmony_ci  str = ' { "a":1, "b":2 } ';
320425bb815Sopenharmony_ci  JSON.parse (str, function (k, v) {
321425bb815Sopenharmony_ci    if (k == "a")
322425bb815Sopenharmony_ci    {
323425bb815Sopenharmony_ci      Object.defineProperty(this, "b", {
324425bb815Sopenharmony_ci        enumerable: true,
325425bb815Sopenharmony_ci        configurable: true,
326425bb815Sopenharmony_ci        get: function() { throw new ReferenceError("error"); }
327425bb815Sopenharmony_ci      });
328425bb815Sopenharmony_ci    }
329425bb815Sopenharmony_ci    return v;
330425bb815Sopenharmony_ci  });
331425bb815Sopenharmony_ci  assert(false);
332425bb815Sopenharmony_ci} catch (e) {
333425bb815Sopenharmony_ci  assert (e.message === "error");
334425bb815Sopenharmony_ci  assert (e instanceof ReferenceError);
335425bb815Sopenharmony_ci}
336425bb815Sopenharmony_ci
337425bb815Sopenharmony_ci// Checking reviver with different primitive types
338425bb815Sopenharmony_ci
339425bb815Sopenharmony_cistr = ' { "a":1 } ';
340425bb815Sopenharmony_ci
341425bb815Sopenharmony_ciresult = JSON.parse (str, 4);
342425bb815Sopenharmony_ciassert (result.a == 1);
343425bb815Sopenharmony_ci
344425bb815Sopenharmony_ciresult = JSON.parse (str, null);
345425bb815Sopenharmony_ciassert (result.a == 1);
346425bb815Sopenharmony_ci
347425bb815Sopenharmony_ciresult = JSON.parse (str, undefined);
348425bb815Sopenharmony_ciassert (result.a == 1);
349425bb815Sopenharmony_ci
350425bb815Sopenharmony_ciresult = JSON.parse (str, true);
351425bb815Sopenharmony_ciassert (result.a == 1);
352425bb815Sopenharmony_ci
353425bb815Sopenharmony_ciresult = JSON.parse (str, "foo");
354425bb815Sopenharmony_ciassert (result.a == 1);
355425bb815Sopenharmony_ci
356425bb815Sopenharmony_ci// Checking reviver with different object types
357425bb815Sopenharmony_ci
358425bb815Sopenharmony_cistr = ' { "a":1 } ';
359425bb815Sopenharmony_ci
360425bb815Sopenharmony_ciresult = JSON.parse(str, new Boolean (true));
361425bb815Sopenharmony_ciassert (result.a == 1);
362425bb815Sopenharmony_ci
363425bb815Sopenharmony_ciresult = JSON.parse(str, new String ("foo"));
364425bb815Sopenharmony_ciassert (result.a == 1);
365425bb815Sopenharmony_ci
366425bb815Sopenharmony_ciresult = JSON.parse(str, new Number (3));
367425bb815Sopenharmony_ciassert (result.a == 1);
368425bb815Sopenharmony_ci
369425bb815Sopenharmony_ciresult = JSON.parse(str, {"a": 2});
370425bb815Sopenharmony_ciassert (result.a == 1);
371425bb815Sopenharmony_ci
372425bb815Sopenharmony_ciresult = JSON.parse(str, [1, 2, 3]);
373425bb815Sopenharmony_ciassert (result.a == 1);
374