1 // Copyright 2010 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 object.defineProperty method - ES 15.2.3.6 29 30 // Flags: --allow-natives-syntax 31 32 // Check that an exception is thrown when null is passed as object. 33 try { 34 Object.defineProperty(null, null, null); 35 assertTrue(false); 36 } catch (e) { 37 assertTrue(/called on non-object/.test(e)); 38 } 39 40 // Check that an exception is thrown when undefined is passed as object. 41 try { 42 Object.defineProperty(undefined, undefined, undefined); 43 assertTrue(false); 44 } catch (e) { 45 assertTrue(/called on non-object/.test(e)); 46 } 47 48 // Check that an exception is thrown when non-object is passed as object. 49 try { 50 Object.defineProperty(0, "foo", undefined); 51 assertTrue(false); 52 } catch (e) { 53 assertTrue(/called on non-object/.test(e)); 54 } 55 56 // Object 57 var obj1 = {}; 58 59 // Values 60 var val1 = 0; 61 var val2 = 0; 62 var val3 = 0; 63 64 // Descriptors 65 var emptyDesc = {}; 66 67 var accessorConfigurable = { 68 set: function() { val1++; }, 69 get: function() { return val1; }, 70 configurable: true 71 }; 72 73 var accessorNoConfigurable = { 74 set: function() { val2++; }, 75 get: function() { return val2; }, 76 configurable: false 77 }; 78 79 var accessorOnlySet = { 80 set: function() { val3++; }, 81 configurable: true 82 }; 83 84 var accessorOnlyGet = { 85 get: function() { return val3; }, 86 configurable: true 87 }; 88 89 var accessorDefault = {set: function(){} }; 90 91 var dataConfigurable = { value: 1000, configurable: true }; 92 93 var dataNoConfigurable = { value: 2000, configurable: false }; 94 95 var dataWritable = { value: 3000, writable: true}; 96 97 98 // Check that we can't add property with undefined attributes. 99 try { 100 Object.defineProperty(obj1, "foo", undefined); 101 assertTrue(false); 102 } catch (e) { 103 assertTrue(/must be an object/.test(e)); 104 } 105 106 // Make sure that we can add a property with an empty descriptor and 107 // that it has the default descriptor values. 108 Object.defineProperty(obj1, "foo", emptyDesc); 109 110 // foo should be undefined as it has no get, set or value 111 assertEquals(undefined, obj1.foo); 112 113 // We should, however, be able to retrieve the propertydescriptor which should 114 // have all default values (according to 8.6.1). 115 var desc = Object.getOwnPropertyDescriptor(obj1, "foo"); 116 assertFalse(desc.configurable); 117 assertFalse(desc.enumerable); 118 assertFalse(desc.writable); 119 assertEquals(desc.get, undefined); 120 assertEquals(desc.set, undefined); 121 assertEquals(desc.value, undefined); 122 123 // Make sure that getOwnPropertyDescriptor does not return a descriptor 124 // with default values if called with non existing property (otherwise 125 // the test above is invalid). 126 desc = Object.getOwnPropertyDescriptor(obj1, "bar"); 127 assertEquals(desc, undefined); 128 129 // Make sure that foo can't be reset (as configurable is false). 130 try { 131 Object.defineProperty(obj1, "foo", accessorConfigurable); 132 } catch (e) { 133 assertTrue(/Cannot redefine property/.test(e)); 134 } 135 136 137 // Accessor properties 138 139 Object.defineProperty(obj1, "bar", accessorConfigurable); 140 desc = Object.getOwnPropertyDescriptor(obj1, "bar"); 141 assertTrue(desc.configurable); 142 assertFalse(desc.enumerable); 143 assertEquals(desc.writable, undefined); 144 assertEquals(desc.get, accessorConfigurable.get); 145 assertEquals(desc.set, accessorConfigurable.set); 146 assertEquals(desc.value, undefined); 147 assertEquals(1, obj1.bar = 1); 148 assertEquals(1, val1); 149 assertEquals(1, obj1.bar = 1); 150 assertEquals(2, val1); 151 assertEquals(2, obj1.bar); 152 153 // Redefine bar with non configurable test 154 Object.defineProperty(obj1, "bar", accessorNoConfigurable); 155 desc = Object.getOwnPropertyDescriptor(obj1, "bar"); 156 assertFalse(desc.configurable); 157 assertFalse(desc.enumerable); 158 assertEquals(desc.writable, undefined); 159 assertEquals(desc.get, accessorNoConfigurable.get); 160 assertEquals(desc.set, accessorNoConfigurable.set); 161 assertEquals(desc.value, undefined); 162 assertEquals(1, obj1.bar = 1); 163 assertEquals(2, val1); 164 assertEquals(1, val2); 165 assertEquals(1, obj1.bar = 1) 166 assertEquals(2, val1); 167 assertEquals(2, val2); 168 assertEquals(2, obj1.bar); 169 170 // Try to redefine bar again - should fail as configurable is false. 171 try { 172 Object.defineProperty(obj1, "bar", accessorConfigurable); 173 assertTrue(false); 174 } catch(e) { 175 assertTrue(/Cannot redefine property/.test(e)); 176 } 177 178 // Try to redefine bar again using the data descriptor - should fail. 179 try { 180 Object.defineProperty(obj1, "bar", dataConfigurable); 181 assertTrue(false); 182 } catch(e) { 183 assertTrue(/Cannot redefine property/.test(e)); 184 } 185 186 // Redefine using same descriptor - should succeed. 187 Object.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 Object.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 Object.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 Object.defineProperty(obj1, "both", accessorConfigurable); 230 231 Object.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 Object.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 Object.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 Object.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 assertFalse(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 try { 289 Object.defineProperty(obj1, "foobar", dataConfigurable); 290 assertTrue(false); 291 } catch (e) { 292 assertTrue(/Cannot redefine property/.test(e)); 293 } 294 295 // Try redefine again with accessor property - shold also fail. 296 try { 297 Object.defineProperty(obj1, "foobar", dataConfigurable); 298 assertTrue(false); 299 } catch (e) { 300 assertTrue(/Cannot redefine property/.test(e)); 301 } 302 303 304 // Redifine with the same descriptor - should succeed (step 6). 305 Object.defineProperty(obj1, "foobar", dataNoConfigurable); 306 desc = Object.getOwnPropertyDescriptor(obj1, "foobar"); 307 assertEquals(obj1.foobar, 2000); 308 assertEquals(desc.value, 2000); 309 assertFalse(desc.configurable); 310 assertFalse(desc.writable); 311 assertFalse(desc.enumerable); 312 assertEquals(desc.get, undefined); 313 assertEquals(desc.set, undefined); 314 315 316 // New object 317 var obj2 = {}; 318 319 // Make accessor - redefine to data 320 Object.defineProperty(obj2, "foo", accessorConfigurable); 321 322 // Redefine to data property 323 Object.defineProperty(obj2, "foo", dataConfigurable); 324 desc = Object.getOwnPropertyDescriptor(obj2, "foo"); 325 assertEquals(obj2.foo, 1000); 326 assertEquals(desc.value, 1000); 327 assertTrue(desc.configurable); 328 assertFalse(desc.writable); 329 assertFalse(desc.enumerable); 330 assertEquals(desc.get, undefined); 331 assertEquals(desc.set, undefined); 332 333 334 // Redefine back to accessor 335 Object.defineProperty(obj2, "foo", accessorConfigurable); 336 desc = Object.getOwnPropertyDescriptor(obj2, "foo"); 337 assertTrue(desc.configurable); 338 assertFalse(desc.enumerable); 339 assertEquals(desc.writable, undefined); 340 assertEquals(desc.get, accessorConfigurable.get); 341 assertEquals(desc.set, accessorConfigurable.set); 342 assertEquals(desc.value, undefined); 343 assertEquals(1, obj2.foo = 1); 344 assertEquals(3, val1); 345 assertEquals(4, val2); 346 assertEquals(3, obj2.foo); 347 348 // Make data - redefine to accessor 349 Object.defineProperty(obj2, "bar", dataConfigurable) 350 351 // Redefine to accessor property 352 Object.defineProperty(obj2, "bar", accessorConfigurable); 353 desc = Object.getOwnPropertyDescriptor(obj2, "bar"); 354 assertTrue(desc.configurable); 355 assertFalse(desc.enumerable); 356 assertEquals(desc.writable, undefined); 357 assertEquals(desc.get, accessorConfigurable.get); 358 assertEquals(desc.set, accessorConfigurable.set); 359 assertEquals(desc.value, undefined); 360 assertEquals(1, obj2.bar = 1); 361 assertEquals(4, val1); 362 assertEquals(4, val2); 363 assertEquals(4, obj2.foo); 364 365 // Redefine back to data property 366 Object.defineProperty(obj2, "bar", dataConfigurable); 367 desc = Object.getOwnPropertyDescriptor(obj2, "bar"); 368 assertEquals(obj2.bar, 1000); 369 assertEquals(desc.value, 1000); 370 assertTrue(desc.configurable); 371 assertFalse(desc.writable); 372 assertFalse(desc.enumerable); 373 assertEquals(desc.get, undefined); 374 assertEquals(desc.set, undefined); 375 376 377 // Redefinition of an accessor defined using __defineGetter__ and 378 // __defineSetter__ 379 function get(){return this.x} 380 function set(x){this.x=x}; 381 382 var obj3 = {x:1000}; 383 obj3.__defineGetter__("foo", get); 384 obj3.__defineSetter__("foo", set); 385 386 desc = Object.getOwnPropertyDescriptor(obj3, "foo"); 387 assertTrue(desc.configurable); 388 assertTrue(desc.enumerable); 389 assertEquals(desc.writable, undefined); 390 assertEquals(desc.get, get); 391 assertEquals(desc.set, set); 392 assertEquals(desc.value, undefined); 393 assertEquals(1, obj3.foo = 1); 394 assertEquals(1, obj3.x); 395 assertEquals(1, obj3.foo); 396 397 // Redefine to accessor property (non configurable) - note that enumerable 398 // which we do not redefine should remain the same (true). 399 Object.defineProperty(obj3, "foo", accessorNoConfigurable); 400 desc = Object.getOwnPropertyDescriptor(obj3, "foo"); 401 assertFalse(desc.configurable); 402 assertTrue(desc.enumerable); 403 assertEquals(desc.writable, undefined); 404 assertEquals(desc.get, accessorNoConfigurable.get); 405 assertEquals(desc.set, accessorNoConfigurable.set); 406 assertEquals(desc.value, undefined); 407 assertEquals(1, obj3.foo = 1); 408 assertEquals(5, val2); 409 assertEquals(5, obj3.foo); 410 411 412 obj3.__defineGetter__("bar", get); 413 obj3.__defineSetter__("bar", set); 414 415 416 // Redefine back to data property 417 Object.defineProperty(obj3, "bar", dataConfigurable); 418 desc = Object.getOwnPropertyDescriptor(obj3, "bar"); 419 assertEquals(obj3.bar, 1000); 420 assertEquals(desc.value, 1000); 421 assertTrue(desc.configurable); 422 assertFalse(desc.writable); 423 assertTrue(desc.enumerable); 424 assertEquals(desc.get, undefined); 425 assertEquals(desc.set, undefined); 426 427 428 var obj4 = {}; 429 var func = function (){return 42;}; 430 obj4.bar = func; 431 assertEquals(42, obj4.bar()); 432 433 Object.defineProperty(obj4, "bar", accessorConfigurable); 434 desc = Object.getOwnPropertyDescriptor(obj4, "bar"); 435 assertTrue(desc.configurable); 436 assertTrue(desc.enumerable); 437 assertEquals(desc.writable, undefined); 438 assertEquals(desc.get, accessorConfigurable.get); 439 assertEquals(desc.set, accessorConfigurable.set); 440 assertEquals(desc.value, undefined); 441 assertEquals(1, obj4.bar = 1); 442 assertEquals(5, val1); 443 assertEquals(5, obj4.bar); 444 445 // Make sure an error is thrown when trying to access to redefined function 446 try { 447 obj4.bar(); 448 assertTrue(false); 449 } catch (e) { 450 assertTrue(/is not a function/.test(e)); 451 } 452 453 454 // Test runtime calls to DefineOrRedefineDataProperty and 455 // DefineOrRedefineAccessorProperty - make sure we don't 456 // crash 457 try { 458 %DefineOrRedefineAccessorProperty(0, 0, 0, 0, 0); 459 } catch (e) { 460 assertTrue(/illegal access/.test(e)); 461 } 462 463 try { 464 %DefineOrRedefineDataProperty(0, 0, 0, 0); 465 } catch (e) { 466 assertTrue(/illegal access/.test(e)); 467 } 468 469 try { 470 %DefineOrRedefineDataProperty(null, null, null, null); 471 } catch (e) { 472 assertTrue(/illegal access/.test(e)); 473 } 474 475 try { 476 %DefineOrRedefineAccessorProperty(null, null, null, null, null); 477 } catch (e) { 478 assertTrue(/illegal access/.test(e)); 479 } 480 481 try { 482 %DefineOrRedefineDataProperty({}, null, null, null); 483 } catch (e) { 484 assertTrue(/illegal access/.test(e)); 485 } 486 487 // Defining properties null should fail even when we have 488 // other allowed values 489 try { 490 %DefineOrRedefineAccessorProperty(null, 'foo', 0, func, 0); 491 } catch (e) { 492 assertTrue(/illegal access/.test(e)); 493 } 494 495 try { 496 %DefineOrRedefineDataProperty(null, 'foo', 0, 0); 497 } catch (e) { 498 assertTrue(/illegal access/.test(e)); 499 } 500