1 2 function createTests() { 3 var simpleArray = ['a', 'b', 'c']; 4 var simpleObject = {a:"1", b:"2", c:"3"}; 5 var complexArray = ['a', 'b', 'c',,,simpleObject, simpleArray, [simpleObject,simpleArray]]; 6 var complexObject = {a:"1", b:"2", c:"3", d:undefined, e:null, "":12, get f(){ return simpleArray; }, array: complexArray}; 7 var simpleArrayWithProto = ['d', 'e', 'f']; 8 simpleArrayWithProto.__proto__ = simpleObject; 9 var simpleObjectWithProto = {d:"4", e:"5", f:"6", __proto__:simpleObject}; 10 var complexArrayWithProto = ['d', 'e', 'f',,,simpleObjectWithProto, simpleArrayWithProto, [simpleObjectWithProto,simpleArrayWithProto]]; 11 complexArrayWithProto.__proto__ = simpleObjectWithProto; 12 var complexObjectWithProto = {d:"4", e:"5", f:"6", g:undefined, h:null, "":12, get i(){ return simpleArrayWithProto; }, array2: complexArrayWithProto, __proto__:complexObject}; 13 var objectWithSideEffectGetter = {get b() {this.foo=1;}}; 14 var objectWithSideEffectGetterAndProto = {__proto__:{foo:"bar"}, get b() {this.foo=1;}}; 15 var arrayWithSideEffectGetter = []; 16 arrayWithSideEffectGetter.__defineGetter__("b", function(){this.foo=1;}); 17 var arrayWithSideEffectGetterAndProto = []; 18 arrayWithSideEffectGetterAndProto.__defineGetter__("b", function(){this.foo=1;}); 19 arrayWithSideEffectGetterAndProto.__proto__ = {foo:"bar"}; 20 var result = []; 21 result.push(function(jsonObject){ 22 return jsonObject.stringify(1); 23 }); 24 result.push(function(jsonObject){ 25 return jsonObject.stringify(1.5); 26 }); 27 result.push(function(jsonObject){ 28 return jsonObject.stringify(-1); 29 }); 30 result.push(function(jsonObject){ 31 return jsonObject.stringify(-1.5); 32 }); 33 result.push(function(jsonObject){ 34 return jsonObject.stringify(null); 35 }); 36 result.push(function(jsonObject){ 37 return jsonObject.stringify("string"); 38 }); 39 result.push(function(jsonObject){ 40 return jsonObject.stringify(new Number(0)); 41 }); 42 result.push(function(jsonObject){ 43 return jsonObject.stringify(new Number(1)); 44 }); 45 result.push(function(jsonObject){ 46 return jsonObject.stringify(new Number(1.5)); 47 }); 48 result.push(function(jsonObject){ 49 return jsonObject.stringify(new Number(-1)); 50 }); 51 result.push(function(jsonObject){ 52 return jsonObject.stringify(new Number(-1.5)); 53 }); 54 result.push(function(jsonObject){ 55 return jsonObject.stringify(new String("a string object")); 56 }); 57 result.push(function(jsonObject){ 58 return jsonObject.stringify(new Boolean(true)); 59 }); 60 result.push(function(jsonObject){ 61 var value = new Number(1); 62 value.valueOf = function() { return 2; } 63 return jsonObject.stringify(value); 64 }); 65 result[result.length - 1].expected = '2'; 66 result.push(function(jsonObject){ 67 var value = new Boolean(true); 68 value.valueOf = function() { return 2; } 69 return jsonObject.stringify(value); 70 }); 71 result[result.length - 1].expected = '2'; 72 result.push(function(jsonObject){ 73 var value = new String("fail"); 74 value.toString = function() { return "converted string"; } 75 return jsonObject.stringify(value); 76 }); 77 result[result.length - 1].expected = '"converted string"'; 78 result.push(function(jsonObject){ 79 return jsonObject.stringify(true); 80 }); 81 result.push(function(jsonObject){ 82 return jsonObject.stringify(false); 83 }); 84 result.push(function(jsonObject){ 85 return jsonObject.stringify(new Date(0)); 86 }); 87 result.push(function(jsonObject){ 88 return jsonObject.stringify({toJSON: Date.prototype.toJSON}); 89 }); 90 result[result.length - 1].throws = true; 91 result.push(function(jsonObject){ 92 return jsonObject.stringify({toJSON: Date.prototype.toJSON, toISOString: function(){ return "custom toISOString"; }}); 93 }); 94 result.push(function(jsonObject){ 95 return jsonObject.stringify({toJSON: Date.prototype.toJSON, toISOString: function(){ return {}; }}); 96 }); 97 result[result.length - 1].throws = true; 98 result.push(function(jsonObject){ 99 return jsonObject.stringify({toJSON: Date.prototype.toJSON, toISOString: function(){ throw "An exception"; }}); 100 }); 101 result[result.length - 1].throws = true; 102 result.push(function(jsonObject){ 103 var d = new Date(0); 104 d.toISOString = null; 105 return jsonObject.stringify(d); 106 }); 107 result[result.length - 1].throws = true; 108 result.push(function(jsonObject){ 109 var d = new Date(0); 110 d.toJSON = undefined; 111 return jsonObject.stringify(d); 112 }); 113 result.push(function(jsonObject){ 114 return jsonObject.stringify({get Foo() { return "bar"; }}); 115 }); 116 result.push(function(jsonObject){ 117 return jsonObject.stringify({get Foo() { this.foo="wibble"; return "bar"; }}); 118 }); 119 result.push(function(jsonObject){ 120 var count = 0; 121 jsonObject.stringify({get Foo() { count++; return "bar"; }}); 122 return count; 123 }); 124 result.push(function(jsonObject){ 125 var count = 0; 126 return jsonObject.stringify({get Foo() { count++; delete this.bar; return "bar"; }, bar: "wibble"}); 127 }); 128 result.push(function(jsonObject){ 129 var count = 0; 130 return jsonObject.stringify({a:"1", b:"2", c:"3", 5:4, 4:5, 2:6, 1:7}); 131 }); 132 result.push(function(jsonObject){ 133 var allString = true; 134 jsonObject.stringify({a:"1", b:"2", c:"3", 5:4, 4:5, 2:6, 1:7}, function(k,v){allString = allString && (typeof k == "string"); return v}); 135 return allString; 136 }); 137 result.push(function(jsonObject){ 138 var allString = true; 139 jsonObject.stringify([1,2,3,4,5], function(k,v){allString = allString && (typeof k == "string"); return v}); 140 return allString; 141 }); 142 result.push(function(jsonObject){ 143 var allString = true; 144 var array = []; 145 return jsonObject.stringify({a:"1", b:"2", c:"3", 5:4, 4:5, 2:6, 1:7}, array); 146 }); 147 result.push(function(jsonObject){ 148 var allString = true; 149 var array = ["a"]; 150 return jsonObject.stringify({get a(){return 1;array[1]="b";array[2]="c"}, b:"2", c:"3"}, array); 151 }); 152 result.push(function(jsonObject){ 153 var allString = true; 154 var array = [{toString:function(){array[0]='a'; array[1]='c'; array[2]='b'; return 'a'}}]; 155 return jsonObject.stringify(simpleObject, array); 156 }); 157 result.push(function(jsonObject){ 158 var allString = true; 159 var array = [{toString:function(){array[0]='a'; array[1]='c'; array[2]='b'; return 'a'}}]; 160 return jsonObject.stringify(simpleObjectWithProto, array); 161 }); 162 result.push(function(jsonObject){ 163 var allString = true; 164 var array = [1, new Number(2), NaN, Infinity, -Infinity, new String("str")]; 165 return jsonObject.stringify({"1":"1","2":"2","NaN":"NaN","Infinity":"Infinity","-Infinity":"-Infinity","str":"str"}, array); 166 }); 167 result[result.length - 1].expected = '{"1":"1","2":"2","NaN":"NaN","Infinity":"Infinity","-Infinity":"-Infinity","str":"str"}'; 168 result.push(function(jsonObject){ 169 var allString = true; 170 var array = ["1","2","3"]; 171 return jsonObject.stringify({1:'a', 2:'b', 3:'c'}, array); 172 }); 173 result.push(function(jsonObject){ 174 var allString = true; 175 var array = ["1","2","3"]; 176 return jsonObject.stringify(simpleArray, array); 177 }); 178 result.push(function(jsonObject){ 179 return jsonObject.stringify(simpleArray, null, " "); 180 }); 181 result.push(function(jsonObject){ 182 return jsonObject.stringify(simpleArray, null, 4); 183 }); 184 result.push(function(jsonObject){ 185 return jsonObject.stringify(simpleArray, null, "ab"); 186 }); 187 result.push(function(jsonObject){ 188 return jsonObject.stringify(simpleArray, null, 4); 189 }); 190 result.push(function(jsonObject){ 191 return jsonObject.stringify(simpleObject, null, " "); 192 }); 193 result.push(function(jsonObject){ 194 return jsonObject.stringify(simpleObject, null, 4); 195 }); 196 result.push(function(jsonObject){ 197 return jsonObject.stringify(simpleObject, null, "ab"); 198 }); 199 result.push(function(jsonObject){ 200 return jsonObject.stringify(simpleObject, null, 4); 201 }); 202 result.push(function(jsonObject){ 203 return jsonObject.stringify(simpleObject, null, 10); 204 }); 205 result.push(function(jsonObject){ 206 return jsonObject.stringify(simpleObject, null, 11); 207 }); 208 result[result.length - 1].expected = JSON.stringify(simpleObject, null, 10); 209 result.push(function(jsonObject){ 210 return jsonObject.stringify(simpleObject, null, " "); 211 }); 212 result[result.length - 1].expected = JSON.stringify(simpleObject, null, 10); 213 result.push(function(jsonObject){ 214 return jsonObject.stringify(simpleObject, null, " "); 215 }); 216 result[result.length - 1].expected = JSON.stringify(simpleObject, null, 10); 217 result.push(function(jsonObject){ 218 return jsonObject.stringify(complexArray, null, " "); 219 }); 220 result.push(function(jsonObject){ 221 return jsonObject.stringify(complexArray, null, 4); 222 }); 223 result.push(function(jsonObject){ 224 return jsonObject.stringify(complexArray, null, "ab"); 225 }); 226 result.push(function(jsonObject){ 227 return jsonObject.stringify(complexArray, null, 4); 228 }); 229 result.push(function(jsonObject){ 230 return jsonObject.stringify(complexObject, null, " "); 231 }); 232 result.push(function(jsonObject){ 233 return jsonObject.stringify(complexObject, null, 4); 234 }); 235 result.push(function(jsonObject){ 236 return jsonObject.stringify(complexObject, null, "ab"); 237 }); 238 result.push(function(jsonObject){ 239 return jsonObject.stringify(complexObject, null, 4); 240 }); 241 result.push(function(jsonObject){ 242 var allString = true; 243 var array = ["1","2","3"]; 244 return jsonObject.stringify(simpleArrayWithProto, array); 245 }); 246 result.push(function(jsonObject){ 247 return jsonObject.stringify(simpleArrayWithProto, null, " "); 248 }); 249 result.push(function(jsonObject){ 250 return jsonObject.stringify(simpleArrayWithProto, null, 4); 251 }); 252 result.push(function(jsonObject){ 253 return jsonObject.stringify(simpleArrayWithProto, null, "ab"); 254 }); 255 result.push(function(jsonObject){ 256 return jsonObject.stringify(simpleArrayWithProto, null, 4); 257 }); 258 result.push(function(jsonObject){ 259 return jsonObject.stringify(simpleObjectWithProto, null, " "); 260 }); 261 result.push(function(jsonObject){ 262 return jsonObject.stringify(simpleObjectWithProto, null, 4); 263 }); 264 result.push(function(jsonObject){ 265 return jsonObject.stringify(simpleObjectWithProto, null, "ab"); 266 }); 267 result.push(function(jsonObject){ 268 return jsonObject.stringify(simpleObjectWithProto, null, 4); 269 }); 270 result.push(function(jsonObject){ 271 return jsonObject.stringify(simpleObjectWithProto, null, 10); 272 }); 273 result.push(function(jsonObject){ 274 return jsonObject.stringify(simpleObjectWithProto, null, 11); 275 }); 276 result[result.length - 1].expected = JSON.stringify(simpleObjectWithProto, null, 10); 277 result.push(function(jsonObject){ 278 return jsonObject.stringify(simpleObjectWithProto, null, " "); 279 }); 280 result[result.length - 1].expected = JSON.stringify(simpleObjectWithProto, null, 10); 281 result.push(function(jsonObject){ 282 return jsonObject.stringify(simpleObjectWithProto, null, " "); 283 }); 284 result[result.length - 1].expected = JSON.stringify(simpleObjectWithProto, null, 10); 285 result.push(function(jsonObject){ 286 return jsonObject.stringify(complexArrayWithProto, null, " "); 287 }); 288 result.push(function(jsonObject){ 289 return jsonObject.stringify(complexArrayWithProto, null, 4); 290 }); 291 result.push(function(jsonObject){ 292 return jsonObject.stringify(complexArrayWithProto, null, "ab"); 293 }); 294 result.push(function(jsonObject){ 295 return jsonObject.stringify(complexArrayWithProto, null, 4); 296 }); 297 result.push(function(jsonObject){ 298 return jsonObject.stringify(complexObjectWithProto, null, " "); 299 }); 300 result.push(function(jsonObject){ 301 return jsonObject.stringify(complexObjectWithProto, null, 4); 302 }); 303 result.push(function(jsonObject){ 304 return jsonObject.stringify(complexObjectWithProto, null, "ab"); 305 }); 306 result.push(function(jsonObject){ 307 return jsonObject.stringify(complexObjectWithProto, null, 4); 308 }); 309 result.push(function(jsonObject){ 310 return jsonObject.stringify(objectWithSideEffectGetter); 311 }); 312 result.push(function(jsonObject){ 313 return jsonObject.stringify(objectWithSideEffectGetterAndProto); 314 }); 315 result.push(function(jsonObject){ 316 return jsonObject.stringify(arrayWithSideEffectGetter); 317 }); 318 result.push(function(jsonObject){ 319 return jsonObject.stringify(arrayWithSideEffectGetterAndProto); 320 }); 321 var replaceTracker; 322 function replaceFunc(key, value) { 323 replaceTracker += key + "("+(typeof key)+")" + JSON.stringify(value) + ";"; 324 return value; 325 } 326 result.push(function(jsonObject){ 327 replaceTracker = ""; 328 jsonObject.stringify([1,2,3,,,,4,5,6], replaceFunc); 329 return replaceTracker; 330 }); 331 result[result.length - 1].expected = '(string)[1,2,3,null,null,null,4,5,6];0(number)1;1(number)2;2(number)3;3(number)undefined;4(number)undefined;5(number)undefined;6(number)4;7(number)5;8(number)6;' 332 result.push(function(jsonObject){ 333 replaceTracker = ""; 334 jsonObject.stringify({a:"a", b:"b", c:"c", 3: "d", 2: "e", 1: "f"}, replaceFunc); 335 return replaceTracker; 336 }); 337 result[result.length - 1].expected = '(string){"a":"a","b":"b","c":"c","3":"d","2":"e","1":"f"};a(string)"a";b(string)"b";c(string)"c";3(string)"d";2(string)"e";1(string)"f";'; 338 result.push(function(jsonObject){ 339 var count = 0; 340 var array = [{toString:function(){count++; array[0]='a'; array[1]='c'; array[2]='b'; return 'a'}}]; 341 jsonObject.stringify(simpleObject, array); 342 return count; 343 }); 344 result.push(function(jsonObject){ 345 var allString = true; 346 var array = [{toString:function(){array[0]='a'; array[1]='c'; array[2]='b'; return 'a'}}, 'b', 'c']; 347 return jsonObject.stringify(simpleObject, array); 348 }); 349 result.push(function(jsonObject){ 350 var count = 0; 351 var array = [{toString:function(){count++; array[0]='a'; array[1]='c'; array[2]='b'; return 'a'}}, 'b', 'c']; 352 jsonObject.stringify(simpleObject, array); 353 return count; 354 }); 355 result.push(function(jsonObject){ 356 return jsonObject.stringify({a:"1", get b() { this.a="foo"; return "getter"; }, c:"3"}); 357 }); 358 result.push(function(jsonObject){ 359 return jsonObject.stringify({a:"1", get b() { this.c="foo"; return "getter"; }, c:"3"}); 360 }); 361 result.push(function(jsonObject){ 362 var setterCalled = false; 363 jsonObject.stringify({a:"1", set b(s) { setterCalled = true; return "setter"; }, c:"3"}); 364 return setterCalled; 365 }); 366 result.push(function(jsonObject){ 367 return jsonObject.stringify({a:"1", get b(){ return "getter"; }, set b(s) { return "setter"; }, c:"3"}); 368 }); 369 result.push(function(jsonObject){ 370 return jsonObject.stringify(new Array(10)); 371 }); 372 result.push(function(jsonObject){ 373 return jsonObject.stringify([undefined,,null,0,false]); 374 }); 375 result.push(function(jsonObject){ 376 return jsonObject.stringify({p1:undefined,p2:null,p3:0,p4:false}); 377 }); 378 var cycleTracker = ""; 379 var cyclicObject = { get preSelf1() { cycleTracker+="preSelf1,"; return "preSelf1"; }, 380 preSelf2: {toJSON:function(){cycleTracker+="preSelf2,"; return "preSelf2"}}, 381 self: [], 382 get postSelf1() { cycleTracker+="postSelf1,"; return "postSelf1" }, 383 postSelf2: {toJSON:function(){cycleTracker+="postSelf2,"; return "postSelf2"}}, 384 toJSON : function(key) { cycleTracker += key + "("+(typeof key)+"):" + this; return this; } 385 }; 386 cyclicObject.self = cyclicObject; 387 result.push(function(jsonObject){ 388 cycleTracker = ""; 389 return jsonObject.stringify(cyclicObject); 390 }); 391 result[result.length - 1].throws = true; 392 result.push(function(jsonObject){ 393 cycleTracker = ""; 394 try { jsonObject.stringify(cyclicObject); } catch(e) { cycleTracker += " -> exception" } 395 return cycleTracker; 396 }); 397 result[result.length - 1].expected = "(string):[object Object]preSelf1,preSelf2,self(string):[object Object] -> exception" 398 var cyclicArray = [{toJSON : function(key,value) { cycleTracker += key + "("+(typeof key)+"):" + this; cycleTracker += "first,"; return this; }}, 399 cyclicArray, 400 {toJSON : function(key,value) { cycleTracker += key + "("+(typeof key)+"):" + this; cycleTracker += "second,"; return this; }}]; 401 cyclicArray[1] = cyclicArray; 402 result.push(function(jsonObject){ 403 cycleTracker = ""; 404 return jsonObject.stringify(cyclicArray); 405 }); 406 result[result.length - 1].throws = true; 407 result.push(function(jsonObject){ 408 cycleTracker = ""; 409 try { jsonObject.stringify(cyclicArray); } catch(e) { cycleTracker += " -> exception" } 410 return cycleTracker; 411 }); 412 result[result.length - 1].expected = "0(number):[object Object]first, -> exception"; 413 function createArray(len, o) { var r = []; for (var i = 0; i < len; i++) r[i] = o; return r; } 414 var getterCalls; 415 var magicObject = createArray(10, {abcdefg: [1,2,5,"ab", null, undefined, true, false,,], 416 get calls() {return ++getterCalls; }, 417 "123":createArray(15, "foo"), 418 "":{a:"b"}}); 419 result.push(function(jsonObject){ 420 getterCalls = 0; 421 return jsonObject.stringify(magicObject) + " :: getter calls = " + getterCalls; 422 }); 423 result.push(function(jsonObject){ 424 return jsonObject.stringify(undefined); 425 }); 426 result.push(function(jsonObject){ 427 return jsonObject.stringify(null); 428 }); 429 result.push(function(jsonObject){ 430 return jsonObject.stringify({toJSON:function(){ return undefined; }}); 431 }); 432 result.push(function(jsonObject){ 433 return jsonObject.stringify({toJSON:function(){ return null; }}); 434 }); 435 result.push(function(jsonObject){ 436 return jsonObject.stringify([{toJSON:function(){ return undefined; }}]); 437 }); 438 result.push(function(jsonObject){ 439 return jsonObject.stringify([{toJSON:function(){ return null; }}]); 440 }); 441 result.push(function(jsonObject){ 442 return jsonObject.stringify({a:{toJSON:function(){ return undefined; }}}); 443 }); 444 result.push(function(jsonObject){ 445 return jsonObject.stringify({a:{toJSON:function(){ return null; }}}); 446 }); 447 result.push(function(jsonObject){ 448 return jsonObject.stringify({a:{toJSON:function(){ return function(){}; }}}); 449 }); 450 result.push(function(jsonObject){ 451 return jsonObject.stringify({a:function(){}}); 452 }); 453 result.push(function(jsonObject){ 454 var deepObject = {}; 455 for (var i = 0; i < 2048; i++) 456 deepObject = {next:deepObject}; 457 return jsonObject.stringify(deepObject); 458 }); 459 result.push(function(jsonObject){ 460 var deepArray = []; 461 for (var i = 0; i < 2048; i++) 462 deepArray = [deepArray]; 463 return jsonObject.stringify(deepArray); 464 }); 465 result.push(function(jsonObject){ 466 var depth = 0; 467 function toDeepVirtualJSONObject() { 468 if (++depth >= 2048) 469 return {}; 470 var r = {}; 471 r.toJSON = toDeepVirtualJSONObject; 472 return {recurse: r}; 473 } 474 return jsonObject.stringify(toDeepVirtualJSONObject()); 475 }); 476 result.push(function(jsonObject){ 477 var depth = 0; 478 function toDeepVirtualJSONArray() { 479 if (++depth >= 2048) 480 return []; 481 var r = []; 482 r.toJSON = toDeepJSONArray; 483 return [r]; 484 } 485 return jsonObject.stringify(toDeepVirtualJSONArray()); 486 }); 487 var fullCharsetString = ""; 488 for (var i = 0; i < 65536; i++) 489 fullCharsetString += String.fromCharCode(i); 490 result.push(function(jsonObject){ 491 return jsonObject.stringify(fullCharsetString); 492 }); 493 return result; 494 } 495 var tests = createTests(); 496 for (var i = 0; i < tests.length; i++) { 497 try { 498 debug(tests[i]); 499 if (tests[i].throws) 500 shouldThrow('tests[i](nativeJSON)'); 501 else if (tests[i].expected) 502 shouldBe('tests[i](nativeJSON)', "tests[i].expected"); 503 else 504 shouldBe('tests[i](nativeJSON)', "tests[i](JSON)"); 505 }catch(e){} 506 } 507 successfullyParsed = true; 508 509