|
1 /* |
|
2 * Check the order of splice's internal operations, because the ordering is |
|
3 * visible externally. |
|
4 */ |
|
5 |
|
6 function handlerMaker(obj, expected_exceptions) { |
|
7 var order = []; |
|
8 function note(trap, name) |
|
9 { |
|
10 order.push(trap + '-' + name); |
|
11 if (expected_exceptions[trap] === name) { |
|
12 throw ("fail"); |
|
13 } |
|
14 } |
|
15 |
|
16 return [{ |
|
17 /* this is the only trap we care about */ |
|
18 delete: function(name) { |
|
19 note("del", name); |
|
20 return delete obj[name]; |
|
21 }, |
|
22 |
|
23 // Fundamental traps |
|
24 getOwnPropertyDescriptor: function(name) { |
|
25 var desc = Object.getOwnPropertyDescriptor(obj, name); |
|
26 // a trapping proxy's properties must always be configurable |
|
27 if (desc !== undefined) |
|
28 desc.configurable = true; |
|
29 return desc; |
|
30 }, |
|
31 getPropertyDescriptor: function(name) { |
|
32 var desc = Object.getPropertyDescriptor(obj, name); // not in ES5 |
|
33 // a trapping proxy's properties must always be configurable |
|
34 if (desc !== undefined) |
|
35 desc.configurable = true; |
|
36 return desc; |
|
37 }, |
|
38 getOwnPropertyNames: function() { |
|
39 return Object.getOwnPropertyNames(obj); |
|
40 }, |
|
41 getPropertyNames: function() { |
|
42 return Object.getPropertyNames(obj); // not in ES5 |
|
43 }, |
|
44 defineProperty: function(name, desc) { |
|
45 note("def", name); |
|
46 Object.defineProperty(obj, name, desc); |
|
47 }, |
|
48 fix: function() { |
|
49 if (Object.isFrozen(obj)) { |
|
50 return Object.getOwnPropertyNames(obj).map(function(name) { |
|
51 return Object.getOwnPropertyDescriptor(obj, name); |
|
52 }); |
|
53 } |
|
54 // As long as obj is not frozen, the proxy won't allow itself to be fixed |
|
55 return undefined; // will cause a TypeError to be thrown |
|
56 }, |
|
57 |
|
58 // derived traps |
|
59 has: function(name) { |
|
60 note("has", name); |
|
61 return name in obj; |
|
62 }, |
|
63 hasOwn: function(name) { return Object.prototype.hasOwnProperty.call(obj, name); }, |
|
64 get: function(receiver, name) { |
|
65 note("get", name); |
|
66 return obj[name]; |
|
67 }, |
|
68 set: function(receiver, name, val) { |
|
69 note("set", name); |
|
70 obj[name] = val; |
|
71 return true; // bad behavior when set fails in non-strict mode |
|
72 }, |
|
73 enumerate: function() { |
|
74 var result = []; |
|
75 for (name in obj) |
|
76 result.push(name); |
|
77 return result; |
|
78 }, |
|
79 keys: function() { return Object.keys(obj) } |
|
80 }, order]; |
|
81 } |
|
82 |
|
83 // arr: the array to splice |
|
84 // expected_order: the expected order of operations on arr, stringified |
|
85 function check_splice_proxy(arr, expected_order, expected_exceptions, expected_array, expected_result) { |
|
86 print (arr); |
|
87 var [handler, store] = handlerMaker(arr, expected_exceptions); |
|
88 var proxy = Proxy.create(handler); |
|
89 |
|
90 try { |
|
91 var args = Array.prototype.slice.call(arguments, 5); |
|
92 var result = Array.prototype.splice.apply(proxy, args); |
|
93 assertEq(Object.keys(expected_exceptions).length, 0); |
|
94 } catch (e) { |
|
95 assertEq(Object.keys(expected_exceptions).length > 0, true); |
|
96 } |
|
97 |
|
98 // check the order of the property accesses, etc |
|
99 assertEq(store.toString(), expected_order); |
|
100 |
|
101 // The deleted elements are returned in an object that's always an Array. |
|
102 assertEq(Array.isArray(result) || result === undefined, true); |
|
103 |
|
104 // check the return value |
|
105 for (var i in expected_result) { |
|
106 assertEq(result[i], expected_result[i]); |
|
107 } |
|
108 for (var i in result) { |
|
109 assertEq(result[i], expected_result[i]); |
|
110 } |
|
111 |
|
112 // check the value of arr |
|
113 for (var i in expected_array) { |
|
114 assertEq(arr[i], expected_array[i]); |
|
115 } |
|
116 for (var i in arr) { |
|
117 assertEq(arr[i], expected_array[i]); |
|
118 } |
|
119 |
|
120 return result; |
|
121 } |
|
122 |
|
123 // Shrinking array |
|
124 check_splice_proxy( |
|
125 [10,1,2,3,4,5], |
|
126 "get-length," + |
|
127 "has-0,get-0,has-1,get-1,has-2,get-2," + |
|
128 "has-3,get-3,set-0,has-4,get-4,set-1,has-5,get-5,set-2," + |
|
129 "del-5,del-4,del-3," + |
|
130 "set-length", |
|
131 {}, |
|
132 [3,4,5], |
|
133 [10,1,2], |
|
134 0, 3 |
|
135 ); |
|
136 |
|
137 // Growing array |
|
138 check_splice_proxy( |
|
139 [11,1,2,3,4,5], |
|
140 "get-length," + |
|
141 "has-0,get-0,has-1,get-1,has-2,get-2," + |
|
142 "has-5,get-5,set-9,has-4,get-4,set-8,has-3,get-3,set-7," + |
|
143 "set-0,set-1,set-2,set-3,set-4,set-5,set-6," + |
|
144 "set-length", |
|
145 {}, |
|
146 [9,9,9,9,9,9,9,3,4,5], |
|
147 [11,1,2], |
|
148 0, 3, 9, 9, 9, 9, 9, 9, 9 |
|
149 ); |
|
150 |
|
151 // Same sized array |
|
152 check_splice_proxy( |
|
153 [12,1,2,3,4,5], |
|
154 "get-length," + |
|
155 "has-0,get-0,has-1,get-1,has-2,get-2," + |
|
156 "set-0,set-1,set-2," + |
|
157 "set-length", |
|
158 {}, |
|
159 [9,9,9,3,4,5], |
|
160 [12,1,2], |
|
161 0, 3, 9, 9, 9 |
|
162 ); |
|
163 |
|
164 |
|
165 /* |
|
166 * Check that if we fail at a particular step in the algorithm, we don't |
|
167 * continue with the algorithm beyond that step. |
|
168 */ |
|
169 |
|
170 |
|
171 // Step 3: fail when getting length |
|
172 check_splice_proxy( |
|
173 [13,1,2,3,4,5], |
|
174 "get-length", |
|
175 {get: 'length'}, |
|
176 [13,1,2,3,4,5], |
|
177 undefined, |
|
178 0, 3, 9, 9, 9 |
|
179 ); |
|
180 |
|
181 // Step 9b: fail when [[HasProperty]] |
|
182 check_splice_proxy( |
|
183 [14,1,2,3,4,5], |
|
184 "get-length," + |
|
185 "has-0,get-0,has-1", |
|
186 {has: '1'}, |
|
187 [14,1,2,3,4,5], |
|
188 undefined, |
|
189 0, 3, 9, 9, 9 |
|
190 ); |
|
191 |
|
192 // Step 9c(i): fail when [[Get]] |
|
193 check_splice_proxy( |
|
194 [15,1,2,3,4,5], |
|
195 "get-length," + |
|
196 "has-0,get-0,has-1,get-1", |
|
197 {get: '1'}, |
|
198 [15,1,2,3,4,5], |
|
199 undefined, |
|
200 0, 3, 9, 9, 9 |
|
201 ); |
|
202 |
|
203 // Step 12b(iii): fail when [[HasProperty]] |
|
204 check_splice_proxy( |
|
205 [16,1,2,3,4,5], |
|
206 "get-length," + |
|
207 "has-0,get-0,has-1,get-1,has-2,get-2," + |
|
208 "has-3,get-3,set-0,has-4", |
|
209 {has: '4'}, |
|
210 [3,1,2,3,4,5], |
|
211 undefined, |
|
212 0, 3 |
|
213 ); |
|
214 |
|
215 |
|
216 // Step 12b(iv)1: fail when [[Get]] |
|
217 check_splice_proxy( |
|
218 [17,1,2,3,4,5], |
|
219 "get-length," + |
|
220 "has-0,get-0,has-1,get-1,has-2,get-2," + |
|
221 "has-3,get-3,set-0,has-4,get-4", |
|
222 {get: '4'}, |
|
223 [3,1,2,3,4,5], |
|
224 undefined, |
|
225 0, 3 |
|
226 ); |
|
227 |
|
228 |
|
229 // Step 12b(iv)2: fail when [[Put]] |
|
230 check_splice_proxy( |
|
231 [18,1,2,3,4,5], |
|
232 "get-length," + |
|
233 "has-0,get-0,has-1,get-1,has-2,get-2," + |
|
234 "has-3,get-3,set-0,has-4,get-4,set-1", |
|
235 {set: '1'}, |
|
236 [3,1,2,3,4,5], |
|
237 undefined, |
|
238 0, 3 |
|
239 ); |
|
240 |
|
241 // Step 12b(v)1: fail when [[Delete]] |
|
242 check_splice_proxy( |
|
243 [19,1,2,3,,5], |
|
244 "get-length," + |
|
245 "has-0,get-0,has-1,get-1,has-2,get-2," + |
|
246 "has-3,get-3,set-0,has-4,del-1", |
|
247 {del: '1'}, |
|
248 [3,1,2,3,,5], |
|
249 undefined, |
|
250 0, 3 |
|
251 ); |
|
252 |
|
253 // Step 12d(i): fail when [[Delete]] |
|
254 check_splice_proxy( |
|
255 [20,1,2,3,4,5], |
|
256 "get-length," + |
|
257 "has-0,get-0,has-1,get-1,has-2,get-2," + |
|
258 "has-3,get-3,set-0,has-4,get-4,set-1,has-5,get-5,set-2," + |
|
259 "del-5,del-4", |
|
260 {del: '4'}, |
|
261 [3,4,5,3,4], |
|
262 undefined, |
|
263 0, 3 |
|
264 ); |
|
265 |
|
266 // Step 13b(iii): fail when [[HasProperty]] |
|
267 check_splice_proxy( |
|
268 [21,1,2,3,4,5], |
|
269 "get-length," + |
|
270 "has-0,get-0,has-1,get-1,has-2,get-2," + |
|
271 "has-5,get-5,set-8,has-4", |
|
272 {has: '4'}, |
|
273 [21,1,2,3,4,5,,,5], |
|
274 undefined, |
|
275 0, 3, 9,9,9,9,9,9 |
|
276 ); |
|
277 |
|
278 |
|
279 // Step 13b(iv)1: fail when [[Get]] |
|
280 check_splice_proxy( |
|
281 [22,1,2,3,4,5], |
|
282 "get-length," + |
|
283 "has-0,get-0,has-1,get-1,has-2,get-2," + |
|
284 "has-5,get-5,set-8,has-4,get-4", |
|
285 {get: '4'}, |
|
286 [22,1,2,3,4,5,,,5], |
|
287 undefined, |
|
288 0, 3, 9,9,9,9,9,9 |
|
289 ); |
|
290 |
|
291 |
|
292 // Step 13b(iv)2: fail when [[Put]] |
|
293 check_splice_proxy( |
|
294 [23,1,2,3,4,5], |
|
295 "get-length," + |
|
296 "has-0,get-0,has-1,get-1,has-2,get-2," + |
|
297 "has-5,get-5,set-8,has-4,get-4,set-7", |
|
298 {set: '7'}, |
|
299 [23,1,2,3,4,5,,,5], |
|
300 undefined, |
|
301 0, 3, 9,9,9,9,9,9 |
|
302 ); |
|
303 |
|
304 // Step 13b(v)1: fail when [[Delete]] |
|
305 check_splice_proxy( |
|
306 [24,1,2,3,,5], |
|
307 "get-length," + |
|
308 "has-0,get-0,has-1,get-1,has-2,get-2," + |
|
309 "has-5,get-5,set-8,has-4,del-7", |
|
310 {del: '7'}, |
|
311 [24,1,2,3,,5,,,5], |
|
312 undefined, |
|
313 0, 3, 9,9,9,9,9,9 |
|
314 ); |
|
315 |
|
316 // Step 15b: fail when [[Put]] |
|
317 check_splice_proxy( |
|
318 [25,1,2,3,4,5], |
|
319 "get-length," + |
|
320 "has-0,get-0,has-1,get-1,has-2,get-2," + |
|
321 "has-5,get-5,set-8,has-4,get-4,set-7,has-3,get-3,set-6," + |
|
322 "set-0,set-1,set-2", |
|
323 {set: '2'}, |
|
324 [9,9,2,3,4,5,3,4,5], |
|
325 undefined, |
|
326 0, 3, 9,9,9,9,9,9 |
|
327 ); |