Home | History | Annotate | Download | only in js
      1 // Copyright 2013 the V8 project authors. All rights reserved.
      2 // Copyright (C) 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
      3 //
      4 // Redistribution and use in source and binary forms, with or without
      5 // modification, are permitted provided that the following conditions
      6 // are met:
      7 // 1.  Redistributions of source code must retain the above copyright
      8 //     notice, this list of conditions and the following disclaimer.
      9 // 2.  Redistributions in binary form must reproduce the above copyright
     10 //     notice, this list of conditions and the following disclaimer in the
     11 //     documentation and/or other materials provided with the distribution.
     12 //
     13 // THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY
     14 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
     15 // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
     16 // DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY
     17 // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
     18 // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
     19 // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
     20 // ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     21 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
     22 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     23 
     24 description("Test behaviour of JSON reviver function.")
     25 if (!Array.isArray)
     26     Array.isArray = function(o) { return o.constructor === Array; }
     27 
     28 function arrayReviver(i,v) {
     29     if (i != "") {
     30         currentHolder = this;
     31         debug("");
     32         debug("Ensure the holder for our array is indeed an array");
     33         shouldBeTrue("Array.isArray(currentHolder)");
     34         shouldBe("currentHolder.length", "" + expectedLength);
     35         if (i > 0) {
     36             debug("");
     37             debug("Ensure that we always get the same holder");
     38             shouldBe("currentHolder", "lastHolder");
     39         }
     40         switch (Number(i)) {
     41         case 0:
     42             v = undefined;
     43             debug("");
     44             debug("Ensure that the holder already has all the properties present at the start of filtering");
     45             shouldBe("currentHolder[0]", '"a value"');
     46             shouldBe("currentHolder[1]", '"another value"');
     47             shouldBe("currentHolder[2]", '"and another value"');
     48             shouldBe("currentHolder[3]", '"to delete"');
     49             shouldBe("currentHolder[4]", '"extra value"');
     50             break;
     51 
     52         case 1:
     53             debug("");
     54             debug("Ensure that returning undefined has removed the property 0 from the holder during filtering.");
     55             shouldBeFalse("currentHolder.hasOwnProperty(0)");
     56             currentHolder[2] = "a replaced value";
     57             break;
     58 
     59         case 2:
     60             debug("");
     61             debug("Ensure that changing the value of a property is reflected while filtering.")
     62             shouldBe("currentHolder[2]", '"a replaced value"');
     63             value = v;
     64             debug("");
     65             debug("Ensure that the changed value is reflected in the arguments passed to the reviver");
     66             shouldBe("value", "currentHolder[2]");
     67             delete this[3];
     68             break;
     69 
     70         case 3:
     71             debug("");
     72             debug("Ensure that we visited a value that we have deleted, and that deletion is reflected while filtering.");
     73             shouldBeFalse("currentHolder.hasOwnProperty(3)");
     74             value = v;
     75             debug("");
     76             debug("Ensure that when visiting a deleted property value is undefined");
     77             shouldBeUndefined("value");
     78             v = "undelete the property";
     79             expectedLength = this.length = 3;
     80             break;
     81 
     82         case 4:
     83             if (this.length != 3) {
     84                 testFailed("Did not call reviver for deleted property");
     85                 expectedLength = this.length = 3;
     86                 break;
     87             }
     88 
     89         case 5:
     90             testPassed("Ensured that property was visited despite Array length being reduced.");
     91             value = v;
     92             shouldBeUndefined("value");
     93             this[10] = "fail";
     94             break;
     95 
     96         default:
     97             testFailed("Visited unexpected property " + i + " with value " + v);
     98         }
     99     }
    100     lastHolder = this;
    101     return v;
    102 }
    103 expectedLength = 5;
    104 var result = JSON.parse('["a value", "another value", "and another value", "to delete", "extra value"]', arrayReviver);
    105 debug("");
    106 debug("Ensure that we created the root holder as specified in ES5");
    107 shouldBeTrue("'' in lastHolder");
    108 shouldBe("result", "lastHolder['']");
    109 debug("");
    110 debug("Ensure that a deleted value is revived if the reviver function returns a value");
    111 shouldBeTrue("result.hasOwnProperty(3)");
    112 
    113 function objectReviver(i,v) {
    114     if (i != "") {
    115         currentHolder = this;
    116         shouldBeTrue("currentHolder != globalObject");
    117         if (seen) {
    118             debug("");
    119             debug("Ensure that we get the same holder object for each property");
    120             shouldBe("currentHolder", "lastHolder");
    121         }
    122         seen = true;
    123         switch (i) {
    124         case "a property":
    125             v = undefined;
    126             debug("");
    127             debug("Ensure that the holder already has all the properties present at the start of filtering");
    128             shouldBe("currentHolder['a property']", '"a value"');
    129             shouldBe("currentHolder['another property']", '"another value"');
    130             shouldBe("currentHolder['and another property']", '"and another value"');
    131             shouldBe("currentHolder['to delete']", '"will be deleted"');
    132             break;
    133 
    134         case "another property":
    135             debug("");
    136             debug("Ensure that returning undefined has correctly removed the property 'a property' from the holder object");
    137             shouldBeFalse("currentHolder.hasOwnProperty('a property')");
    138             currentHolder['and another property'] = "a replaced value";
    139             break;
    140 
    141         case "and another property":
    142             debug("Ensure that changing the value of a property is reflected while filtering.");
    143             shouldBe("currentHolder['and another property']", '"a replaced value"');
    144             value = v;
    145             debug("");
    146             debug("Ensure that the changed value is reflected in the arguments passed to the reviver");
    147             shouldBe("value", '"a replaced value"');
    148             delete this["to delete"];
    149             break;
    150 
    151         case "to delete":
    152             debug("");
    153             debug("Ensure that we visited a value that we have deleted, and that deletion is reflected while filtering.");
    154             shouldBeFalse("currentHolder.hasOwnProperty('to delete')");
    155             value = v;
    156             debug("");
    157             debug("Ensure that when visiting a deleted property value is undefined");
    158             shouldBeUndefined("value");
    159             v = "undelete the property";
    160             this["new property"] = "fail";
    161             break;
    162         default:
    163             testFailed("Visited unexpected property " + i + " with value " + v);
    164         }
    165     }
    166     lastHolder = this;
    167     return v;
    168 }
    169 
    170 debug("");
    171 debug("Test behaviour of revivor used in conjunction with an object");
    172 var seen = false;
    173 var globalObject = this;
    174 var result = JSON.parse('{"a property" : "a value", "another property" : "another value", "and another property" : "and another value", "to delete" : "will be deleted"}', objectReviver);
    175 debug("");
    176 debug("Ensure that we created the root holder as specified in ES5");
    177 shouldBeTrue("lastHolder.hasOwnProperty('')");
    178 shouldBeFalse("result.hasOwnProperty('a property')");
    179 shouldBeTrue("result.hasOwnProperty('to delete')");
    180 shouldBe("result", "lastHolder['']");
    181 
    182 debug("");
    183 debug("Test behaviour of revivor that introduces a cycle");
    184 function reviveAddsCycle(i, v) {
    185     if (i == 0)
    186         this[1] = this;
    187     return v;
    188 }
    189 
    190 shouldThrow('JSON.parse("[0,1]", reviveAddsCycle)');
    191 
    192 debug("");
    193 debug("Test behaviour of revivor that introduces a new array classed object (the result of a regex)");
    194 var createdBadness = false;
    195 function reviveIntroducesNewArrayLikeObject(i, v) {
    196     if (i == 0 && !createdBadness) {
    197         this[1] = /(a)+/.exec("a");
    198         createdBadness = true;
    199     }
    200     return v;
    201 }
    202 
    203 shouldBe('JSON.stringify(JSON.parse("[0,1]", reviveIntroducesNewArrayLikeObject))', '\'[0,["a","a"]]\'');
    204