| // 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"); | |
| this.length = 3; | |
| v = "undelete the property"; | |
| expectedLength = 4; | |
| break; | |
| case 4: | |
| if (this.length != 4) { | |
| 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"]]\''); |