OLD | NEW |
| (Empty) |
1 // Copyright 2012-2015 the V8 project authors. All rights reserved. | |
2 // Redistribution and use in source and binary forms, with or without | |
3 // modification, are permitted provided that the following conditions are | |
4 // met: | |
5 // | |
6 // * Redistributions of source code must retain the above copyright | |
7 // notice, this list of conditions and the following disclaimer. | |
8 // * Redistributions in binary form must reproduce the above | |
9 // copyright notice, this list of conditions and the following | |
10 // disclaimer in the documentation and/or other materials provided | |
11 // with the distribution. | |
12 // * Neither the name of Google Inc. nor the names of its | |
13 // contributors may be used to endorse or promote products derived | |
14 // from this software without specific prior written permission. | |
15 // | |
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
27 | |
28 // Tests the Reflect.defineProperty method - ES6 26.1.3 | |
29 // This is adapted from mjsunit/object-define-property.js. | |
30 | |
31 // Flags: --allow-natives-syntax --harmony-reflect | |
32 | |
33 | |
34 // Check that an exception is thrown when null is passed as object. | |
35 var exception = false; | |
36 try { | |
37 Reflect.defineProperty(null, null, null); | |
38 } catch (e) { | |
39 exception = true; | |
40 assertTrue(/called on non-object/.test(e)); | |
41 } | |
42 assertTrue(exception); | |
43 | |
44 // Check that an exception is thrown when undefined is passed as object. | |
45 exception = false; | |
46 try { | |
47 Reflect.defineProperty(undefined, undefined, undefined); | |
48 } catch (e) { | |
49 exception = true; | |
50 assertTrue(/called on non-object/.test(e)); | |
51 } | |
52 assertTrue(exception); | |
53 | |
54 // Check that an exception is thrown when non-object is passed as object. | |
55 exception = false; | |
56 try { | |
57 Reflect.defineProperty(0, "foo", undefined); | |
58 } catch (e) { | |
59 exception = true; | |
60 assertTrue(/called on non-object/.test(e)); | |
61 } | |
62 assertTrue(exception); | |
63 | |
64 // Object. | |
65 var obj1 = {}; | |
66 | |
67 // Values. | |
68 var val1 = 0; | |
69 var val2 = 0; | |
70 var val3 = 0; | |
71 | |
72 function setter1() {val1++; } | |
73 function getter1() {return val1; } | |
74 | |
75 function setter2() {val2++; } | |
76 function getter2() {return val2; } | |
77 | |
78 function setter3() {val3++; } | |
79 function getter3() {return val3; } | |
80 | |
81 | |
82 // Descriptors. | |
83 var emptyDesc = {}; | |
84 | |
85 var accessorConfigurable = { | |
86 set: setter1, | |
87 get: getter1, | |
88 configurable: true | |
89 }; | |
90 | |
91 var accessorNoConfigurable = { | |
92 set: setter2, | |
93 get: getter2, | |
94 configurable: false | |
95 }; | |
96 | |
97 var accessorOnlySet = { | |
98 set: setter3, | |
99 configurable: true | |
100 }; | |
101 | |
102 var accessorOnlyGet = { | |
103 get: getter3, | |
104 configurable: true | |
105 }; | |
106 | |
107 var accessorDefault = {set: function(){} }; | |
108 | |
109 var dataConfigurable = { value: 1000, configurable: true }; | |
110 | |
111 var dataNoConfigurable = { value: 2000, configurable: false }; | |
112 | |
113 var dataWritable = { value: 3000, writable: true}; | |
114 | |
115 | |
116 // Check that we can't add property with undefined attributes. | |
117 assertThrows(function() { Reflect.defineProperty(obj1, "foo", undefined) }, | |
118 TypeError); | |
119 | |
120 // Make sure that we can add a property with an empty descriptor and | |
121 // that it has the default descriptor values. | |
122 assertTrue(Reflect.defineProperty(obj1, "foo", emptyDesc)); | |
123 | |
124 // foo should be undefined as it has no get, set or value | |
125 assertEquals(undefined, obj1.foo); | |
126 | |
127 // We should, however, be able to retrieve the propertydescriptor which should | |
128 // have all default values (according to 8.6.1). | |
129 var desc = Object.getOwnPropertyDescriptor(obj1, "foo"); | |
130 assertFalse(desc.configurable); | |
131 assertFalse(desc.enumerable); | |
132 assertFalse(desc.writable); | |
133 assertEquals(desc.get, undefined); | |
134 assertEquals(desc.set, undefined); | |
135 assertEquals(desc.value, undefined); | |
136 | |
137 // Make sure that getOwnPropertyDescriptor does not return a descriptor | |
138 // with default values if called with non existing property (otherwise | |
139 // the test above is invalid). | |
140 desc = Object.getOwnPropertyDescriptor(obj1, "bar"); | |
141 assertEquals(desc, undefined); | |
142 | |
143 // Make sure that foo can't be reset (as configurable is false). | |
144 assertFalse(Reflect.defineProperty(obj1, "foo", accessorConfigurable)); | |
145 | |
146 | |
147 // Accessor properties | |
148 | |
149 assertTrue(Reflect.defineProperty(obj1, "bar", accessorConfigurable)); | |
150 desc = Object.getOwnPropertyDescriptor(obj1, "bar"); | |
151 assertTrue(desc.configurable); | |
152 assertFalse(desc.enumerable); | |
153 assertEquals(desc.writable, undefined); | |
154 assertEquals(desc.get, accessorConfigurable.get); | |
155 assertEquals(desc.set, accessorConfigurable.set); | |
156 assertEquals(desc.value, undefined); | |
157 assertEquals(1, obj1.bar = 1); | |
158 assertEquals(1, val1); | |
159 assertEquals(1, obj1.bar = 1); | |
160 assertEquals(2, val1); | |
161 assertEquals(2, obj1.bar); | |
162 | |
163 // Redefine bar with non configurable test | |
164 assertTrue(Reflect.defineProperty(obj1, "bar", accessorNoConfigurable)); | |
165 desc = Object.getOwnPropertyDescriptor(obj1, "bar"); | |
166 assertFalse(desc.configurable); | |
167 assertFalse(desc.enumerable); | |
168 assertEquals(desc.writable, undefined); | |
169 assertEquals(desc.get, accessorNoConfigurable.get); | |
170 assertEquals(desc.set, accessorNoConfigurable.set); | |
171 assertEquals(desc.value, undefined); | |
172 assertEquals(1, obj1.bar = 1); | |
173 assertEquals(2, val1); | |
174 assertEquals(1, val2); | |
175 assertEquals(1, obj1.bar = 1) | |
176 assertEquals(2, val1); | |
177 assertEquals(2, val2); | |
178 assertEquals(2, obj1.bar); | |
179 | |
180 // Try to redefine bar again - should fail as configurable is false. | |
181 assertFalse(Reflect.defineProperty(obj1, "bar", accessorConfigurable)); | |
182 | |
183 // Try to redefine bar again using the data descriptor - should fail. | |
184 assertFalse(Reflect.defineProperty(obj1, "bar", dataConfigurable)); | |
185 | |
186 // Redefine using same descriptor - should succeed. | |
187 assertTrue(Reflect.defineProperty(obj1, "bar", accessorNoConfigurable)); | |
188 desc = Object.getOwnPropertyDescriptor(obj1, "bar"); | |
189 assertFalse(desc.configurable); | |
190 assertFalse(desc.enumerable); | |
191 assertEquals(desc.writable, undefined); | |
192 assertEquals(desc.get, accessorNoConfigurable.get); | |
193 assertEquals(desc.set, accessorNoConfigurable.set); | |
194 assertEquals(desc.value, undefined); | |
195 assertEquals(1, obj1.bar = 1); | |
196 assertEquals(2, val1); | |
197 assertEquals(3, val2); | |
198 assertEquals(1, obj1.bar = 1) | |
199 assertEquals(2, val1); | |
200 assertEquals(4, val2); | |
201 assertEquals(4, obj1.bar); | |
202 | |
203 // Define an accessor that has only a setter. | |
204 assertTrue(Reflect.defineProperty(obj1, "setOnly", accessorOnlySet)); | |
205 desc = Object.getOwnPropertyDescriptor(obj1, "setOnly"); | |
206 assertTrue(desc.configurable); | |
207 assertFalse(desc.enumerable); | |
208 assertEquals(desc.set, accessorOnlySet.set); | |
209 assertEquals(desc.writable, undefined); | |
210 assertEquals(desc.value, undefined); | |
211 assertEquals(desc.get, undefined); | |
212 assertEquals(1, obj1.setOnly = 1); | |
213 assertEquals(1, val3); | |
214 | |
215 // Add a getter - should not touch the setter. | |
216 assertTrue(Reflect.defineProperty(obj1, "setOnly", accessorOnlyGet)); | |
217 desc = Object.getOwnPropertyDescriptor(obj1, "setOnly"); | |
218 assertTrue(desc.configurable); | |
219 assertFalse(desc.enumerable); | |
220 assertEquals(desc.get, accessorOnlyGet.get); | |
221 assertEquals(desc.set, accessorOnlySet.set); | |
222 assertEquals(desc.writable, undefined); | |
223 assertEquals(desc.value, undefined); | |
224 assertEquals(1, obj1.setOnly = 1); | |
225 assertEquals(2, val3); | |
226 | |
227 // The above should also work if redefining just a getter or setter on | |
228 // an existing property with both a getter and a setter. | |
229 assertTrue(Reflect.defineProperty(obj1, "both", accessorConfigurable)); | |
230 | |
231 assertTrue(Reflect.defineProperty(obj1, "both", accessorOnlySet)); | |
232 desc = Object.getOwnPropertyDescriptor(obj1, "both"); | |
233 assertTrue(desc.configurable); | |
234 assertFalse(desc.enumerable); | |
235 assertEquals(desc.set, accessorOnlySet.set); | |
236 assertEquals(desc.get, accessorConfigurable.get); | |
237 assertEquals(desc.writable, undefined); | |
238 assertEquals(desc.value, undefined); | |
239 assertEquals(1, obj1.both = 1); | |
240 assertEquals(3, val3); | |
241 | |
242 | |
243 // Data properties | |
244 | |
245 assertTrue(Reflect.defineProperty(obj1, "foobar", dataConfigurable)); | |
246 desc = Object.getOwnPropertyDescriptor(obj1, "foobar"); | |
247 assertEquals(obj1.foobar, 1000); | |
248 assertEquals(desc.value, 1000); | |
249 assertTrue(desc.configurable); | |
250 assertFalse(desc.writable); | |
251 assertFalse(desc.enumerable); | |
252 assertEquals(desc.get, undefined); | |
253 assertEquals(desc.set, undefined); | |
254 //Try writing to non writable attribute - should remain 1000 | |
255 obj1.foobar = 1001; | |
256 assertEquals(obj1.foobar, 1000); | |
257 | |
258 | |
259 // Redefine to writable descriptor - now writing to foobar should be allowed. | |
260 assertTrue(Reflect.defineProperty(obj1, "foobar", dataWritable)); | |
261 desc = Object.getOwnPropertyDescriptor(obj1, "foobar"); | |
262 assertEquals(obj1.foobar, 3000); | |
263 assertEquals(desc.value, 3000); | |
264 // Note that since dataWritable does not define configurable the configurable | |
265 // setting from the redefined property (in this case true) is used. | |
266 assertTrue(desc.configurable); | |
267 assertTrue(desc.writable); | |
268 assertFalse(desc.enumerable); | |
269 assertEquals(desc.get, undefined); | |
270 assertEquals(desc.set, undefined); | |
271 // Writing to the property should now be allowed | |
272 obj1.foobar = 1001; | |
273 assertEquals(obj1.foobar, 1001); | |
274 | |
275 | |
276 // Redefine with non configurable data property. | |
277 assertTrue(Reflect.defineProperty(obj1, "foobar", dataNoConfigurable)); | |
278 desc = Object.getOwnPropertyDescriptor(obj1, "foobar"); | |
279 assertEquals(obj1.foobar, 2000); | |
280 assertEquals(desc.value, 2000); | |
281 assertFalse(desc.configurable); | |
282 assertTrue(desc.writable); | |
283 assertFalse(desc.enumerable); | |
284 assertEquals(desc.get, undefined); | |
285 assertEquals(desc.set, undefined); | |
286 | |
287 // Try redefine again - shold fail because configurable is now false. | |
288 assertFalse(Reflect.defineProperty(obj1, "foobar", dataConfigurable)); | |
289 | |
290 // Try redefine again with accessor property - shold also fail. | |
291 assertFalse(Reflect.defineProperty(obj1, "foobar", dataConfigurable)); | |
292 | |
293 | |
294 // Redifine with the same descriptor - should succeed (step 6). | |
295 assertTrue(Reflect.defineProperty(obj1, "foobar", dataNoConfigurable)); | |
296 desc = Object.getOwnPropertyDescriptor(obj1, "foobar"); | |
297 assertEquals(obj1.foobar, 2000); | |
298 assertEquals(desc.value, 2000); | |
299 assertFalse(desc.configurable); | |
300 assertTrue(desc.writable); | |
301 assertFalse(desc.enumerable); | |
302 assertEquals(desc.get, undefined); | |
303 assertEquals(desc.set, undefined); | |
304 | |
305 | |
306 // New object | |
307 var obj2 = {}; | |
308 | |
309 // Make accessor - redefine to data | |
310 assertTrue(Reflect.defineProperty(obj2, "foo", accessorConfigurable)); | |
311 | |
312 // Redefine to data property | |
313 assertTrue(Reflect.defineProperty(obj2, "foo", dataConfigurable)); | |
314 desc = Object.getOwnPropertyDescriptor(obj2, "foo"); | |
315 assertEquals(obj2.foo, 1000); | |
316 assertEquals(desc.value, 1000); | |
317 assertTrue(desc.configurable); | |
318 assertFalse(desc.writable); | |
319 assertFalse(desc.enumerable); | |
320 assertEquals(desc.get, undefined); | |
321 assertEquals(desc.set, undefined); | |
322 | |
323 | |
324 // Redefine back to accessor | |
325 assertTrue(Reflect.defineProperty(obj2, "foo", accessorConfigurable)); | |
326 desc = Object.getOwnPropertyDescriptor(obj2, "foo"); | |
327 assertTrue(desc.configurable); | |
328 assertFalse(desc.enumerable); | |
329 assertEquals(desc.writable, undefined); | |
330 assertEquals(desc.get, accessorConfigurable.get); | |
331 assertEquals(desc.set, accessorConfigurable.set); | |
332 assertEquals(desc.value, undefined); | |
333 assertEquals(1, obj2.foo = 1); | |
334 assertEquals(3, val1); | |
335 assertEquals(4, val2); | |
336 assertEquals(3, obj2.foo); | |
337 | |
338 // Make data - redefine to accessor | |
339 assertTrue(Reflect.defineProperty(obj2, "bar", dataConfigurable)) | |
340 | |
341 // Redefine to accessor property | |
342 assertTrue(Reflect.defineProperty(obj2, "bar", accessorConfigurable)); | |
343 desc = Object.getOwnPropertyDescriptor(obj2, "bar"); | |
344 assertTrue(desc.configurable); | |
345 assertFalse(desc.enumerable); | |
346 assertEquals(desc.writable, undefined); | |
347 assertEquals(desc.get, accessorConfigurable.get); | |
348 assertEquals(desc.set, accessorConfigurable.set); | |
349 assertEquals(desc.value, undefined); | |
350 assertEquals(1, obj2.bar = 1); | |
351 assertEquals(4, val1); | |
352 assertEquals(4, val2); | |
353 assertEquals(4, obj2.foo); | |
354 | |
355 // Redefine back to data property | |
356 assertTrue(Reflect.defineProperty(obj2, "bar", dataConfigurable)); | |
357 desc = Object.getOwnPropertyDescriptor(obj2, "bar"); | |
358 assertEquals(obj2.bar, 1000); | |
359 assertEquals(desc.value, 1000); | |
360 assertTrue(desc.configurable); | |
361 assertFalse(desc.writable); | |
362 assertFalse(desc.enumerable); | |
363 assertEquals(desc.get, undefined); | |
364 assertEquals(desc.set, undefined); | |
365 | |
366 | |
367 // Redefinition of an accessor defined using __defineGetter__ and | |
368 // __defineSetter__. | |
369 function get(){return this.x} | |
370 function set(x){this.x=x}; | |
371 | |
372 var obj3 = {x:1000}; | |
373 obj3.__defineGetter__("foo", get); | |
374 obj3.__defineSetter__("foo", set); | |
375 | |
376 desc = Object.getOwnPropertyDescriptor(obj3, "foo"); | |
377 assertTrue(desc.configurable); | |
378 assertTrue(desc.enumerable); | |
379 assertEquals(desc.writable, undefined); | |
380 assertEquals(desc.get, get); | |
381 assertEquals(desc.set, set); | |
382 assertEquals(desc.value, undefined); | |
383 assertEquals(1, obj3.foo = 1); | |
384 assertEquals(1, obj3.x); | |
385 assertEquals(1, obj3.foo); | |
386 | |
387 // Redefine to accessor property (non configurable) - note that enumerable | |
388 // which we do not redefine should remain the same (true). | |
389 assertTrue(Reflect.defineProperty(obj3, "foo", accessorNoConfigurable)); | |
390 desc = Object.getOwnPropertyDescriptor(obj3, "foo"); | |
391 assertFalse(desc.configurable); | |
392 assertTrue(desc.enumerable); | |
393 assertEquals(desc.writable, undefined); | |
394 assertEquals(desc.get, accessorNoConfigurable.get); | |
395 assertEquals(desc.set, accessorNoConfigurable.set); | |
396 assertEquals(desc.value, undefined); | |
397 assertEquals(1, obj3.foo = 1); | |
398 assertEquals(5, val2); | |
399 assertEquals(5, obj3.foo); | |
400 | |
401 | |
402 obj3.__defineGetter__("bar", get); | |
403 obj3.__defineSetter__("bar", set); | |
404 | |
405 | |
406 // Redefine back to data property | |
407 assertTrue(Reflect.defineProperty(obj3, "bar", dataConfigurable)); | |
408 desc = Object.getOwnPropertyDescriptor(obj3, "bar"); | |
409 assertEquals(obj3.bar, 1000); | |
410 assertEquals(desc.value, 1000); | |
411 assertTrue(desc.configurable); | |
412 assertFalse(desc.writable); | |
413 assertTrue(desc.enumerable); | |
414 assertEquals(desc.get, undefined); | |
415 assertEquals(desc.set, undefined); | |
416 | |
417 | |
418 var obj4 = {}; | |
419 var func = function (){return 42;}; | |
420 obj4.bar = func; | |
421 assertEquals(42, obj4.bar()); | |
422 | |
423 assertTrue(Reflect.defineProperty(obj4, "bar", accessorConfigurable)); | |
424 desc = Object.getOwnPropertyDescriptor(obj4, "bar"); | |
425 assertTrue(desc.configurable); | |
426 assertTrue(desc.enumerable); | |
427 assertEquals(desc.writable, undefined); | |
428 assertEquals(desc.get, accessorConfigurable.get); | |
429 assertEquals(desc.set, accessorConfigurable.set); | |
430 assertEquals(desc.value, undefined); | |
431 assertEquals(1, obj4.bar = 1); | |
432 assertEquals(5, val1); | |
433 assertEquals(5, obj4.bar); | |
434 | |
435 // Make sure an error is thrown when trying to access to redefined function. | |
436 try { | |
437 obj4.bar(); | |
438 assertTrue(false); | |
439 } catch (e) { | |
440 assertTrue(/is not a function/.test(e)); | |
441 } | |
442 | |
443 | |
444 // Test runtime calls to DefineDataPropertyUnchecked and | |
445 // DefineAccessorPropertyUnchecked - make sure we don't | |
446 // crash. | |
447 try { | |
448 %DefineAccessorPropertyUnchecked(0, 0, 0, 0, 0); | |
449 } catch (e) { | |
450 assertTrue(/illegal access/.test(e)); | |
451 } | |
452 | |
453 try { | |
454 %DefineDataPropertyUnchecked(0, 0, 0, 0); | |
455 } catch (e) { | |
456 assertTrue(/illegal access/.test(e)); | |
457 } | |
458 | |
459 try { | |
460 %DefineDataPropertyUnchecked(null, null, null, null); | |
461 } catch (e) { | |
462 assertTrue(/illegal access/.test(e)); | |
463 } | |
464 | |
465 try { | |
466 %DefineAccessorPropertyUnchecked(null, null, null, null, null); | |
467 } catch (e) { | |
468 assertTrue(/illegal access/.test(e)); | |
469 } | |
470 | |
471 try { | |
472 %DefineDataPropertyUnchecked({}, null, null, null); | |
473 } catch (e) { | |
474 assertTrue(/illegal access/.test(e)); | |
475 } | |
476 | |
477 // Defining properties null should fail even when we have | |
478 // other allowed values | |
479 try { | |
480 %DefineAccessorPropertyUnchecked(null, 'foo', func, null, 0); | |
481 } catch (e) { | |
482 assertTrue(/illegal access/.test(e)); | |
483 } | |
484 | |
485 try { | |
486 %DefineDataPropertyUnchecked(null, 'foo', 0, 0); | |
487 } catch (e) { | |
488 assertTrue(/illegal access/.test(e)); | |
489 } | |
490 | |
491 // Test that all possible differences in step 6 in DefineOwnProperty are | |
492 // exercised, i.e., any difference in the given property descriptor and the | |
493 // existing properties should not return true, but throw an error if the | |
494 // existing configurable property is false. | |
495 | |
496 var obj5 = {}; | |
497 // Enumerable will default to false. | |
498 assertTrue(Reflect.defineProperty(obj5, 'foo', accessorNoConfigurable)); | |
499 desc = Object.getOwnPropertyDescriptor(obj5, 'foo'); | |
500 // First, test that we are actually allowed to set the accessor if all | |
501 // values are of the descriptor are the same as the existing one. | |
502 assertTrue(Reflect.defineProperty(obj5, 'foo', accessorNoConfigurable)); | |
503 | |
504 // Different setter. | |
505 var descDifferent = { | |
506 configurable:false, | |
507 enumerable:false, | |
508 set: setter1, | |
509 get: getter2 | |
510 }; | |
511 | |
512 assertFalse(Reflect.defineProperty(obj5, 'foo', descDifferent)); | |
513 | |
514 // Different getter. | |
515 descDifferent = { | |
516 configurable:false, | |
517 enumerable:false, | |
518 set: setter2, | |
519 get: getter1 | |
520 }; | |
521 | |
522 assertFalse(Reflect.defineProperty(obj5, 'foo', descDifferent)); | |
523 | |
524 // Different enumerable. | |
525 descDifferent = { | |
526 configurable:false, | |
527 enumerable:true, | |
528 set: setter2, | |
529 get: getter2 | |
530 }; | |
531 | |
532 assertFalse(Reflect.defineProperty(obj5, 'foo', descDifferent)); | |
533 | |
534 // Different configurable. | |
535 descDifferent = { | |
536 configurable:false, | |
537 enumerable:true, | |
538 set: setter2, | |
539 get: getter2 | |
540 }; | |
541 | |
542 assertFalse(Reflect.defineProperty(obj5, 'foo', descDifferent)); | |
543 | |
544 // No difference. | |
545 descDifferent = { | |
546 configurable:false, | |
547 enumerable:false, | |
548 set: setter2, | |
549 get: getter2 | |
550 }; | |
551 // Make sure we can still redefine if all properties are the same. | |
552 assertTrue(Reflect.defineProperty(obj5, 'foo', descDifferent)); | |
553 | |
554 // Make sure that obj5 still holds the original values. | |
555 desc = Object.getOwnPropertyDescriptor(obj5, 'foo'); | |
556 assertEquals(desc.get, getter2); | |
557 assertEquals(desc.set, setter2); | |
558 assertFalse(desc.enumerable); | |
559 assertFalse(desc.configurable); | |
560 | |
561 | |
562 // Also exercise step 6 on data property, writable and enumerable | |
563 // defaults to false. | |
564 assertTrue(Reflect.defineProperty(obj5, 'bar', dataNoConfigurable)); | |
565 | |
566 // Test that redefinition with the same property descriptor is possible | |
567 assertTrue(Reflect.defineProperty(obj5, 'bar', dataNoConfigurable)); | |
568 | |
569 // Different value. | |
570 descDifferent = { | |
571 configurable:false, | |
572 enumerable:false, | |
573 writable: false, | |
574 value: 1999 | |
575 }; | |
576 | |
577 assertFalse(Reflect.defineProperty(obj5, 'bar', descDifferent)); | |
578 | |
579 // Different writable. | |
580 descDifferent = { | |
581 configurable:false, | |
582 enumerable:false, | |
583 writable: true, | |
584 value: 2000 | |
585 }; | |
586 | |
587 assertFalse(Reflect.defineProperty(obj5, 'bar', descDifferent)); | |
588 | |
589 | |
590 // Different enumerable. | |
591 descDifferent = { | |
592 configurable:false, | |
593 enumerable:true , | |
594 writable:false, | |
595 value: 2000 | |
596 }; | |
597 | |
598 assertFalse(Reflect.defineProperty(obj5, 'bar', descDifferent)); | |
599 | |
600 | |
601 // Different configurable. | |
602 descDifferent = { | |
603 configurable:true, | |
604 enumerable:false, | |
605 writable:false, | |
606 value: 2000 | |
607 }; | |
608 | |
609 assertFalse(Reflect.defineProperty(obj5, 'bar', descDifferent)); | |
610 | |
611 // No difference. | |
612 descDifferent = { | |
613 configurable:false, | |
614 enumerable:false, | |
615 writable:false, | |
616 value:2000 | |
617 }; | |
618 // Make sure we can still redefine if all properties are the same. | |
619 assertTrue(Reflect.defineProperty(obj5, 'bar', descDifferent)); | |
620 | |
621 // Make sure that obj5 still holds the original values. | |
622 desc = Object.getOwnPropertyDescriptor(obj5, 'bar'); | |
623 assertEquals(desc.value, 2000); | |
624 assertFalse(desc.writable); | |
625 assertFalse(desc.enumerable); | |
626 assertFalse(desc.configurable); | |
627 | |
628 | |
629 // Make sure that we can't overwrite +0 with -0 and vice versa. | |
630 var descMinusZero = {value: -0, configurable: false}; | |
631 var descPlusZero = {value: +0, configurable: false}; | |
632 | |
633 assertTrue(Reflect.defineProperty(obj5, 'minuszero', descMinusZero)); | |
634 | |
635 // Make sure we can redefine with -0. | |
636 assertTrue(Reflect.defineProperty(obj5, 'minuszero', descMinusZero)); | |
637 | |
638 assertFalse(Reflect.defineProperty(obj5, 'minuszero', descPlusZero)); | |
639 | |
640 | |
641 assertTrue(Reflect.defineProperty(obj5, 'pluszero', descPlusZero)); | |
642 | |
643 // Make sure we can redefine with +0. | |
644 assertTrue(Reflect.defineProperty(obj5, 'pluszero', descPlusZero)); | |
645 | |
646 assertFalse(Reflect.defineProperty(obj5, 'pluszero', descMinusZero)); | |
647 | |
648 | |
649 var obj6 = {}; | |
650 obj6[1] = 'foo'; | |
651 obj6[2] = 'bar'; | |
652 obj6[3] = '42'; | |
653 obj6[4] = '43'; | |
654 obj6[5] = '44'; | |
655 | |
656 var descElement = { value: 'foobar' }; | |
657 var descElementNonConfigurable = { value: 'barfoo', configurable: false }; | |
658 var descElementNonWritable = { value: 'foofoo', writable: false }; | |
659 var descElementNonEnumerable = { value: 'barbar', enumerable: false }; | |
660 var descElementAllFalse = { value: 'foofalse', | |
661 configurable: false, | |
662 writable: false, | |
663 enumerable: false }; | |
664 | |
665 | |
666 // Redefine existing property. | |
667 assertTrue(Reflect.defineProperty(obj6, '1', descElement)); | |
668 desc = Object.getOwnPropertyDescriptor(obj6, '1'); | |
669 assertEquals(desc.value, 'foobar'); | |
670 assertTrue(desc.writable); | |
671 assertTrue(desc.enumerable); | |
672 assertTrue(desc.configurable); | |
673 | |
674 // Redefine existing property with configurable: false. | |
675 assertTrue(Reflect.defineProperty(obj6, '2', descElementNonConfigurable)); | |
676 desc = Object.getOwnPropertyDescriptor(obj6, '2'); | |
677 assertEquals(desc.value, 'barfoo'); | |
678 assertTrue(desc.writable); | |
679 assertTrue(desc.enumerable); | |
680 assertFalse(desc.configurable); | |
681 | |
682 // Can use defineProperty to change the value of a non | |
683 // configurable property. | |
684 try { | |
685 assertTrue(Reflect.defineProperty(obj6, '2', descElement)); | |
686 desc = Object.getOwnPropertyDescriptor(obj6, '2'); | |
687 assertEquals(desc.value, 'foobar'); | |
688 } catch (e) { | |
689 assertUnreachable(); | |
690 } | |
691 | |
692 // Ensure that we can't change the descriptor of a | |
693 // non configurable property. | |
694 var descAccessor = { get: function() { return 0; } }; | |
695 assertFalse(Reflect.defineProperty(obj6, '2', descAccessor)); | |
696 | |
697 assertTrue(Reflect.defineProperty(obj6, '2', descElementNonWritable)); | |
698 desc = Object.getOwnPropertyDescriptor(obj6, '2'); | |
699 assertEquals(desc.value, 'foofoo'); | |
700 assertFalse(desc.writable); | |
701 assertTrue(desc.enumerable); | |
702 assertFalse(desc.configurable); | |
703 | |
704 assertTrue(Reflect.defineProperty(obj6, '3', descElementNonWritable)); | |
705 desc = Object.getOwnPropertyDescriptor(obj6, '3'); | |
706 assertEquals(desc.value, 'foofoo'); | |
707 assertFalse(desc.writable); | |
708 assertTrue(desc.enumerable); | |
709 assertTrue(desc.configurable); | |
710 | |
711 // Redefine existing property with configurable: false. | |
712 assertTrue(Reflect.defineProperty(obj6, '4', descElementNonEnumerable)); | |
713 desc = Object.getOwnPropertyDescriptor(obj6, '4'); | |
714 assertEquals(desc.value, 'barbar'); | |
715 assertTrue(desc.writable); | |
716 assertFalse(desc.enumerable); | |
717 assertTrue(desc.configurable); | |
718 | |
719 // Redefine existing property with configurable: false. | |
720 assertTrue(Reflect.defineProperty(obj6, '5', descElementAllFalse)); | |
721 desc = Object.getOwnPropertyDescriptor(obj6, '5'); | |
722 assertEquals(desc.value, 'foofalse'); | |
723 assertFalse(desc.writable); | |
724 assertFalse(desc.enumerable); | |
725 assertFalse(desc.configurable); | |
726 | |
727 // Define non existing property - all attributes should default to false. | |
728 assertTrue(Reflect.defineProperty(obj6, '15', descElement)); | |
729 desc = Object.getOwnPropertyDescriptor(obj6, '15'); | |
730 assertEquals(desc.value, 'foobar'); | |
731 assertFalse(desc.writable); | |
732 assertFalse(desc.enumerable); | |
733 assertFalse(desc.configurable); | |
734 | |
735 // Make sure that we can't redefine using direct access. | |
736 obj6[15] ='overwrite'; | |
737 assertEquals(obj6[15],'foobar'); | |
738 | |
739 | |
740 // Repeat the above tests on an array. | |
741 var arr = new Array(); | |
742 arr[1] = 'foo'; | |
743 arr[2] = 'bar'; | |
744 arr[3] = '42'; | |
745 arr[4] = '43'; | |
746 arr[5] = '44'; | |
747 | |
748 var descElement = { value: 'foobar' }; | |
749 var descElementNonConfigurable = { value: 'barfoo', configurable: false }; | |
750 var descElementNonWritable = { value: 'foofoo', writable: false }; | |
751 var descElementNonEnumerable = { value: 'barbar', enumerable: false }; | |
752 var descElementAllFalse = { value: 'foofalse', | |
753 configurable: false, | |
754 writable: false, | |
755 enumerable: false }; | |
756 | |
757 | |
758 // Redefine existing property. | |
759 assertTrue(Reflect.defineProperty(arr, '1', descElement)); | |
760 desc = Object.getOwnPropertyDescriptor(arr, '1'); | |
761 assertEquals(desc.value, 'foobar'); | |
762 assertTrue(desc.writable); | |
763 assertTrue(desc.enumerable); | |
764 assertTrue(desc.configurable); | |
765 | |
766 // Redefine existing property with configurable: false. | |
767 assertTrue(Reflect.defineProperty(arr, '2', descElementNonConfigurable)); | |
768 desc = Object.getOwnPropertyDescriptor(arr, '2'); | |
769 assertEquals(desc.value, 'barfoo'); | |
770 assertTrue(desc.writable); | |
771 assertTrue(desc.enumerable); | |
772 assertFalse(desc.configurable); | |
773 | |
774 // Can use defineProperty to change the value of a non | |
775 // configurable property of an array. | |
776 try { | |
777 assertTrue(Reflect.defineProperty(arr, '2', descElement)); | |
778 desc = Object.getOwnPropertyDescriptor(arr, '2'); | |
779 assertEquals(desc.value, 'foobar'); | |
780 } catch (e) { | |
781 assertUnreachable(); | |
782 } | |
783 | |
784 // Ensure that we can't change the descriptor of a | |
785 // non configurable property. | |
786 var descAccessor = { get: function() { return 0; } }; | |
787 assertFalse(Reflect.defineProperty(arr, '2', descAccessor)); | |
788 | |
789 assertTrue(Reflect.defineProperty(arr, '2', descElementNonWritable)); | |
790 desc = Object.getOwnPropertyDescriptor(arr, '2'); | |
791 assertEquals(desc.value, 'foofoo'); | |
792 assertFalse(desc.writable); | |
793 assertTrue(desc.enumerable); | |
794 assertFalse(desc.configurable); | |
795 | |
796 assertTrue(Reflect.defineProperty(arr, '3', descElementNonWritable)); | |
797 desc = Object.getOwnPropertyDescriptor(arr, '3'); | |
798 assertEquals(desc.value, 'foofoo'); | |
799 assertFalse(desc.writable); | |
800 assertTrue(desc.enumerable); | |
801 assertTrue(desc.configurable); | |
802 | |
803 // Redefine existing property with configurable: false. | |
804 assertTrue(Reflect.defineProperty(arr, '4', descElementNonEnumerable)); | |
805 desc = Object.getOwnPropertyDescriptor(arr, '4'); | |
806 assertEquals(desc.value, 'barbar'); | |
807 assertTrue(desc.writable); | |
808 assertFalse(desc.enumerable); | |
809 assertTrue(desc.configurable); | |
810 | |
811 // Redefine existing property with configurable: false. | |
812 assertTrue(Reflect.defineProperty(arr, '5', descElementAllFalse)); | |
813 desc = Object.getOwnPropertyDescriptor(arr, '5'); | |
814 assertEquals(desc.value, 'foofalse'); | |
815 assertFalse(desc.writable); | |
816 assertFalse(desc.enumerable); | |
817 assertFalse(desc.configurable); | |
818 | |
819 // Define non existing property - all attributes should default to false. | |
820 assertTrue(Reflect.defineProperty(arr, '15', descElement)); | |
821 desc = Object.getOwnPropertyDescriptor(arr, '15'); | |
822 assertEquals(desc.value, 'foobar'); | |
823 assertFalse(desc.writable); | |
824 assertFalse(desc.enumerable); | |
825 assertFalse(desc.configurable); | |
826 | |
827 // Define non-array property, check that .length is unaffected. | |
828 assertEquals(16, arr.length); | |
829 assertTrue(Reflect.defineProperty(arr, '0x20', descElement)); | |
830 assertEquals(16, arr.length); | |
831 | |
832 // See issue 968: http://code.google.com/p/v8/issues/detail?id=968 | |
833 var o = { x : 42 }; | |
834 assertTrue(Reflect.defineProperty(o, "x", { writable: false })); | |
835 assertEquals(42, o.x); | |
836 o.x = 37; | |
837 assertEquals(42, o.x); | |
838 | |
839 o = { x : 42 }; | |
840 assertTrue(Reflect.defineProperty(o, "x", {})); | |
841 assertEquals(42, o.x); | |
842 o.x = 37; | |
843 // Writability is preserved. | |
844 assertEquals(37, o.x); | |
845 | |
846 var o = { }; | |
847 assertTrue(Reflect.defineProperty(o, "x", { writable: false })); | |
848 assertEquals(undefined, o.x); | |
849 o.x = 37; | |
850 assertEquals(undefined, o.x); | |
851 | |
852 o = { get x() { return 87; } }; | |
853 assertTrue(Reflect.defineProperty(o, "x", { writable: false })); | |
854 assertEquals(undefined, o.x); | |
855 o.x = 37; | |
856 assertEquals(undefined, o.x); | |
857 | |
858 // Ignore inherited properties. | |
859 o = { __proto__ : { x : 87 } }; | |
860 assertTrue(Reflect.defineProperty(o, "x", { writable: false })); | |
861 assertEquals(undefined, o.x); | |
862 o.x = 37; | |
863 assertEquals(undefined, o.x); | |
864 | |
865 function testDefineProperty(obj, propertyName, desc, resultDesc) { | |
866 assertTrue(Reflect.defineProperty(obj, propertyName, desc)); | |
867 var actualDesc = Object.getOwnPropertyDescriptor(obj, propertyName); | |
868 assertEquals(resultDesc.enumerable, actualDesc.enumerable); | |
869 assertEquals(resultDesc.configurable, actualDesc.configurable); | |
870 if (resultDesc.hasOwnProperty('value')) { | |
871 assertEquals(resultDesc.value, actualDesc.value); | |
872 assertEquals(resultDesc.writable, actualDesc.writable); | |
873 assertFalse(resultDesc.hasOwnProperty('get')); | |
874 assertFalse(resultDesc.hasOwnProperty('set')); | |
875 } else { | |
876 assertEquals(resultDesc.get, actualDesc.get); | |
877 assertEquals(resultDesc.set, actualDesc.set); | |
878 assertFalse(resultDesc.hasOwnProperty('value')); | |
879 assertFalse(resultDesc.hasOwnProperty('writable')); | |
880 } | |
881 } | |
882 | |
883 // tests redefining existing property with a generic descriptor | |
884 o = { p : 42 }; | |
885 testDefineProperty(o, 'p', | |
886 { }, | |
887 { value : 42, writable : true, enumerable : true, configurable : true }); | |
888 | |
889 o = { p : 42 }; | |
890 testDefineProperty(o, 'p', | |
891 { enumerable : true }, | |
892 { value : 42, writable : true, enumerable : true, configurable : true }); | |
893 | |
894 o = { p : 42 }; | |
895 testDefineProperty(o, 'p', | |
896 { configurable : true }, | |
897 { value : 42, writable : true, enumerable : true, configurable : true }); | |
898 | |
899 o = { p : 42 }; | |
900 testDefineProperty(o, 'p', | |
901 { enumerable : false }, | |
902 { value : 42, writable : true, enumerable : false, configurable : true }); | |
903 | |
904 o = { p : 42 }; | |
905 testDefineProperty(o, 'p', | |
906 { configurable : false }, | |
907 { value : 42, writable : true, enumerable : true, configurable : false }); | |
908 | |
909 o = { p : 42 }; | |
910 testDefineProperty(o, 'p', | |
911 { enumerable : true, configurable : true }, | |
912 { value : 42, writable : true, enumerable : true, configurable : true }); | |
913 | |
914 o = { p : 42 }; | |
915 testDefineProperty(o, 'p', | |
916 { enumerable : false, configurable : true }, | |
917 { value : 42, writable : true, enumerable : false, configurable : true }); | |
918 | |
919 o = { p : 42 }; | |
920 testDefineProperty(o, 'p', | |
921 { enumerable : true, configurable : false }, | |
922 { value : 42, writable : true, enumerable : true, configurable : false }); | |
923 | |
924 o = { p : 42 }; | |
925 testDefineProperty(o, 'p', | |
926 { enumerable : false, configurable : false }, | |
927 { value : 42, writable : true, enumerable : false, configurable : false }); | |
928 | |
929 // can make a writable, non-configurable field non-writable | |
930 o = { p : 42 }; | |
931 assertTrue(Reflect.defineProperty(o, 'p', { configurable: false })); | |
932 testDefineProperty(o, 'p', | |
933 { writable: false }, | |
934 { value : 42, writable : false, enumerable : true, configurable : false }); | |
935 | |
936 // redefine of get only property with generic descriptor | |
937 o = {}; | |
938 assertTrue(Reflect.defineProperty(o, 'p', | |
939 { get : getter1, enumerable: true, configurable: true })); | |
940 testDefineProperty(o, 'p', | |
941 { enumerable : false, configurable : false }, | |
942 { get: getter1, set: undefined, enumerable : false, configurable : false }); | |
943 | |
944 // redefine of get/set only property with generic descriptor | |
945 o = {}; | |
946 assertTrue(Reflect.defineProperty(o, 'p', | |
947 { get: getter1, set: setter1, enumerable: true, configurable: true })); | |
948 testDefineProperty(o, 'p', | |
949 { enumerable : false, configurable : false }, | |
950 { get: getter1, set: setter1, enumerable : false, configurable : false }); | |
951 | |
952 // redefine of set only property with generic descriptor | |
953 o = {}; | |
954 assertTrue(Reflect.defineProperty(o, 'p', | |
955 { set : setter1, enumerable: true, configurable: true })); | |
956 testDefineProperty(o, 'p', | |
957 { enumerable : false, configurable : false }, | |
958 { get: undefined, set: setter1, enumerable : false, configurable : false }); | |
959 | |
960 | |
961 // Regression test: Ensure that growing dictionaries are not ignored. | |
962 o = {}; | |
963 for (var i = 0; i < 1000; i++) { | |
964 // Non-enumerable property forces dictionary mode. | |
965 assertTrue(Reflect.defineProperty(o, i, {value: i, enumerable: false})); | |
966 } | |
967 assertEquals(999, o[999]); | |
968 | |
969 | |
970 // Regression test: Bizzare behavior on non-strict arguments object. | |
971 // TODO(yangguo): Tests disabled, needs investigation! | |
972 /* | |
973 (function test(arg0) { | |
974 // Here arguments[0] is a fast alias on arg0. | |
975 Reflect.defineProperty(arguments, "0", { | |
976 value:1, | |
977 enumerable:false | |
978 }); | |
979 // Here arguments[0] is a slow alias on arg0. | |
980 Reflect.defineProperty(arguments, "0", { | |
981 value:2, | |
982 writable:false | |
983 }); | |
984 // Here arguments[0] is no alias at all. | |
985 Reflect.defineProperty(arguments, "0", { | |
986 value:3 | |
987 }); | |
988 assertEquals(2, arg0); | |
989 assertEquals(3, arguments[0]); | |
990 })(0); | |
991 */ | |
992 | |
993 // Regression test: We should never observe the hole value. | |
994 var objectWithGetter = {}; | |
995 objectWithGetter.__defineGetter__('foo', function() {}); | |
996 assertEquals(undefined, objectWithGetter.__lookupSetter__('foo')); | |
997 | |
998 var objectWithSetter = {}; | |
999 objectWithSetter.__defineSetter__('foo', function(x) {}); | |
1000 assertEquals(undefined, objectWithSetter.__lookupGetter__('foo')); | |
1001 | |
1002 // An object with a getter on the prototype chain. | |
1003 function getter() { return 111; } | |
1004 function anotherGetter() { return 222; } | |
1005 | |
1006 function testGetterOnProto(expected, o) { | |
1007 assertEquals(expected, o.quebec); | |
1008 } | |
1009 | |
1010 obj1 = {}; | |
1011 assertTrue( | |
1012 Reflect.defineProperty(obj1, "quebec", { get: getter, configurable: true })); | |
1013 obj2 = Object.create(obj1); | |
1014 obj3 = Object.create(obj2); | |
1015 | |
1016 testGetterOnProto(111, obj3); | |
1017 testGetterOnProto(111, obj3); | |
1018 %OptimizeFunctionOnNextCall(testGetterOnProto); | |
1019 testGetterOnProto(111, obj3); | |
1020 testGetterOnProto(111, obj3); | |
1021 | |
1022 assertTrue(Reflect.defineProperty(obj1, "quebec", { get: anotherGetter })); | |
1023 | |
1024 testGetterOnProto(222, obj3); | |
1025 testGetterOnProto(222, obj3); | |
1026 %OptimizeFunctionOnNextCall(testGetterOnProto); | |
1027 testGetterOnProto(222, obj3); | |
1028 testGetterOnProto(222, obj3); | |
1029 | |
1030 // An object with a setter on the prototype chain. | |
1031 var modifyMe; | |
1032 function setter(x) { modifyMe = x+1; } | |
1033 function anotherSetter(x) { modifyMe = x+2; } | |
1034 | |
1035 function testSetterOnProto(expected, o) { | |
1036 modifyMe = 333; | |
1037 o.romeo = 444; | |
1038 assertEquals(expected, modifyMe); | |
1039 } | |
1040 | |
1041 obj1 = {}; | |
1042 assertTrue( | |
1043 Reflect.defineProperty(obj1, "romeo", { set: setter, configurable: true })); | |
1044 obj2 = Object.create(obj1); | |
1045 obj3 = Object.create(obj2); | |
1046 | |
1047 testSetterOnProto(445, obj3); | |
1048 testSetterOnProto(445, obj3); | |
1049 %OptimizeFunctionOnNextCall(testSetterOnProto); | |
1050 testSetterOnProto(445, obj3); | |
1051 testSetterOnProto(445, obj3); | |
1052 | |
1053 assertTrue(Reflect.defineProperty(obj1, "romeo", { set: anotherSetter })); | |
1054 | |
1055 testSetterOnProto(446, obj3); | |
1056 testSetterOnProto(446, obj3); | |
1057 %OptimizeFunctionOnNextCall(testSetterOnProto); | |
1058 testSetterOnProto(446, obj3); | |
1059 testSetterOnProto(446, obj3); | |
1060 | |
1061 // Removing a setter on the prototype chain. | |
1062 function testSetterOnProtoStrict(o) { | |
1063 "use strict"; | |
1064 o.sierra = 12345; | |
1065 } | |
1066 | |
1067 obj1 = {}; | |
1068 assertTrue(Reflect.defineProperty(obj1, "sierra", | |
1069 { get: getter, set: setter, configurable: true })); | |
1070 obj2 = Object.create(obj1); | |
1071 obj3 = Object.create(obj2); | |
1072 | |
1073 testSetterOnProtoStrict(obj3); | |
1074 testSetterOnProtoStrict(obj3); | |
1075 %OptimizeFunctionOnNextCall(testSetterOnProtoStrict); | |
1076 testSetterOnProtoStrict(obj3); | |
1077 testSetterOnProtoStrict(obj3); | |
1078 | |
1079 assertTrue(Reflect.defineProperty(obj1, "sierra", | |
1080 { get: getter, set: undefined, configurable: true })); | |
1081 | |
1082 exception = false; | |
1083 try { | |
1084 testSetterOnProtoStrict(obj3); | |
1085 } catch (e) { | |
1086 exception = true; | |
1087 assertTrue(/which has only a getter/.test(e)); | |
1088 } | |
1089 assertTrue(exception); | |
1090 | |
1091 // Test assignment to a getter-only property on the prototype chain. This makes | |
1092 // sure that crankshaft re-checks its assumptions and doesn't rely only on type | |
1093 // feedback (which would be monomorphic here). | |
1094 | |
1095 function Assign(o) { | |
1096 o.blubb = 123; | |
1097 } | |
1098 | |
1099 function C() {} | |
1100 | |
1101 Assign(new C); | |
1102 Assign(new C); | |
1103 %OptimizeFunctionOnNextCall(Assign); | |
1104 assertTrue( | |
1105 Reflect.defineProperty(C.prototype, "blubb", {get: function() {return -42}})); | |
1106 Assign(new C); | |
1107 | |
1108 // Test that changes to the prototype of a simple constructor are not ignored, | |
1109 // even after creating initial instances. | |
1110 function C() { | |
1111 this.x = 23; | |
1112 } | |
1113 assertEquals(23, new C().x); | |
1114 C.prototype.__defineSetter__('x', function(value) { this.y = 23; }); | |
1115 assertEquals(void 0, new C().x); | |
OLD | NEW |