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