1// Copyright 2012 the V8 project authors. All rights reserved. 2// Redistribution and use in source and binary forms, with or without 3// modification, are permitted provided that the following conditions are 4// met: 5// 6// * Redistributions of source code must retain the above copyright 7// notice, this list of conditions and the following disclaimer. 8// * Redistributions in binary form must reproduce the above 9// copyright notice, this list of conditions and the following 10// disclaimer in the documentation and/or other materials provided 11// with the distribution. 12// * Neither the name of Google Inc. nor the names of its 13// contributors may be used to endorse or promote products derived 14// from this software without specific prior written permission. 15// 16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 28// Flags: --allow-natives-syntax --expose-externalize-string 29 30// Test JSON.stringify on the global object. 31var a = 12345; 32assertTrue(JSON.stringify(this).indexOf('"a":12345') > 0); 33assertTrue(JSON.stringify(this, null, 0).indexOf('"a":12345') > 0); 34 35// Test JSON.stringify of array in dictionary mode. 36function TestStringify(expected, input) { 37 assertEquals(expected, JSON.stringify(input)); 38 assertEquals(expected, JSON.stringify(input, null, 0)); 39} 40 41var array_1 = []; 42var array_2 = []; 43array_1[1<<17] = 1; 44array_2[1<<17] = function() { return 1; }; 45var nulls = "null,"; 46for (var i = 0; i < 17; i++) { 47 nulls += nulls; 48} 49 50expected_1 = '[' + nulls + '1]'; 51expected_2 = '[' + nulls + 'null]'; 52TestStringify(expected_1, array_1); 53TestStringify(expected_2, array_2); 54 55// Test JSValue with custom prototype. 56var num_wrapper = Object(42); 57num_wrapper.__proto__ = { __proto__: null, 58 toString: function() { return true; } }; 59TestStringify('1', num_wrapper); 60 61var str_wrapper = Object('2'); 62str_wrapper.__proto__ = { __proto__: null, 63 toString: function() { return true; } }; 64TestStringify('"true"', str_wrapper); 65 66var bool_wrapper = Object(false); 67bool_wrapper.__proto__ = { __proto__: null, 68 toString: function() { return true; } }; 69// Note that toString function is not evaluated here! 70TestStringify('false', bool_wrapper); 71 72// Test getters. 73var counter = 0; 74var getter_obj = { get getter() { 75 counter++; 76 return 123; 77 } }; 78TestStringify('{"getter":123}', getter_obj); 79assertEquals(2, counter); 80 81// Test toJSON function. 82var tojson_obj = { toJSON: function() { 83 counter++; 84 return [1, 2]; 85 }, 86 a: 1}; 87TestStringify('[1,2]', tojson_obj); 88assertEquals(4, counter); 89 90// Test that we don't recursively look for the toJSON function. 91var tojson_proto_obj = { a: 'fail' }; 92tojson_proto_obj.__proto__ = { toJSON: function() { 93 counter++; 94 return tojson_obj; 95 } }; 96TestStringify('{"a":1}', tojson_proto_obj); 97 98// Test toJSON produced by a getter. 99var tojson_via_getter = { get toJSON() { 100 return function(x) { 101 counter++; 102 return 321; 103 }; 104 }, 105 a: 1 }; 106TestStringify('321', tojson_via_getter); 107 108assertThrows(function() { 109 JSON.stringify({ get toJSON() { throw "error"; } }); 110}); 111 112// Test toJSON with key. 113tojson_obj = { toJSON: function(key) { return key + key; } }; 114var tojson_with_key_1 = { a: tojson_obj, b: tojson_obj }; 115TestStringify('{"a":"aa","b":"bb"}', tojson_with_key_1); 116var tojson_with_key_2 = [ tojson_obj, tojson_obj ]; 117TestStringify('["00","11"]', tojson_with_key_2); 118 119// Test toJSON with exception. 120var tojson_ex = { toJSON: function(key) { throw "123" } }; 121assertThrows(function() { JSON.stringify(tojson_ex); }); 122assertThrows(function() { JSON.stringify(tojson_ex, null, 0); }); 123 124// Test toJSON with access to this. 125var obj = { toJSON: function(key) { return this.a + key; }, a: "x" }; 126TestStringify('{"y":"xy"}', {y: obj}); 127 128// Test holes in arrays. 129var fast_smi = [1, 2, 3, 4]; 130fast_smi.__proto__ = [7, 7, 7, 7]; 131delete fast_smi[2]; 132assertTrue(%HasFastSmiElements(fast_smi)); 133TestStringify("[1,2,7,4]", fast_smi); 134 135var fast_double = [1.1, 2, 3, 4]; 136fast_double.__proto__ = [7, 7, 7, 7]; 137 138delete fast_double[2]; 139assertTrue(%HasFastDoubleElements(fast_double)); 140TestStringify("[1.1,2,7,4]", fast_double); 141 142var fast_obj = [1, 2, {}, {}]; 143fast_obj.__proto__ = [7, 7, 7, 7]; 144 145delete fast_obj[2]; 146assertTrue(%HasFastObjectElements(fast_obj)); 147TestStringify("[1,2,7,{}]", fast_obj); 148 149var getter_side_effect = { a: 1, 150 get b() { 151 delete this.a; 152 delete this.c; 153 this.e = 5; 154 return 2; 155 }, 156 c: 3, 157 d: 4 }; 158assertEquals('{"a":1,"b":2,"d":4}', JSON.stringify(getter_side_effect)); 159assertEquals('{"b":2,"d":4,"e":5}', JSON.stringify(getter_side_effect)); 160 161getter_side_effect = { a: 1, 162 get b() { 163 delete this.a; 164 delete this.c; 165 this.e = 5; 166 return 2; 167 }, 168 c: 3, 169 d: 4 }; 170assertEquals('{"a":1,"b":2,"d":4}', 171 JSON.stringify(getter_side_effect, null, 0)); 172assertEquals('{"b":2,"d":4,"e":5}', 173 JSON.stringify(getter_side_effect, null, 0)); 174 175var non_enum = {}; 176non_enum.a = 1; 177Object.defineProperty(non_enum, "b", { value: 2, enumerable: false }); 178non_enum.c = 3; 179TestStringify('{"a":1,"c":3}', non_enum); 180 181var str = "external"; 182try { 183 externalizeString(str, true); 184} catch (e) { } 185TestStringify("\"external\"", str, null, 0); 186 187var o = {}; 188o.somespecialproperty = 10; 189o["\x19"] = 10; 190assertThrows("JSON.parse('{\"somespecialproperty\":100, \"\x19\":10}')"); 191