Index: test/webkit/fast/js/JSON-parse-reviver.js |
diff --git a/test/webkit/fast/js/JSON-parse-reviver.js b/test/webkit/fast/js/JSON-parse-reviver.js |
new file mode 100644 |
index 0000000000000000000000000000000000000000..b02a2fc468595b05ce04c242ebcd952bc8e1bf44 |
--- /dev/null |
+++ b/test/webkit/fast/js/JSON-parse-reviver.js |
@@ -0,0 +1,205 @@ |
+// Copyright 2013 the V8 project authors. All rights reserved. |
+// Copyright (C) 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved. |
+// |
+// Redistribution and use in source and binary forms, with or without |
+// modification, are permitted provided that the following conditions |
+// are met: |
+// 1. Redistributions of source code must retain the above copyright |
+// notice, this list of conditions and the following disclaimer. |
+// 2. Redistributions in binary form must reproduce the above copyright |
+// notice, this list of conditions and the following disclaimer in the |
+// documentation and/or other materials provided with the distribution. |
+// |
+// THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY |
+// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
+// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
+// DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY |
+// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
+// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
+// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON |
+// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
+// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
+ |
+description("Test behaviour of JSON reviver function.") |
+if (!Array.isArray) |
+ Array.isArray = function(o) { return o.constructor === Array; } |
+ |
+function arrayReviver(i,v) { |
+ if (i != "") { |
+ currentHolder = this; |
+ debug(""); |
+ debug("Ensure the holder for our array is indeed an array"); |
+ shouldBeTrue("Array.isArray(currentHolder)"); |
+ shouldBe("currentHolder.length", "" + expectedLength); |
+ if (i > 0) { |
+ debug(""); |
+ debug("Ensure that we always get the same holder"); |
+ shouldBe("currentHolder", "lastHolder"); |
+ } |
+ switch (Number(i)) { |
+ case 0: |
+ v = undefined; |
+ debug(""); |
+ debug("Ensure that the holder already has all the properties present at the start of filtering"); |
+ shouldBe("currentHolder[0]", '"a value"'); |
+ shouldBe("currentHolder[1]", '"another value"'); |
+ shouldBe("currentHolder[2]", '"and another value"'); |
+ shouldBe("currentHolder[3]", '"to delete"'); |
+ shouldBe("currentHolder[4]", '"extra value"'); |
+ break; |
+ |
+ case 1: |
+ debug(""); |
+ debug("Ensure that returning undefined has removed the property 0 from the holder during filtering."); |
+ shouldBeFalse("currentHolder.hasOwnProperty(0)"); |
+ currentHolder[2] = "a replaced value"; |
+ break; |
+ |
+ case 2: |
+ debug(""); |
+ debug("Ensure that changing the value of a property is reflected while filtering.") |
+ shouldBe("currentHolder[2]", '"a replaced value"'); |
+ value = v; |
+ debug(""); |
+ debug("Ensure that the changed value is reflected in the arguments passed to the reviver"); |
+ shouldBe("value", "currentHolder[2]"); |
+ delete this[3]; |
+ break; |
+ |
+ case 3: |
+ debug(""); |
+ debug("Ensure that we visited a value that we have deleted, and that deletion is reflected while filtering."); |
+ shouldBeFalse("currentHolder.hasOwnProperty(3)"); |
+ value = v; |
+ debug(""); |
+ debug("Ensure that when visiting a deleted property value is undefined"); |
+ shouldBeUndefined("value"); |
+ v = "undelete the property"; |
+ expectedLength = this.length = 3; |
+ break; |
+ |
+ case 4: |
+ if (this.length != 3) { |
+ testFailed("Did not call reviver for deleted property"); |
+ expectedLength = this.length = 3; |
+ break; |
+ } |
+ |
+ case 5: |
+ testPassed("Ensured that property was visited despite Array length being reduced."); |
+ value = v; |
+ shouldBeUndefined("value"); |
+ this[10] = "fail"; |
+ break; |
+ |
+ default: |
+ testFailed("Visited unexpected property " + i + " with value " + v); |
+ } |
+ } |
+ lastHolder = this; |
+ return v; |
+} |
+expectedLength = 5; |
+var result = JSON.parse('["a value", "another value", "and another value", "to delete", "extra value"]', arrayReviver); |
+debug(""); |
+debug("Ensure that we created the root holder as specified in ES5"); |
+shouldBeTrue("'' in lastHolder"); |
+shouldBe("result", "lastHolder['']"); |
+debug(""); |
+debug("Ensure that a deleted value is revived if the reviver function returns a value"); |
+shouldBeTrue("result.hasOwnProperty(3)"); |
+ |
+function objectReviver(i,v) { |
+ if (i != "") { |
+ currentHolder = this; |
+ shouldBeTrue("currentHolder != globalObject"); |
+ if (seen) { |
+ debug(""); |
+ debug("Ensure that we get the same holder object for each property"); |
+ shouldBe("currentHolder", "lastHolder"); |
+ } |
+ seen = true; |
+ switch (i) { |
+ case "a property": |
+ v = undefined; |
+ debug(""); |
+ debug("Ensure that the holder already has all the properties present at the start of filtering"); |
+ shouldBe("currentHolder['a property']", '"a value"'); |
+ shouldBe("currentHolder['another property']", '"another value"'); |
+ shouldBe("currentHolder['and another property']", '"and another value"'); |
+ shouldBe("currentHolder['to delete']", '"will be deleted"'); |
+ break; |
+ |
+ case "another property": |
+ debug(""); |
+ debug("Ensure that returning undefined has correctly removed the property 'a property' from the holder object"); |
+ shouldBeFalse("currentHolder.hasOwnProperty('a property')"); |
+ currentHolder['and another property'] = "a replaced value"; |
+ break; |
+ |
+ case "and another property": |
+ debug("Ensure that changing the value of a property is reflected while filtering."); |
+ shouldBe("currentHolder['and another property']", '"a replaced value"'); |
+ value = v; |
+ debug(""); |
+ debug("Ensure that the changed value is reflected in the arguments passed to the reviver"); |
+ shouldBe("value", '"a replaced value"'); |
+ delete this["to delete"]; |
+ break; |
+ |
+ case "to delete": |
+ debug(""); |
+ debug("Ensure that we visited a value that we have deleted, and that deletion is reflected while filtering."); |
+ shouldBeFalse("currentHolder.hasOwnProperty('to delete')"); |
+ value = v; |
+ debug(""); |
+ debug("Ensure that when visiting a deleted property value is undefined"); |
+ shouldBeUndefined("value"); |
+ v = "undelete the property"; |
+ this["new property"] = "fail"; |
+ break; |
+ default: |
+ testFailed("Visited unexpected property " + i + " with value " + v); |
+ } |
+ } |
+ lastHolder = this; |
+ return v; |
+} |
+ |
+debug(""); |
+debug("Test behaviour of revivor used in conjunction with an object"); |
+var seen = false; |
+var globalObject = this; |
+var result = JSON.parse('{"a property" : "a value", "another property" : "another value", "and another property" : "and another value", "to delete" : "will be deleted"}', objectReviver); |
+debug(""); |
+debug("Ensure that we created the root holder as specified in ES5"); |
+shouldBeTrue("lastHolder.hasOwnProperty('')"); |
+shouldBeFalse("result.hasOwnProperty('a property')"); |
+shouldBeTrue("result.hasOwnProperty('to delete')"); |
+shouldBe("result", "lastHolder['']"); |
+ |
+debug(""); |
+debug("Test behaviour of revivor that introduces a cycle"); |
+function reviveAddsCycle(i, v) { |
+ if (i == 0) |
+ this[1] = this; |
+ return v; |
+} |
+ |
+shouldThrow('JSON.parse("[0,1]", reviveAddsCycle)'); |
+ |
+debug(""); |
+debug("Test behaviour of revivor that introduces a new array classed object (the result of a regex)"); |
+var createdBadness = false; |
+function reviveIntroducesNewArrayLikeObject(i, v) { |
+ if (i == 0 && !createdBadness) { |
+ this[1] = /(a)+/.exec("a"); |
+ createdBadness = true; |
+ } |
+ return v; |
+} |
+ |
+shouldBe('JSON.stringify(JSON.parse("[0,1]", reviveIntroducesNewArrayLikeObject))', '\'[0,["a","a"]]\''); |
+ |
+ |