• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
24description("Test behaviour of JSON reviver function.")
25if (!Array.isArray)
26    Array.isArray = function(o) { return o.constructor === Array; }
27
28function 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            this.length = 3;
79            v = "undelete the property";
80            expectedLength = 4;
81            break;
82
83        case 4:
84            if (this.length != 4) {
85                testFailed("Did not call reviver for deleted property");
86                expectedLength = this.length = 3;
87                break;
88            }
89
90        case 5:
91            testPassed("Ensured that property was visited despite Array length being reduced.");
92            value = v;
93            shouldBeUndefined("value");
94            this[10] = "fail";
95            break;
96
97        default:
98            testFailed("Visited unexpected property " + i + " with value " + v);
99        }
100    }
101    lastHolder = this;
102    return v;
103}
104expectedLength = 5;
105var result = JSON.parse('["a value", "another value", "and another value", "to delete", "extra value"]', arrayReviver);
106debug("");
107debug("Ensure that we created the root holder as specified in ES5");
108shouldBeTrue("'' in lastHolder");
109shouldBe("result", "lastHolder['']");
110debug("");
111debug("Ensure that a deleted value is revived if the reviver function returns a value");
112shouldBeTrue("result.hasOwnProperty(3)");
113
114function objectReviver(i,v) {
115    if (i != "") {
116        currentHolder = this;
117        shouldBeTrue("currentHolder != globalObject");
118        if (seen) {
119            debug("");
120            debug("Ensure that we get the same holder object for each property");
121            shouldBe("currentHolder", "lastHolder");
122        }
123        seen = true;
124        switch (i) {
125        case "a property":
126            v = undefined;
127            debug("");
128            debug("Ensure that the holder already has all the properties present at the start of filtering");
129            shouldBe("currentHolder['a property']", '"a value"');
130            shouldBe("currentHolder['another property']", '"another value"');
131            shouldBe("currentHolder['and another property']", '"and another value"');
132            shouldBe("currentHolder['to delete']", '"will be deleted"');
133            break;
134
135        case "another property":
136            debug("");
137            debug("Ensure that returning undefined has correctly removed the property 'a property' from the holder object");
138            shouldBeFalse("currentHolder.hasOwnProperty('a property')");
139            currentHolder['and another property'] = "a replaced value";
140            break;
141
142        case "and another property":
143            debug("Ensure that changing the value of a property is reflected while filtering.");
144            shouldBe("currentHolder['and another property']", '"a replaced value"');
145            value = v;
146            debug("");
147            debug("Ensure that the changed value is reflected in the arguments passed to the reviver");
148            shouldBe("value", '"a replaced value"');
149            delete this["to delete"];
150            break;
151
152        case "to delete":
153            debug("");
154            debug("Ensure that we visited a value that we have deleted, and that deletion is reflected while filtering.");
155            shouldBeFalse("currentHolder.hasOwnProperty('to delete')");
156            value = v;
157            debug("");
158            debug("Ensure that when visiting a deleted property value is undefined");
159            shouldBeUndefined("value");
160            v = "undelete the property";
161            this["new property"] = "fail";
162            break;
163        default:
164            testFailed("Visited unexpected property " + i + " with value " + v);
165        }
166    }
167    lastHolder = this;
168    return v;
169}
170
171debug("");
172debug("Test behaviour of revivor used in conjunction with an object");
173var seen = false;
174var globalObject = this;
175var result = JSON.parse('{"a property" : "a value", "another property" : "another value", "and another property" : "and another value", "to delete" : "will be deleted"}', objectReviver);
176debug("");
177debug("Ensure that we created the root holder as specified in ES5");
178shouldBeTrue("lastHolder.hasOwnProperty('')");
179shouldBeFalse("result.hasOwnProperty('a property')");
180shouldBeTrue("result.hasOwnProperty('to delete')");
181shouldBe("result", "lastHolder['']");
182
183debug("");
184debug("Test behaviour of revivor that introduces a cycle");
185function reviveAddsCycle(i, v) {
186    if (i == 0)
187        this[1] = this;
188    return v;
189}
190
191shouldThrow('JSON.parse("[0,1]", reviveAddsCycle)');
192
193debug("");
194debug("Test behaviour of revivor that introduces a new array classed object (the result of a regex)");
195var createdBadness = false;
196function reviveIntroducesNewArrayLikeObject(i, v) {
197    if (i == 0 && !createdBadness) {
198        this[1] = /(a)+/.exec("a");
199        createdBadness = true;
200    }
201    return v;
202}
203
204shouldBe('JSON.stringify(JSON.parse("[0,1]", reviveIntroducesNewArrayLikeObject))', '\'[0,["a","a"]]\'');
205