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. 31 var a = 12345; 32 assertTrue(JSON.stringify(this).indexOf('"a":12345') > 0); 33 assertTrue(JSON.stringify(this, null, 0).indexOf('"a":12345') > 0); 34 35 // Test JSON.stringify of array in dictionary mode. 36 function TestStringify(expected, input) { 37 assertEquals(expected, JSON.stringify(input)); 38 assertEquals(expected, JSON.stringify(input, null, 0)); 39 } 40 41 var array_1 = []; 42 var array_2 = []; 43 array_1[100000] = 1; 44 array_2[100000] = function() { return 1; }; 45 var nulls = ""; 46 for (var i = 0; i < 100000; i++) { 47 nulls += 'null,'; 48 } 49 expected_1 = '[' + nulls + '1]'; 50 expected_2 = '[' + nulls + 'null]'; 51 TestStringify(expected_1, array_1); 52 TestStringify(expected_2, array_2); 53 54 // Test JSValue with custom prototype. 55 var num_wrapper = Object(42); 56 num_wrapper.__proto__ = { __proto__: null, 57 toString: function() { return true; } }; 58 TestStringify('1', num_wrapper); 59 60 var str_wrapper = Object('2'); 61 str_wrapper.__proto__ = { __proto__: null, 62 toString: function() { return true; } }; 63 TestStringify('"true"', str_wrapper); 64 65 var bool_wrapper = Object(false); 66 bool_wrapper.__proto__ = { __proto__: null, 67 toString: function() { return true; } }; 68 // Note that toString function is not evaluated here! 69 TestStringify('false', bool_wrapper); 70 71 // Test getters. 72 var counter = 0; 73 var getter_obj = { get getter() { 74 counter++; 75 return 123; 76 } }; 77 TestStringify('{"getter":123}', getter_obj); 78 assertEquals(2, counter); 79 80 // Test toJSON function. 81 var tojson_obj = { toJSON: function() { 82 counter++; 83 return [1, 2]; 84 }, 85 a: 1}; 86 TestStringify('[1,2]', tojson_obj); 87 assertEquals(4, counter); 88 89 // Test that we don't recursively look for the toJSON function. 90 var tojson_proto_obj = { a: 'fail' }; 91 tojson_proto_obj.__proto__ = { toJSON: function() { 92 counter++; 93 return tojson_obj; 94 } }; 95 TestStringify('{"a":1}', tojson_proto_obj); 96 97 // Test toJSON produced by a getter. 98 var tojson_via_getter = { get toJSON() { 99 return function(x) { 100 counter++; 101 return 321; 102 }; 103 }, 104 a: 1 }; 105 TestStringify('321', tojson_via_getter); 106 107 // Test toJSON with key. 108 tojson_obj = { toJSON: function(key) { return key + key; } }; 109 var tojson_with_key_1 = { a: tojson_obj, b: tojson_obj }; 110 TestStringify('{"a":"aa","b":"bb"}', tojson_with_key_1); 111 var tojson_with_key_2 = [ tojson_obj, tojson_obj ]; 112 TestStringify('["00","11"]', tojson_with_key_2); 113 114 // Test toJSON with exception. 115 var tojson_ex = { toJSON: function(key) { throw "123" } }; 116 assertThrows(function() { JSON.stringify(tojson_ex); }); 117 assertThrows(function() { JSON.stringify(tojson_ex, null, 0); }); 118 119 // Test toJSON with access to this. 120 var obj = { toJSON: function(key) { return this.a + key; }, a: "x" }; 121 TestStringify('{"y":"xy"}', {y: obj}); 122 123 // Test holes in arrays. 124 var fast_smi = [1, 2, 3, 4]; 125 fast_smi.__proto__ = [7, 7, 7, 7]; 126 delete fast_smi[2]; 127 assertTrue(%HasFastSmiElements(fast_smi)); 128 TestStringify("[1,2,7,4]", fast_smi); 129 130 var fast_double = [1.1, 2, 3, 4]; 131 fast_double.__proto__ = [7, 7, 7, 7]; 132 133 delete fast_double[2]; 134 assertTrue(%HasFastDoubleElements(fast_double)); 135 TestStringify("[1.1,2,7,4]", fast_double); 136 137 var fast_obj = [1, 2, {}, {}]; 138 fast_obj.__proto__ = [7, 7, 7, 7]; 139 140 delete fast_obj[2]; 141 assertTrue(%HasFastObjectElements(fast_obj)); 142 TestStringify("[1,2,7,{}]", fast_obj); 143 144 var getter_side_effect = { a: 1, 145 get b() { 146 delete this.a; 147 delete this.c; 148 this.e = 5; 149 return 2; 150 }, 151 c: 3, 152 d: 4 }; 153 assertEquals('{"a":1,"b":2,"d":4}', JSON.stringify(getter_side_effect)); 154 assertEquals('{"b":2,"d":4,"e":5}', JSON.stringify(getter_side_effect)); 155 156 getter_side_effect = { a: 1, 157 get b() { 158 delete this.a; 159 delete this.c; 160 this.e = 5; 161 return 2; 162 }, 163 c: 3, 164 d: 4 }; 165 assertEquals('{"a":1,"b":2,"d":4}', 166 JSON.stringify(getter_side_effect, null, 0)); 167 assertEquals('{"b":2,"d":4,"e":5}', 168 JSON.stringify(getter_side_effect, null, 0)); 169 170 var non_enum = {}; 171 non_enum.a = 1; 172 Object.defineProperty(non_enum, "b", { value: 2, enumerable: false }); 173 non_enum.c = 3; 174 TestStringify('{"a":1,"c":3}', non_enum); 175 176 var str = "external"; 177 try { 178 externalizeString(str, true); 179 } catch (e) { } 180 TestStringify("\"external\"", str, null, 0); 181