Extend test coverage for JSON.stringify's slow path.
authoryangguo@chromium.org <yangguo@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Wed, 20 Mar 2013 14:07:30 +0000 (14:07 +0000)
committeryangguo@chromium.org <yangguo@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Wed, 20 Mar 2013 14:07:30 +0000 (14:07 +0000)
R=verwaest@chromium.org
BUG=

Review URL: https://chromiumcodereview.appspot.com/12702009

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@14008 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

test/mjsunit/json.js
test/mjsunit/json2.js
test/mjsunit/regress/regress-2374.js
test/mjsunit/regress/regress-2570.js
test/mjsunit/regress/regress-753.js
test/mjsunit/regress/regress-latin-1.js

index 79826db..c72c153 100644 (file)
@@ -225,23 +225,28 @@ TestInvalid('"Garbage""After string"');
 
 // Stringify
 
-assertEquals("true", JSON.stringify(true));
-assertEquals("false", JSON.stringify(false));
-assertEquals("null", JSON.stringify(null));
-assertEquals("false", JSON.stringify({toJSON: function () { return false; }}));
-assertEquals("4", JSON.stringify(4));
-assertEquals('"foo"', JSON.stringify("foo"));
-assertEquals("null", JSON.stringify(Infinity));
-assertEquals("null", JSON.stringify(-Infinity));
-assertEquals("null", JSON.stringify(NaN));
-assertEquals("4", JSON.stringify(new Number(4)));
-assertEquals('"bar"', JSON.stringify(new String("bar")));
-
-assertEquals('"foo\\u0000bar"', JSON.stringify("foo\0bar"));
-assertEquals('"f\\"o\'o\\\\b\\ba\\fr\\nb\\ra\\tz"',
-             JSON.stringify("f\"o\'o\\b\ba\fr\nb\ra\tz"));
-
-assertEquals("[1,2,3]", JSON.stringify([1, 2, 3]));
+function TestStringify(expected, input) {
+  assertEquals(expected, JSON.stringify(input));
+  assertEquals(expected, JSON.stringify(input, null, 0));
+}
+
+TestStringify("true", true);
+TestStringify("false", false);
+TestStringify("null", null);
+TestStringify("false", {toJSON: function () { return false; }});
+TestStringify("4", 4);
+TestStringify('"foo"', "foo");
+TestStringify("null", Infinity);
+TestStringify("null", -Infinity);
+TestStringify("null", NaN);
+TestStringify("4", new Number(4));
+TestStringify('"bar"', new String("bar"));
+
+TestStringify('"foo\\u0000bar"', "foo\0bar");
+TestStringify('"f\\"o\'o\\\\b\\ba\\fr\\nb\\ra\\tz"',
+              "f\"o\'o\\b\ba\fr\nb\ra\tz");
+
+TestStringify("[1,2,3]", [1, 2, 3]);
 assertEquals("[\n 1,\n 2,\n 3\n]", JSON.stringify([1, 2, 3], null, 1));
 assertEquals("[\n  1,\n  2,\n  3\n]", JSON.stringify([1, 2, 3], null, 2));
 assertEquals("[\n  1,\n  2,\n  3\n]",
@@ -256,33 +261,38 @@ assertEquals("[1,2,[3,[4],5],6,7]",
              JSON.stringify([1, 2, [3, [4], 5], 6, 7], null));
 assertEquals("[2,4,[6,[8],10],12,14]",
              JSON.stringify([1, 2, [3, [4], 5], 6, 7], DoubleNumbers));
-assertEquals('["a","ab","abc"]', JSON.stringify(["a","ab","abc"]));
-assertEquals('{"a":1,"c":true}',
-              JSON.stringify({ a : 1,
-                               b : function() { 1 },
-                               c : true,
-                               d : function() { 2 } }));
-assertEquals('[1,null,true,null]',
-             JSON.stringify([1, function() { 1 }, true, function() { 2 }]));
-assertEquals('"toJSON 123"',
-             JSON.stringify({ toJSON : function() { return 'toJSON 123'; } }));
-assertEquals('{"a":321}',
-             JSON.stringify({ a : { toJSON : function() { return 321; } } }));
+TestStringify('["a","ab","abc"]', ["a","ab","abc"]);
+TestStringify('{"a":1,"c":true}', { a : 1,
+                                    b : function() { 1 },
+                                    c : true,
+                                    d : function() { 2 } });
+TestStringify('[1,null,true,null]',
+              [1, function() { 1 }, true, function() { 2 }]);
+TestStringify('"toJSON 123"',
+              { toJSON : function() { return 'toJSON 123'; } });
+TestStringify('{"a":321}',
+              { a : { toJSON : function() { return 321; } } });
 var counter = 0;
 assertEquals('{"getter":123}',
              JSON.stringify({ get getter() { counter++; return 123; } }));
 assertEquals(1, counter);
-assertEquals('{"a":"abc","b":"\u1234bc"}',
-             JSON.stringify({ a : "abc", b : "\u1234bc" }));
+assertEquals('{"getter":123}',
+             JSON.stringify({ get getter() { counter++; return 123; } },
+                            null,
+                            0));
+assertEquals(2, counter);
+
+TestStringify('{"a":"abc","b":"\u1234bc"}',
+              { a : "abc", b : "\u1234bc" });
 
 
 var a = { a : 1, b : 2 };
 delete a.a;
-assertEquals('{"b":2}', JSON.stringify(a));
+TestStringify('{"b":2}', a);
 
 var b = {};
 b.__proto__ = { toJSON : function() { return 321;} };
-assertEquals("321", JSON.stringify(b));
+TestStringify("321", b);
 
 var array = [""];
 var expected = '""';
@@ -291,18 +301,19 @@ for (var i = 0; i < 10000; i++) {
   expected = '"",' + expected;
 }
 expected = '[' + expected + ']';
-assertEquals(expected, JSON.stringify(array));
+TestStringify(expected, array);
 
 
 var circular = [1, 2, 3];
 circular[2] = circular;
 assertThrows(function () { JSON.stringify(circular); }, TypeError);
+assertThrows(function () { JSON.stringify(circular, null, 0); }, TypeError);
 
 var singleton = [];
 var multiOccurrence = [singleton, singleton, singleton];
-assertEquals("[[],[],[]]", JSON.stringify(multiOccurrence));
+TestStringify("[[],[],[]]", multiOccurrence);
 
-assertEquals('{"x":5,"y":6}', JSON.stringify({x:5,y:6}));
+TestStringify('{"x":5,"y":6}', {x:5,y:6});
 assertEquals('{"x":5}', JSON.stringify({x:5,y:6}, ['x']));
 assertEquals('{\n "a": "b",\n "c": "d"\n}',
              JSON.stringify({a:"b",c:"d"}, null, 1));
@@ -312,7 +323,7 @@ assertEquals('{"y":6,"x":5}', JSON.stringify({x:5,y:6}, ['y', 'x']));
 var checker = {};
 var array = [checker];
 checker.toJSON = function(key) { return 1 + key; };
-assertEquals('["10"]', JSON.stringify(array));
+TestStringify('["10"]', array);
 
 // The gap is capped at ten characters if specified as string.
 assertEquals('{\n          "a": "b",\n          "c": "d"\n}',
@@ -329,12 +340,11 @@ assertEquals('{"x":"42"}', JSON.stringify({x: String}, newx));
 assertEquals('{"x":42}', JSON.stringify({x: Number}, newx));
 assertEquals('{"x":true}', JSON.stringify({x: Boolean}, newx));
 
-assertEquals(undefined, JSON.stringify(undefined));
-assertEquals(undefined, JSON.stringify(function () { }));
+TestStringify(undefined, undefined);
+TestStringify(undefined, function () { });
 // Arrays with missing, undefined or function elements have those elements
 // replaced by null.
-assertEquals("[null,null,null]",
-             JSON.stringify([undefined,,function(){}]));
+TestStringify("[null,null,null]", [undefined,,function(){}]);
 
 // Objects with undefined or function properties (including replaced properties)
 // have those properties ignored.
@@ -415,16 +425,15 @@ var re = /Is callable/;
 var reJSON = /Is callable/;
 reJSON.toJSON = function() { return "has toJSON"; };
 
-assertEquals(
-    '[37,null,1,"foo","37","true",null,"has toJSON",{},"has toJSON"]',
-    JSON.stringify([num37, numFoo, numTrue,
-                    strFoo, str37, strTrue,
-                    func, funcJSON, re, reJSON]));
+TestStringify('[37,null,1,"foo","37","true",null,"has toJSON",{},"has toJSON"]',
+              [num37, numFoo, numTrue,
+               strFoo, str37, strTrue,
+               func, funcJSON, re, reJSON]);
 
 
 var oddball = Object(42);
 oddball.__proto__ = { __proto__: null, toString: function() { return true; } };
-assertEquals('1', JSON.stringify(oddball));
+TestStringify('1', oddball);
 
 var getCount = 0;
 var callCount = 0;
@@ -433,10 +442,10 @@ var counter = { get toJSON() { getCount++;
                                                    return 42; }; } };
 
 // RegExps are not callable, so they are stringified as objects.
-assertEquals('{}', JSON.stringify(/regexp/));
-assertEquals('42', JSON.stringify(counter));
-assertEquals(1, getCount);
-assertEquals(1, callCount);
+TestStringify('{}', /regexp/);
+TestStringify('42', counter);
+assertEquals(2, getCount);
+assertEquals(2, callCount);
 
 var oddball2 = Object(42);
 var oddball3 = Object("foo");
@@ -445,13 +454,13 @@ oddball3.__proto__ = { __proto__: null,
                        valueOf: function() { return true; } };
 oddball2.__proto__ = { __proto__: null,
                        toJSON: function () { return oddball3; } }
-assertEquals('"true"', JSON.stringify(oddball2));
+TestStringify('"true"', oddball2);
 
 
 var falseNum = Object("37");
 falseNum.__proto__ = Number.prototype;
 falseNum.toString = function() { return 42; };
-assertEquals('"42"', JSON.stringify(falseNum));
+TestStringify('"42"', falseNum);
 
 // Parse an object value as __proto__.
 var o1 = JSON.parse('{"__proto__":[]}');
@@ -472,4 +481,4 @@ assertTrue(o2.hasOwnProperty("__proto__"));
 assertTrue(Object.prototype.isPrototypeOf(o2));
 
 var json = '{"stuff before slash\\\\stuff after slash":"whatever"}';
-assertEquals(json, JSON.stringify(JSON.parse(json)));
+TestStringify(json, JSON.parse(json));
index 4c0b8f5..6a72051 100644 (file)
 // Test JSON.stringify on the global object.
 var a = 12345;
 assertTrue(JSON.stringify(this).indexOf('"a":12345') > 0);
+assertTrue(JSON.stringify(this, null, 0).indexOf('"a":12345') > 0);
 
 // Test JSON.stringify of array in dictionary mode.
+function TestStringify(expected, input) {
+  assertEquals(expected, JSON.stringify(input));
+  assertEquals(expected, JSON.stringify(input, null, 0));
+}
+
 var array_1 = [];
 var array_2 = [];
 array_1[100000] = 1;
@@ -42,25 +48,25 @@ for (var i = 0; i < 100000; i++) {
 }
 expected_1 = '[' + nulls + '1]';
 expected_2 = '[' + nulls + 'null]';
-assertEquals(expected_1, JSON.stringify(array_1));
-assertEquals(expected_2, JSON.stringify(array_2));
+TestStringify(expected_1, array_1);
+TestStringify(expected_2, array_2);
 
 // Test JSValue with custom prototype.
 var num_wrapper = Object(42);
 num_wrapper.__proto__ = { __proto__: null,
                           toString: function() { return true; } };
-assertEquals('1', JSON.stringify(num_wrapper));
+TestStringify('1', num_wrapper);
 
 var str_wrapper = Object('2');
 str_wrapper.__proto__ = { __proto__: null,
                           toString: function() { return true; } };
-assertEquals('"true"', JSON.stringify(str_wrapper));
+TestStringify('"true"', str_wrapper);
 
 var bool_wrapper = Object(false);
 bool_wrapper.__proto__ = { __proto__: null,
                            toString: function() { return true; } };
 // Note that toString function is not evaluated here!
-assertEquals('false', JSON.stringify(bool_wrapper));
+TestStringify('false', bool_wrapper);
 
 // Test getters.
 var counter = 0;
@@ -68,8 +74,8 @@ var getter_obj = { get getter() {
                          counter++;
                          return 123;
                        } };
-assertEquals('{"getter":123}', JSON.stringify(getter_obj));
-assertEquals(1, counter);
+TestStringify('{"getter":123}', getter_obj);
+assertEquals(2, counter);
 
 // Test toJSON function.
 var tojson_obj = { toJSON: function() {
@@ -77,8 +83,8 @@ var tojson_obj = { toJSON: function() {
                              return [1, 2];
                            },
                    a: 1};
-assertEquals('[1,2]', JSON.stringify(tojson_obj));
-assertEquals(2, counter);
+TestStringify('[1,2]', tojson_obj);
+assertEquals(4, counter);
 
 // Test that we don't recursively look for the toJSON function.
 var tojson_proto_obj = { a: 'fail' };
@@ -86,7 +92,7 @@ tojson_proto_obj.__proto__ = { toJSON: function() {
                                          counter++;
                                          return tojson_obj;
                                        } };
-assertEquals('{"a":1}', JSON.stringify(tojson_proto_obj));
+TestStringify('{"a":1}', tojson_proto_obj);
 
 // Test toJSON produced by a getter.
 var tojson_via_getter = { get toJSON() {
@@ -96,43 +102,44 @@ var tojson_via_getter = { get toJSON() {
                                        };
                               },
                           a: 1 };
-assertEquals('321', JSON.stringify(tojson_via_getter));
+TestStringify('321', tojson_via_getter);
 
 // Test toJSON with key.
 tojson_obj = { toJSON: function(key) { return key + key; } };
 var tojson_with_key_1 = { a: tojson_obj, b: tojson_obj };
-assertEquals('{"a":"aa","b":"bb"}', JSON.stringify(tojson_with_key_1));
+TestStringify('{"a":"aa","b":"bb"}', tojson_with_key_1);
 var tojson_with_key_2 = [ tojson_obj, tojson_obj ];
-assertEquals('["00","11"]', JSON.stringify(tojson_with_key_2));
+TestStringify('["00","11"]', tojson_with_key_2);
 
 // Test toJSON with exception.
 var tojson_ex = { toJSON: function(key) { throw "123" } };
 assertThrows(function() { JSON.stringify(tojson_ex); });
+assertThrows(function() { JSON.stringify(tojson_ex, null, 0); });
 
 // Test toJSON with access to this.
 var obj = { toJSON: function(key) { return this.a + key; }, a: "x" };
-assertEquals('{"y":"xy"}', JSON.stringify({y: obj}));
+TestStringify('{"y":"xy"}', {y: obj});
 
 // Test holes in arrays.
 var fast_smi = [1, 2, 3, 4];
 fast_smi.__proto__ = [7, 7, 7, 7];
 delete fast_smi[2];
 assertTrue(%HasFastSmiElements(fast_smi));
-assertEquals("[1,2,7,4]", JSON.stringify(fast_smi));
+TestStringify("[1,2,7,4]", fast_smi);
 
 var fast_double = [1.1, 2, 3, 4];
 fast_double.__proto__ = [7, 7, 7, 7];
 
 delete fast_double[2];
 assertTrue(%HasFastDoubleElements(fast_double));
-assertEquals("[1.1,2,7,4]", JSON.stringify(fast_double));
+TestStringify("[1.1,2,7,4]", fast_double);
 
 var fast_obj = [1, 2, {}, {}];
 fast_obj.__proto__ = [7, 7, 7, 7];
 
 delete fast_obj[2];
 assertTrue(%HasFastObjectElements(fast_obj));
-assertEquals("[1,2,7,{}]", JSON.stringify(fast_obj));
+TestStringify("[1,2,7,{}]", fast_obj);
 
 var getter_side_effect = { a: 1,
                            get b() {
@@ -146,8 +153,22 @@ var getter_side_effect = { a: 1,
 assertEquals('{"a":1,"b":2,"d":4}', JSON.stringify(getter_side_effect));
 assertEquals('{"b":2,"d":4,"e":5}', JSON.stringify(getter_side_effect));
 
+getter_side_effect = { a: 1,
+    get b() {
+      delete this.a;
+      delete this.c;
+      this.e = 5;
+      return 2;
+    },
+    c: 3,
+    d: 4 };
+assertEquals('{"a":1,"b":2,"d":4}',
+             JSON.stringify(getter_side_effect, null, 0));
+assertEquals('{"b":2,"d":4,"e":5}',
+             JSON.stringify(getter_side_effect, null, 0));
+
 var non_enum = {};
 non_enum.a = 1;
 Object.defineProperty(non_enum, "b", { value: 2, enumerable: false });
 non_enum.c = 3;
-assertEquals('{"a":1,"c":3}', JSON.stringify(non_enum));
+TestStringify('{"a":1,"c":3}', non_enum);
index b12e5f2..b333720 100644 (file)
@@ -31,3 +31,4 @@ var obj = JSON.parse(msg);
 var obj2 = JSON.parse(msg);
 
 assertEquals(JSON.stringify(obj), JSON.stringify(obj2));
+assertEquals(JSON.stringify(obj, null, 0), JSON.stringify(obj2));
\ No newline at end of file
index f9060e8..4e32a21 100644 (file)
@@ -29,3 +29,4 @@ var o = ["\u56e7",   // Switch JSON stringifier to two-byte mode.
          "\u00e6"];  // Latin-1 character.
 
 assertEquals('["\u56e7","\u00e6"]', JSON.stringify(o));
+assertEquals('["\u56e7","\u00e6"]', JSON.stringify(o, null, 0));
\ No newline at end of file
index 6a6d87b..4621de6 100644 (file)
@@ -32,5 +32,5 @@
 // See: http://code.google.com/p/v8/issues/detail?id=753
 
 var obj = {a1: {b1: [1,2,3,4], b2: {c1: 1, c2: 2}},a2: 'a2'};
-assertEquals(JSON.stringify(obj,null, 5.99999), JSON.stringify(obj,null, 5));
+assertEquals(JSON.stringify(obj, null, 5.99999), JSON.stringify(obj, null, 5));
 
index a988ebd..e7f3136 100644 (file)
@@ -29,6 +29,7 @@ assertEquals(String.fromCharCode(97, 220, 256), 'a' + '\u00DC' + '\u0100');
 assertEquals(String.fromCharCode(97, 220, 256), 'a\u00DC\u0100');
 
 assertEquals(0x80, JSON.stringify("\x80").charCodeAt(1));
+assertEquals(0x80, JSON.stringify("\x80", 0, null).charCodeAt(1));
 
 assertEquals(['a', 'b', '\xdc'], ['b', '\xdc', 'a'].sort());