blob: 1f04602ee9ce8ee39932c5b07b5c8256f6153fc0 [file] [log] [blame]
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001// 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 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}
103expectedLength = 5;
104var result = JSON.parse('["a value", "another value", "and another value", "to delete", "extra value"]', arrayReviver);
105debug("");
106debug("Ensure that we created the root holder as specified in ES5");
107shouldBeTrue("'' in lastHolder");
108shouldBe("result", "lastHolder['']");
109debug("");
110debug("Ensure that a deleted value is revived if the reviver function returns a value");
111shouldBeTrue("result.hasOwnProperty(3)");
112
113function 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
170debug("");
171debug("Test behaviour of revivor used in conjunction with an object");
172var seen = false;
173var globalObject = this;
174var result = JSON.parse('{"a property" : "a value", "another property" : "another value", "and another property" : "and another value", "to delete" : "will be deleted"}', objectReviver);
175debug("");
176debug("Ensure that we created the root holder as specified in ES5");
177shouldBeTrue("lastHolder.hasOwnProperty('')");
178shouldBeFalse("result.hasOwnProperty('a property')");
179shouldBeTrue("result.hasOwnProperty('to delete')");
180shouldBe("result", "lastHolder['']");
181
182debug("");
183debug("Test behaviour of revivor that introduces a cycle");
184function reviveAddsCycle(i, v) {
185 if (i == 0)
186 this[1] = this;
187 return v;
188}
189
190shouldThrow('JSON.parse("[0,1]", reviveAddsCycle)');
191
192debug("");
193debug("Test behaviour of revivor that introduces a new array classed object (the result of a regex)");
194var createdBadness = false;
195function reviveIntroducesNewArrayLikeObject(i, v) {
196 if (i == 0 && !createdBadness) {
197 this[1] = /(a)+/.exec("a");
198 createdBadness = true;
199 }
200 return v;
201}
202
203shouldBe('JSON.stringify(JSON.parse("[0,1]", reviveIntroducesNewArrayLikeObject))', '\'[0,["a","a"]]\'');