1 // Copyright 2011 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 // Flags: --harmony-proxies 29 30 31 // Helper. 32 33 function TestWithProxies(test, x, y, z) { 34 test(Proxy.create, x, y, z) 35 test(function(h) {return Proxy.createFunction(h, function() {})}, x, y, z) 36 } 37 38 39 40 // Getting property descriptors (Object.getOwnPropertyDescriptor). 41 42 var key 43 44 function TestGetOwnProperty(handler) { 45 TestWithProxies(TestGetOwnProperty2, handler) 46 } 47 48 function TestGetOwnProperty2(create, handler) { 49 var p = create(handler) 50 assertEquals(42, Object.getOwnPropertyDescriptor(p, "a").value) 51 assertEquals("a", key) 52 assertEquals(42, Object.getOwnPropertyDescriptor(p, 99).value) 53 assertEquals("99", key) 54 } 55 56 TestGetOwnProperty({ 57 getOwnPropertyDescriptor: function(k) { 58 key = k 59 return {value: 42, configurable: true} 60 } 61 }) 62 63 TestGetOwnProperty({ 64 getOwnPropertyDescriptor: function(k) { 65 return this.getOwnPropertyDescriptor2(k) 66 }, 67 getOwnPropertyDescriptor2: function(k) { 68 key = k 69 return {value: 42, configurable: true} 70 } 71 }) 72 73 TestGetOwnProperty({ 74 getOwnPropertyDescriptor: function(k) { 75 key = k 76 return {get value() { return 42 }, get configurable() { return true }} 77 } 78 }) 79 80 TestGetOwnProperty(Proxy.create({ 81 get: function(pr, pk) { 82 return function(k) { key = k; return {value: 42, configurable: true} } 83 } 84 })) 85 86 87 function TestGetOwnPropertyThrow(handler) { 88 TestWithProxies(TestGetOwnPropertyThrow2, handler) 89 } 90 91 function TestGetOwnPropertyThrow2(create, handler) { 92 var p = create(handler) 93 assertThrows(function(){ Object.getOwnPropertyDescriptor(p, "a") }, "myexn") 94 assertThrows(function(){ Object.getOwnPropertyDescriptor(p, 77) }, "myexn") 95 } 96 97 TestGetOwnPropertyThrow({ 98 getOwnPropertyDescriptor: function(k) { throw "myexn" } 99 }) 100 101 TestGetOwnPropertyThrow({ 102 getOwnPropertyDescriptor: function(k) { 103 return this.getPropertyDescriptor2(k) 104 }, 105 getOwnPropertyDescriptor2: function(k) { throw "myexn" } 106 }) 107 108 TestGetOwnPropertyThrow({ 109 getOwnPropertyDescriptor: function(k) { 110 return {get value() { throw "myexn" }} 111 } 112 }) 113 114 TestGetOwnPropertyThrow(Proxy.create({ 115 get: function(pr, pk) { 116 return function(k) { throw "myexn" } 117 } 118 })) 119 120 121 122 // Getters (dot, brackets). 123 124 var key 125 126 function TestGet(handler) { 127 TestWithProxies(TestGet2, handler) 128 } 129 130 function TestGet2(create, handler) { 131 var p = create(handler) 132 assertEquals(42, p.a) 133 assertEquals("a", key) 134 assertEquals(42, p["b"]) 135 assertEquals("b", key) 136 assertEquals(42, p[99]) 137 assertEquals("99", key) 138 assertEquals(42, (function(n) { return p[n] })("c")) 139 assertEquals("c", key) 140 assertEquals(42, (function(n) { return p[n] })(101)) 141 assertEquals("101", key) 142 143 var o = Object.create(p, {x: {value: 88}}) 144 assertEquals(42, o.a) 145 assertEquals("a", key) 146 assertEquals(42, o["b"]) 147 assertEquals("b", key) 148 assertEquals(42, o[99]) 149 assertEquals("99", key) 150 assertEquals(88, o.x) 151 assertEquals(88, o["x"]) 152 assertEquals(42, (function(n) { return o[n] })("c")) 153 assertEquals("c", key) 154 assertEquals(42, (function(n) { return o[n] })(101)) 155 assertEquals("101", key) 156 assertEquals(88, (function(n) { return o[n] })("x")) 157 } 158 159 TestGet({ 160 get: function(r, k) { key = k; return 42 } 161 }) 162 163 TestGet({ 164 get: function(r, k) { return this.get2(r, k) }, 165 get2: function(r, k) { key = k; return 42 } 166 }) 167 168 TestGet({ 169 getPropertyDescriptor: function(k) { key = k; return {value: 42} } 170 }) 171 172 TestGet({ 173 getPropertyDescriptor: function(k) { return this.getPropertyDescriptor2(k) }, 174 getPropertyDescriptor2: function(k) { key = k; return {value: 42} } 175 }) 176 177 TestGet({ 178 getPropertyDescriptor: function(k) { 179 key = k; 180 return {get value() { return 42 }} 181 } 182 }) 183 184 TestGet({ 185 get: undefined, 186 getPropertyDescriptor: function(k) { key = k; return {value: 42} } 187 }) 188 189 TestGet(Proxy.create({ 190 get: function(pr, pk) { 191 return function(r, k) { key = k; return 42 } 192 } 193 })) 194 195 196 function TestGetCall(handler) { 197 TestWithProxies(TestGetCall2, handler) 198 } 199 200 function TestGetCall2(create, handler) { 201 var p = create(handler) 202 assertEquals(55, p.f()) 203 assertEquals(55, p["f"]()) 204 assertEquals(55, p.f("unused", "arguments")) 205 assertEquals(55, p.f.call(p)) 206 assertEquals(55, p["f"].call(p)) 207 assertEquals(55, p[101].call(p)) 208 assertEquals(55, p.withargs(45, 5)) 209 assertEquals(55, p.withargs.call(p, 11, 22)) 210 assertEquals(55, (function(n) { return p[n]() })("f")) 211 assertEquals(55, (function(n) { return p[n].call(p) })("f")) 212 assertEquals(55, (function(n) { return p[n](15, 20) })("withargs")) 213 assertEquals(55, (function(n) { return p[n].call(p, 13, 21) })("withargs")) 214 assertEquals("6655", "66" + p) // calls p.toString 215 216 var o = Object.create(p, {g: {value: function(x) { return x + 88 }}}) 217 assertEquals(55, o.f()) 218 assertEquals(55, o["f"]()) 219 assertEquals(55, o.f("unused", "arguments")) 220 assertEquals(55, o.f.call(o)) 221 assertEquals(55, o.f.call(p)) 222 assertEquals(55, o["f"].call(p)) 223 assertEquals(55, o[101].call(p)) 224 assertEquals(55, o.withargs(45, 5)) 225 assertEquals(55, o.withargs.call(p, 11, 22)) 226 assertEquals(90, o.g(2)) 227 assertEquals(91, o.g.call(o, 3)) 228 assertEquals(92, o.g.call(p, 4)) 229 assertEquals(55, (function(n) { return o[n]() })("f")) 230 assertEquals(55, (function(n) { return o[n].call(o) })("f")) 231 assertEquals(55, (function(n) { return o[n](15, 20) })("withargs")) 232 assertEquals(55, (function(n) { return o[n].call(o, 13, 21) })("withargs")) 233 assertEquals(93, (function(n) { return o[n](5) })("g")) 234 assertEquals(94, (function(n) { return o[n].call(o, 6) })("g")) 235 assertEquals(95, (function(n) { return o[n].call(p, 7) })("g")) 236 assertEquals("6655", "66" + o) // calls o.toString 237 } 238 239 TestGetCall({ 240 get: function(r, k) { return function() { return 55 } } 241 }) 242 243 TestGetCall({ 244 get: function(r, k) { return this.get2(r, k) }, 245 get2: function(r, k) { return function() { return 55 } } 246 }) 247 248 TestGetCall({ 249 getPropertyDescriptor: function(k) { 250 return {value: function() { return 55 }} 251 } 252 }) 253 254 TestGetCall({ 255 getPropertyDescriptor: function(k) { return this.getPropertyDescriptor2(k) }, 256 getPropertyDescriptor2: function(k) { 257 return {value: function() { return 55 }} 258 } 259 }) 260 261 TestGetCall({ 262 getPropertyDescriptor: function(k) { 263 return {get value() { return function() { return 55 } }} 264 } 265 }) 266 267 TestGetCall({ 268 get: undefined, 269 getPropertyDescriptor: function(k) { 270 return {value: function() { return 55 }} 271 } 272 }) 273 274 TestGetCall({ 275 get: function(r, k) { 276 if (k == "gg") { 277 return function() { return 55 } 278 } else if (k == "withargs") { 279 return function(n, m) { return n + m * 2 } 280 } else { 281 return function() { return this.gg() } 282 } 283 } 284 }) 285 286 TestGetCall(Proxy.create({ 287 get: function(pr, pk) { 288 return function(r, k) { return function() { return 55 } } 289 } 290 })) 291 292 293 function TestGetThrow(handler) { 294 TestWithProxies(TestGetThrow2, handler) 295 } 296 297 function TestGetThrow2(create, handler) { 298 var p = create(handler) 299 assertThrows(function(){ p.a }, "myexn") 300 assertThrows(function(){ p["b"] }, "myexn") 301 assertThrows(function(){ p[3] }, "myexn") 302 assertThrows(function(){ (function(n) { p[n] })("c") }, "myexn") 303 assertThrows(function(){ (function(n) { p[n] })(99) }, "myexn") 304 305 var o = Object.create(p, {x: {value: 88}, '4': {value: 89}}) 306 assertThrows(function(){ o.a }, "myexn") 307 assertThrows(function(){ o["b"] }, "myexn") 308 assertThrows(function(){ o[3] }, "myexn") 309 assertThrows(function(){ (function(n) { o[n] })("c") }, "myexn") 310 assertThrows(function(){ (function(n) { o[n] })(99) }, "myexn") 311 } 312 313 TestGetThrow({ 314 get: function(r, k) { throw "myexn" } 315 }) 316 317 TestGetThrow({ 318 get: function(r, k) { return this.get2(r, k) }, 319 get2: function(r, k) { throw "myexn" } 320 }) 321 322 TestGetThrow({ 323 getPropertyDescriptor: function(k) { throw "myexn" } 324 }) 325 326 TestGetThrow({ 327 getPropertyDescriptor: function(k) { return this.getPropertyDescriptor2(k) }, 328 getPropertyDescriptor2: function(k) { throw "myexn" } 329 }) 330 331 TestGetThrow({ 332 getPropertyDescriptor: function(k) { 333 return {get value() { throw "myexn" }} 334 } 335 }) 336 337 TestGetThrow({ 338 get: undefined, 339 getPropertyDescriptor: function(k) { throw "myexn" } 340 }) 341 342 TestGetThrow(Proxy.create({ 343 get: function(pr, pk) { throw "myexn" } 344 })) 345 346 TestGetThrow(Proxy.create({ 347 get: function(pr, pk) { 348 return function(r, k) { throw "myexn" } 349 } 350 })) 351 352 353 354 // Setters. 355 356 var key 357 var val 358 359 function TestSet(handler) { 360 TestWithProxies(TestSet2, handler) 361 } 362 363 function TestSet2(create, handler) { 364 var p = create(handler) 365 assertEquals(42, p.a = 42) 366 assertEquals("a", key) 367 assertEquals(42, val) 368 assertEquals(43, p["b"] = 43) 369 assertEquals("b", key) 370 assertEquals(43, val) 371 assertEquals(44, p[77] = 44) 372 assertEquals("77", key) 373 assertEquals(44, val) 374 375 assertEquals(45, (function(n) { return p[n] = 45 })("c")) 376 assertEquals("c", key) 377 assertEquals(45, val) 378 assertEquals(46, (function(n) { return p[n] = 46 })(99)) 379 assertEquals("99", key) 380 assertEquals(46, val) 381 } 382 383 TestSet({ 384 set: function(r, k, v) { key = k; val = v; return true } 385 }) 386 387 TestSet({ 388 set: function(r, k, v) { return this.set2(r, k, v) }, 389 set2: function(r, k, v) { key = k; val = v; return true } 390 }) 391 392 TestSet({ 393 getOwnPropertyDescriptor: function(k) { return {writable: true} }, 394 defineProperty: function(k, desc) { key = k; val = desc.value } 395 }) 396 397 TestSet({ 398 getOwnPropertyDescriptor: function(k) { 399 return this.getOwnPropertyDescriptor2(k) 400 }, 401 getOwnPropertyDescriptor2: function(k) { return {writable: true} }, 402 defineProperty: function(k, desc) { this.defineProperty2(k, desc) }, 403 defineProperty2: function(k, desc) { key = k; val = desc.value } 404 }) 405 406 TestSet({ 407 getOwnPropertyDescriptor: function(k) { 408 return {get writable() { return true }} 409 }, 410 defineProperty: function(k, desc) { key = k; val = desc.value } 411 }) 412 413 TestSet({ 414 getOwnPropertyDescriptor: function(k) { 415 return {set: function(v) { key = k; val = v }} 416 } 417 }) 418 419 TestSet({ 420 getOwnPropertyDescriptor: function(k) { return null }, 421 getPropertyDescriptor: function(k) { return {writable: true} }, 422 defineProperty: function(k, desc) { key = k; val = desc.value } 423 }) 424 425 TestSet({ 426 getOwnPropertyDescriptor: function(k) { return null }, 427 getPropertyDescriptor: function(k) { 428 return {get writable() { return true }} 429 }, 430 defineProperty: function(k, desc) { key = k; val = desc.value } 431 }) 432 433 TestSet({ 434 getOwnPropertyDescriptor: function(k) { return null }, 435 getPropertyDescriptor: function(k) { 436 return {set: function(v) { key = k; val = v }} 437 } 438 }) 439 440 TestSet({ 441 getOwnPropertyDescriptor: function(k) { return null }, 442 getPropertyDescriptor: function(k) { return null }, 443 defineProperty: function(k, desc) { key = k, val = desc.value } 444 }) 445 446 TestSet(Proxy.create({ 447 get: function(pr, pk) { 448 return function(r, k, v) { key = k; val = v; return true } 449 } 450 })) 451 452 453 function TestSetThrow(handler) { 454 TestWithProxies(TestSetThrow2, handler) 455 } 456 457 function TestSetThrow2(create, handler) { 458 var p = create(handler) 459 assertThrows(function(){ p.a = 42 }, "myexn") 460 assertThrows(function(){ p["b"] = 42 }, "myexn") 461 assertThrows(function(){ p[22] = 42 }, "myexn") 462 assertThrows(function(){ (function(n) { p[n] = 45 })("c") }, "myexn") 463 assertThrows(function(){ (function(n) { p[n] = 46 })(99) }, "myexn") 464 } 465 466 TestSetThrow({ 467 set: function(r, k, v) { throw "myexn" } 468 }) 469 470 TestSetThrow({ 471 set: function(r, k, v) { return this.set2(r, k, v) }, 472 set2: function(r, k, v) { throw "myexn" } 473 }) 474 475 TestSetThrow({ 476 getOwnPropertyDescriptor: function(k) { throw "myexn" }, 477 defineProperty: function(k, desc) { key = k; val = desc.value } 478 }) 479 480 TestSetThrow({ 481 getOwnPropertyDescriptor: function(k) { return {writable: true} }, 482 defineProperty: function(k, desc) { throw "myexn" } 483 }) 484 485 TestSetThrow({ 486 getOwnPropertyDescriptor: function(k) { 487 return this.getOwnPropertyDescriptor2(k) 488 }, 489 getOwnPropertyDescriptor2: function(k) { throw "myexn" }, 490 defineProperty: function(k, desc) { this.defineProperty2(k, desc) }, 491 defineProperty2: function(k, desc) { key = k; val = desc.value } 492 }) 493 494 TestSetThrow({ 495 getOwnPropertyDescriptor: function(k) { 496 return this.getOwnPropertyDescriptor2(k) 497 }, 498 getOwnPropertyDescriptor2: function(k) { return {writable: true} }, 499 defineProperty: function(k, desc) { this.defineProperty2(k, desc) }, 500 defineProperty2: function(k, desc) { throw "myexn" } 501 }) 502 503 TestSetThrow({ 504 getOwnPropertyDescriptor: function(k) { throw "myexn" }, 505 defineProperty: function(k, desc) { key = k; val = desc.value } 506 }) 507 508 TestSetThrow({ 509 getOwnPropertyDescriptor: function(k) { 510 return {get writable() { return true }} 511 }, 512 defineProperty: function(k, desc) { throw "myexn" } 513 }) 514 515 TestSetThrow({ 516 getOwnPropertyDescriptor: function(k) { throw "myexn" } 517 }) 518 519 TestSetThrow({ 520 getOwnPropertyDescriptor: function(k) { 521 return {set: function(v) { throw "myexn" }} 522 } 523 }) 524 525 TestSetThrow({ 526 getOwnPropertyDescriptor: function(k) { throw "myexn" }, 527 getPropertyDescriptor: function(k) { return {writable: true} }, 528 defineProperty: function(k, desc) { key = k; val = desc.value } 529 }) 530 531 TestSetThrow({ 532 getOwnPropertyDescriptor: function(k) { return null }, 533 getPropertyDescriptor: function(k) { throw "myexn" }, 534 defineProperty: function(k, desc) { key = k; val = desc.value } 535 }) 536 537 TestSetThrow({ 538 getOwnPropertyDescriptor: function(k) { return null }, 539 getPropertyDescriptor: function(k) { return {writable: true} }, 540 defineProperty: function(k, desc) { throw "myexn" } 541 }) 542 543 TestSetThrow({ 544 getOwnPropertyDescriptor: function(k) { return null }, 545 getPropertyDescriptor: function(k) { 546 return {get writable() { throw "myexn" }} 547 }, 548 defineProperty: function(k, desc) { key = k; val = desc.value } 549 }) 550 551 TestSetThrow({ 552 getOwnPropertyDescriptor: function(k) { return null }, 553 getPropertyDescriptor: function(k) { 554 return {set: function(v) { throw "myexn" }} 555 } 556 }) 557 558 TestSetThrow({ 559 getOwnPropertyDescriptor: function(k) { return null }, 560 getPropertyDescriptor: function(k) { return null }, 561 defineProperty: function(k, desc) { throw "myexn" } 562 }) 563 564 TestSetThrow(Proxy.create({ 565 get: function(pr, pk) { throw "myexn" } 566 })) 567 568 TestSetThrow(Proxy.create({ 569 get: function(pr, pk) { 570 return function(r, k, v) { throw "myexn" } 571 } 572 })) 573 574 575 var rec 576 var key 577 var val 578 579 function TestSetForDerived(trap) { 580 TestWithProxies(TestSetForDerived2, trap) 581 } 582 583 function TestSetForDerived2(create, trap) { 584 var p = create({getPropertyDescriptor: trap, getOwnPropertyDescriptor: trap}) 585 var o = Object.create(p, {x: {value: 88, writable: true}, 586 '1': {value: 89, writable: true}}) 587 588 key = "" 589 assertEquals(48, o.x = 48) 590 assertEquals("", key) // trap not invoked 591 assertEquals(48, o.x) 592 593 assertEquals(47, o[1] = 47) 594 assertEquals("", key) // trap not invoked 595 assertEquals(47, o[1]) 596 597 assertEquals(49, o.y = 49) 598 assertEquals("y", key) 599 assertEquals(49, o.y) 600 601 assertEquals(50, o[2] = 50) 602 assertEquals("2", key) 603 assertEquals(50, o[2]) 604 605 assertEquals(44, o.p_writable = 44) 606 assertEquals("p_writable", key) 607 assertEquals(44, o.p_writable) 608 609 assertEquals(45, o.p_nonwritable = 45) 610 assertEquals("p_nonwritable", key) 611 assertFalse(Object.prototype.hasOwnProperty.call(o, "p_nonwritable")) 612 613 assertThrows(function(){ "use strict"; o.p_nonwritable = 45 }, TypeError) 614 assertEquals("p_nonwritable", key) 615 assertFalse(Object.prototype.hasOwnProperty.call(o, "p_nonwritable")) 616 617 val = "" 618 assertEquals(46, o.p_setter = 46) 619 assertEquals("p_setter", key) 620 assertSame(o, rec) 621 assertEquals(46, val) // written to parent 622 assertFalse(Object.prototype.hasOwnProperty.call(o, "p_setter")) 623 624 val = "" 625 assertEquals(47, o.p_nosetter = 47) 626 assertEquals("p_nosetter", key) 627 assertEquals("", val) // not written at all 628 assertFalse(Object.prototype.hasOwnProperty.call(o, "p_nosetter")); 629 630 key = "" 631 assertThrows(function(){ "use strict"; o.p_nosetter = 50 }, TypeError) 632 assertEquals("p_nosetter", key) 633 assertEquals("", val) // not written at all 634 assertFalse(Object.prototype.hasOwnProperty.call(o, "p_nosetter")); 635 636 assertThrows(function(){ o.p_nonconf = 53 }, TypeError) 637 assertEquals("p_nonconf", key) 638 assertFalse(Object.prototype.hasOwnProperty.call(o, "p_nonconf")); 639 640 assertThrows(function(){ o.p_throw = 51 }, "myexn") 641 assertEquals("p_throw", key) 642 assertFalse(Object.prototype.hasOwnProperty.call(o, "p_throw")); 643 644 assertThrows(function(){ o.p_setterthrow = 52 }, "myexn") 645 assertEquals("p_setterthrow", key) 646 assertFalse(Object.prototype.hasOwnProperty.call(o, "p_setterthrow")); 647 } 648 649 650 TestSetForDerived( 651 function(k) { 652 // TODO(yangguo): issue 2398 - throwing an error causes formatting of 653 // the message string, which can be observable through this handler. 654 // We ignore keys that occur when formatting the message string. 655 if (k == "toString" || k == "valueOf") return; 656 657 key = k; 658 switch (k) { 659 case "p_writable": return {writable: true, configurable: true} 660 case "p_nonwritable": return {writable: false, configurable: true} 661 case "p_setter": return { 662 set: function(x) { rec = this; val = x }, 663 configurable: true 664 } 665 case "p_nosetter": return { 666 get: function() { return 1 }, 667 configurable: true 668 } 669 case "p_nonconf": return {} 670 case "p_throw": throw "myexn" 671 case "p_setterthrow": return {set: function(x) { throw "myexn" }} 672 default: return undefined 673 } 674 } 675 ) 676 677 678 // Evil proxy-induced side-effects shouldn't crash. 679 // TODO(rossberg): proper behaviour isn't really spec'ed yet, so ignore results. 680 681 TestWithProxies(function(create) { 682 var calls = 0 683 var handler = { 684 getPropertyDescriptor: function() { 685 ++calls 686 return (calls % 2 == 1) 687 ? {get: function() { return 5 }, configurable: true} 688 : {set: function() { return false }, configurable: true} 689 } 690 } 691 var p = create(handler) 692 var o = Object.create(p) 693 // Make proxy prototype property read-only after CanPut check. 694 try { o.x = 4 } catch (e) { assertInstanceof(e, Error) } 695 }) 696 697 TestWithProxies(function(create) { 698 var handler = { 699 getPropertyDescriptor: function() { 700 Object.defineProperty(o, "x", {get: function() { return 5 }}); 701 return {set: function() {}} 702 } 703 } 704 var p = create(handler) 705 var o = Object.create(p) 706 // Make object property read-only after CanPut check. 707 try { o.x = 4 } catch (e) { assertInstanceof(e, Error) } 708 }) 709 710 711 712 // TODO(rossberg): TestSetReject, returning false 713 // TODO(rossberg): TestGetProperty, TestSetProperty 714 715 716 717 // Property definition (Object.defineProperty and Object.defineProperties). 718 719 var key 720 var desc 721 722 function TestDefine(handler) { 723 TestWithProxies(TestDefine2, handler) 724 } 725 726 function TestDefine2(create, handler) { 727 var p = create(handler) 728 assertEquals(p, Object.defineProperty(p, "a", {value: 44})) 729 assertEquals("a", key) 730 assertEquals(1, Object.getOwnPropertyNames(desc).length) 731 assertEquals(44, desc.value) 732 733 assertEquals(p, Object.defineProperty(p, "b", {value: 45, writable: false})) 734 assertEquals("b", key) 735 assertEquals(2, Object.getOwnPropertyNames(desc).length) 736 assertEquals(45, desc.value) 737 assertEquals(false, desc.writable) 738 739 assertEquals(p, Object.defineProperty(p, "c", {value: 46, enumerable: false})) 740 assertEquals("c", key) 741 assertEquals(2, Object.getOwnPropertyNames(desc).length) 742 assertEquals(46, desc.value) 743 assertEquals(false, desc.enumerable) 744 745 assertEquals(p, Object.defineProperty(p, 101, {value: 47, enumerable: false})) 746 assertEquals("101", key) 747 assertEquals(2, Object.getOwnPropertyNames(desc).length) 748 assertEquals(47, desc.value) 749 assertEquals(false, desc.enumerable) 750 751 var attributes = {configurable: true, mine: 66, minetoo: 23} 752 assertEquals(p, Object.defineProperty(p, "d", attributes)) 753 assertEquals("d", key) 754 // Modifying the attributes object after the fact should have no effect. 755 attributes.configurable = false 756 attributes.mine = 77 757 delete attributes.minetoo 758 assertEquals(3, Object.getOwnPropertyNames(desc).length) 759 assertEquals(true, desc.configurable) 760 assertEquals(66, desc.mine) 761 assertEquals(23, desc.minetoo) 762 763 assertEquals(p, Object.defineProperty(p, "e", {get: function(){ return 5 }})) 764 assertEquals("e", key) 765 assertEquals(1, Object.getOwnPropertyNames(desc).length) 766 assertEquals(5, desc.get()) 767 768 assertEquals(p, Object.defineProperty(p, "zzz", {})) 769 assertEquals("zzz", key) 770 assertEquals(0, Object.getOwnPropertyNames(desc).length) 771 772 var d = create({ 773 get: function(r, k) { return (k === "value") ? 77 : void 0 }, 774 getOwnPropertyNames: function() { return ["value"] }, 775 enumerate: function() { return ["value"] } 776 }) 777 assertEquals(1, Object.getOwnPropertyNames(d).length) 778 assertEquals(77, d.value) 779 assertEquals(p, Object.defineProperty(p, "p", d)) 780 assertEquals("p", key) 781 assertEquals(1, Object.getOwnPropertyNames(desc).length) 782 assertEquals(77, desc.value) 783 784 var props = { 785 '11': {}, 786 blub: {get: function() { return true }}, 787 '': {get value() { return 20 }}, 788 last: {value: 21, configurable: true, mine: "eyes"} 789 } 790 Object.defineProperty(props, "hidden", {value: "hidden", enumerable: false}) 791 assertEquals(p, Object.defineProperties(p, props)) 792 assertEquals("last", key) 793 assertEquals(2, Object.getOwnPropertyNames(desc).length) 794 assertEquals(21, desc.value) 795 assertEquals(true, desc.configurable) 796 assertEquals(undefined, desc.mine) // Arguably a bug in the spec... 797 798 var props = {bla: {get value() { throw "myexn" }}} 799 assertThrows(function(){ Object.defineProperties(p, props) }, "myexn") 800 } 801 802 TestDefine({ 803 defineProperty: function(k, d) { key = k; desc = d; return true } 804 }) 805 806 TestDefine({ 807 defineProperty: function(k, d) { return this.defineProperty2(k, d) }, 808 defineProperty2: function(k, d) { key = k; desc = d; return true } 809 }) 810 811 TestDefine(Proxy.create({ 812 get: function(pr, pk) { 813 return function(k, d) { key = k; desc = d; return true } 814 } 815 })) 816 817 818 function TestDefineThrow(handler) { 819 TestWithProxies(TestDefineThrow2, handler) 820 } 821 822 function TestDefineThrow2(create, handler) { 823 var p = create(handler) 824 assertThrows(function(){ Object.defineProperty(p, "a", {value: 44})}, "myexn") 825 assertThrows(function(){ Object.defineProperty(p, 0, {value: 44})}, "myexn") 826 827 var d1 = create({ 828 get: function(r, k) { throw "myexn" }, 829 getOwnPropertyNames: function() { return ["value"] } 830 }) 831 assertThrows(function(){ Object.defineProperty(p, "p", d1) }, "myexn") 832 var d2 = create({ 833 get: function(r, k) { return 77 }, 834 getOwnPropertyNames: function() { throw "myexn" } 835 }) 836 assertThrows(function(){ Object.defineProperty(p, "p", d2) }, "myexn") 837 838 var props = {bla: {get value() { throw "otherexn" }}} 839 assertThrows(function(){ Object.defineProperties(p, props) }, "otherexn") 840 } 841 842 TestDefineThrow({ 843 defineProperty: function(k, d) { throw "myexn" } 844 }) 845 846 TestDefineThrow({ 847 defineProperty: function(k, d) { return this.defineProperty2(k, d) }, 848 defineProperty2: function(k, d) { throw "myexn" } 849 }) 850 851 TestDefineThrow(Proxy.create({ 852 get: function(pr, pk) { throw "myexn" } 853 })) 854 855 TestDefineThrow(Proxy.create({ 856 get: function(pr, pk) { 857 return function(k, d) { throw "myexn" } 858 } 859 })) 860 861 862 863 // Property deletion (delete). 864 865 var key 866 867 function TestDelete(handler) { 868 TestWithProxies(TestDelete2, handler) 869 } 870 871 function TestDelete2(create, handler) { 872 var p = create(handler) 873 assertEquals(true, delete p.a) 874 assertEquals("a", key) 875 assertEquals(true, delete p["b"]) 876 assertEquals("b", key) 877 assertEquals(true, delete p[1]) 878 assertEquals("1", key) 879 880 assertEquals(false, delete p.z1) 881 assertEquals("z1", key) 882 assertEquals(false, delete p["z2"]) 883 assertEquals("z2", key); 884 885 (function() { 886 "use strict" 887 assertEquals(true, delete p.c) 888 assertEquals("c", key) 889 assertEquals(true, delete p["d"]) 890 assertEquals("d", key) 891 assertEquals(true, delete p[2]) 892 assertEquals("2", key) 893 894 assertThrows(function(){ delete p.z3 }, TypeError) 895 assertEquals("z3", key) 896 assertThrows(function(){ delete p["z4"] }, TypeError) 897 assertEquals("z4", key) 898 })() 899 } 900 901 TestDelete({ 902 delete: function(k) { key = k; return k < "z" } 903 }) 904 905 TestDelete({ 906 delete: function(k) { return this.delete2(k) }, 907 delete2: function(k) { key = k; return k < "z" } 908 }) 909 910 TestDelete(Proxy.create({ 911 get: function(pr, pk) { 912 return function(k) { key = k; return k < "z" } 913 } 914 })) 915 916 917 function TestDeleteThrow(handler) { 918 TestWithProxies(TestDeleteThrow2, handler) 919 } 920 921 function TestDeleteThrow2(create, handler) { 922 var p = create(handler) 923 assertThrows(function(){ delete p.a }, "myexn") 924 assertThrows(function(){ delete p["b"] }, "myexn"); 925 assertThrows(function(){ delete p[3] }, "myexn"); 926 927 (function() { 928 "use strict" 929 assertThrows(function(){ delete p.c }, "myexn") 930 assertThrows(function(){ delete p["d"] }, "myexn") 931 assertThrows(function(){ delete p[4] }, "myexn"); 932 })() 933 } 934 935 TestDeleteThrow({ 936 delete: function(k) { throw "myexn" } 937 }) 938 939 TestDeleteThrow({ 940 delete: function(k) { return this.delete2(k) }, 941 delete2: function(k) { throw "myexn" } 942 }) 943 944 TestDeleteThrow(Proxy.create({ 945 get: function(pr, pk) { throw "myexn" } 946 })) 947 948 TestDeleteThrow(Proxy.create({ 949 get: function(pr, pk) { 950 return function(k) { throw "myexn" } 951 } 952 })) 953 954 955 956 // Property descriptors (Object.getOwnPropertyDescriptor). 957 958 function TestDescriptor(handler) { 959 TestWithProxies(TestDescriptor2, handler) 960 } 961 962 function TestDescriptor2(create, handler) { 963 var p = create(handler) 964 var descs = [ 965 {configurable: true}, 966 {value: 34, enumerable: true, configurable: true}, 967 {value: 3, writable: false, mine: "eyes", configurable: true}, 968 {get value() { return 20 }, get configurable() { return true }}, 969 {get: function() { "get" }, set: function() { "set" }, configurable: true} 970 ] 971 for (var i = 0; i < descs.length; ++i) { 972 assertEquals(p, Object.defineProperty(p, i, descs[i])) 973 var desc = Object.getOwnPropertyDescriptor(p, i) 974 for (prop in descs[i]) { 975 // TODO(rossberg): Ignore user attributes as long as the spec isn't 976 // fixed suitably. 977 if (prop != "mine") assertEquals(descs[i][prop], desc[prop]) 978 } 979 assertEquals(undefined, Object.getOwnPropertyDescriptor(p, "absent")) 980 } 981 } 982 983 TestDescriptor({ 984 defineProperty: function(k, d) { this["__" + k] = d; return true }, 985 getOwnPropertyDescriptor: function(k) { return this["__" + k] } 986 }) 987 988 TestDescriptor({ 989 defineProperty: function(k, d) { this["__" + k] = d; return true }, 990 getOwnPropertyDescriptor: function(k) { 991 return this.getOwnPropertyDescriptor2(k) 992 }, 993 getOwnPropertyDescriptor2: function(k) { return this["__" + k] } 994 }) 995 996 997 function TestDescriptorThrow(handler) { 998 TestWithProxies(TestDescriptorThrow2, handler) 999 } 1000 1001 function TestDescriptorThrow2(create, handler) { 1002 var p = create(handler) 1003 assertThrows(function(){ Object.getOwnPropertyDescriptor(p, "a") }, "myexn") 1004 } 1005 1006 TestDescriptorThrow({ 1007 getOwnPropertyDescriptor: function(k) { throw "myexn" } 1008 }) 1009 1010 TestDescriptorThrow({ 1011 getOwnPropertyDescriptor: function(k) { 1012 return this.getOwnPropertyDescriptor2(k) 1013 }, 1014 getOwnPropertyDescriptor2: function(k) { throw "myexn" } 1015 }) 1016 1017 1018 1019 // Comparison. 1020 1021 function TestComparison(eq) { 1022 TestWithProxies(TestComparison2, eq) 1023 } 1024 1025 function TestComparison2(create, eq) { 1026 var p1 = create({}) 1027 var p2 = create({}) 1028 1029 assertTrue(eq(p1, p1)) 1030 assertTrue(eq(p2, p2)) 1031 assertTrue(!eq(p1, p2)) 1032 assertTrue(!eq(p1, {})) 1033 assertTrue(!eq({}, p2)) 1034 assertTrue(!eq({}, {})) 1035 } 1036 1037 TestComparison(function(o1, o2) { return o1 == o2 }) 1038 TestComparison(function(o1, o2) { return o1 === o2 }) 1039 TestComparison(function(o1, o2) { return !(o1 != o2) }) 1040 TestComparison(function(o1, o2) { return !(o1 !== o2) }) 1041 1042 1043 1044 // Type (typeof). 1045 1046 function TestTypeof() { 1047 assertEquals("object", typeof Proxy.create({})) 1048 assertTrue(typeof Proxy.create({}) == "object") 1049 assertTrue("object" == typeof Proxy.create({})) 1050 1051 assertEquals("function", typeof Proxy.createFunction({}, function() {})) 1052 assertTrue(typeof Proxy.createFunction({}, function() {}) == "function") 1053 assertTrue("function" == typeof Proxy.createFunction({}, function() {})) 1054 } 1055 1056 TestTypeof() 1057 1058 1059 1060 // Membership test (in). 1061 1062 var key 1063 1064 function TestIn(handler) { 1065 TestWithProxies(TestIn2, handler) 1066 } 1067 1068 function TestIn2(create, handler) { 1069 var p = create(handler) 1070 assertTrue("a" in p) 1071 assertEquals("a", key) 1072 assertTrue(99 in p) 1073 assertEquals("99", key) 1074 assertFalse("z" in p) 1075 assertEquals("z", key) 1076 1077 assertEquals(2, ("a" in p) ? 2 : 0) 1078 assertEquals(0, !("a" in p) ? 2 : 0) 1079 assertEquals(0, ("zzz" in p) ? 2 : 0) 1080 assertEquals(2, !("zzz" in p) ? 2 : 0) 1081 1082 // Test compilation in conditionals. 1083 if ("b" in p) { 1084 } else { 1085 assertTrue(false) 1086 } 1087 assertEquals("b", key) 1088 1089 if ("zz" in p) { 1090 assertTrue(false) 1091 } 1092 assertEquals("zz", key) 1093 1094 if (!("c" in p)) { 1095 assertTrue(false) 1096 } 1097 assertEquals("c", key) 1098 1099 if (!("zzz" in p)) { 1100 } else { 1101 assertTrue(false) 1102 } 1103 assertEquals("zzz", key) 1104 } 1105 1106 TestIn({ 1107 has: function(k) { key = k; return k < "z" } 1108 }) 1109 1110 TestIn({ 1111 has: function(k) { return this.has2(k) }, 1112 has2: function(k) { key = k; return k < "z" } 1113 }) 1114 1115 TestIn({ 1116 getPropertyDescriptor: function(k) { 1117 key = k; return k < "z" ? {value: 42} : void 0 1118 } 1119 }) 1120 1121 TestIn({ 1122 getPropertyDescriptor: function(k) { return this.getPropertyDescriptor2(k) }, 1123 getPropertyDescriptor2: function(k) { 1124 key = k; return k < "z" ? {value: 42} : void 0 1125 } 1126 }) 1127 1128 TestIn({ 1129 getPropertyDescriptor: function(k) { 1130 key = k; return k < "z" ? {get value() { return 42 }} : void 0 1131 } 1132 }) 1133 1134 TestIn({ 1135 has: undefined, 1136 getPropertyDescriptor: function(k) { 1137 key = k; return k < "z" ? {value: 42} : void 0 1138 } 1139 }) 1140 1141 TestIn(Proxy.create({ 1142 get: function(pr, pk) { 1143 return function(k) { key = k; return k < "z" } 1144 } 1145 })) 1146 1147 1148 function TestInThrow(handler) { 1149 TestWithProxies(TestInThrow2, handler) 1150 } 1151 1152 function TestInThrow2(create, handler) { 1153 var p = create(handler) 1154 assertThrows(function(){ return "a" in o }, "myexn") 1155 assertThrows(function(){ return 99 in o }, "myexn") 1156 assertThrows(function(){ return !("a" in o) }, "myexn") 1157 assertThrows(function(){ return ("a" in o) ? 2 : 3 }, "myexn") 1158 assertThrows(function(){ if ("b" in o) {} }, "myexn") 1159 assertThrows(function(){ if (!("b" in o)) {} }, "myexn") 1160 assertThrows(function(){ if ("zzz" in o) {} }, "myexn") 1161 } 1162 1163 TestInThrow({ 1164 has: function(k) { throw "myexn" } 1165 }) 1166 1167 TestInThrow({ 1168 has: function(k) { return this.has2(k) }, 1169 has2: function(k) { throw "myexn" } 1170 }) 1171 1172 TestInThrow({ 1173 getPropertyDescriptor: function(k) { throw "myexn" } 1174 }) 1175 1176 TestInThrow({ 1177 getPropertyDescriptor: function(k) { return this.getPropertyDescriptor2(k) }, 1178 getPropertyDescriptor2: function(k) { throw "myexn" } 1179 }) 1180 1181 TestInThrow({ 1182 has: undefined, 1183 getPropertyDescriptor: function(k) { throw "myexn" } 1184 }) 1185 1186 TestInThrow(Proxy.create({ 1187 get: function(pr, pk) { throw "myexn" } 1188 })) 1189 1190 TestInThrow(Proxy.create({ 1191 get: function(pr, pk) { 1192 return function(k) { throw "myexn" } 1193 } 1194 })) 1195 1196 1197 function TestInForDerived(handler) { 1198 TestWithProxies(TestInForDerived2, handler) 1199 } 1200 1201 function TestInForDerived2(create, handler) { 1202 var p = create(handler) 1203 var o = Object.create(p) 1204 1205 assertTrue("a" in o) 1206 assertEquals("a", key) 1207 assertTrue(99 in o) 1208 assertEquals("99", key) 1209 assertFalse("z" in o) 1210 assertEquals("z", key) 1211 1212 assertEquals(2, ("a" in o) ? 2 : 0) 1213 assertEquals(0, !("a" in o) ? 2 : 0) 1214 assertEquals(0, ("zzz" in o) ? 2 : 0) 1215 assertEquals(2, !("zzz" in o) ? 2 : 0) 1216 1217 if ("b" in o) { 1218 } else { 1219 assertTrue(false) 1220 } 1221 assertEquals("b", key) 1222 1223 if ("zz" in o) { 1224 assertTrue(false) 1225 } 1226 assertEquals("zz", key) 1227 1228 if (!("c" in o)) { 1229 assertTrue(false) 1230 } 1231 assertEquals("c", key) 1232 1233 if (!("zzz" in o)) { 1234 } else { 1235 assertTrue(false) 1236 } 1237 assertEquals("zzz", key) 1238 } 1239 1240 TestInForDerived({ 1241 getPropertyDescriptor: function(k) { 1242 key = k; return k < "z" ? {value: 42, configurable: true} : void 0 1243 } 1244 }) 1245 1246 TestInForDerived({ 1247 getPropertyDescriptor: function(k) { return this.getPropertyDescriptor2(k) }, 1248 getPropertyDescriptor2: function(k) { 1249 key = k; return k < "z" ? {value: 42, configurable: true} : void 0 1250 } 1251 }) 1252 1253 TestInForDerived({ 1254 getPropertyDescriptor: function(k) { 1255 key = k; 1256 return k < "z" ? {get value() { return 42 }, configurable: true} : void 0 1257 } 1258 }) 1259 1260 /* TODO(rossberg): this will work once we implement the newest proposal 1261 * regarding default traps for getPropertyDescriptor. 1262 TestInForDerived({ 1263 getOwnPropertyDescriptor: function(k) { 1264 key = k; return k < "z" ? {value: 42, configurable: true} : void 0 1265 } 1266 }) 1267 1268 TestInForDerived({ 1269 getOwnPropertyDescriptor: function(k) { 1270 return this.getOwnPropertyDescriptor2(k) 1271 }, 1272 getOwnPropertyDescriptor2: function(k) { 1273 key = k; return k < "z" ? {value: 42, configurable: true} : void 0 1274 } 1275 }) 1276 1277 TestInForDerived({ 1278 getOwnPropertyDescriptor: function(k) { 1279 key = k; 1280 return k < "z" ? {get value() { return 42 }, configurable: true} : void 0 1281 } 1282 }) 1283 */ 1284 1285 TestInForDerived(Proxy.create({ 1286 get: function(pr, pk) { 1287 return function(k) { 1288 key = k; return k < "z" ? {value: 42, configurable: true} : void 0 1289 } 1290 } 1291 })) 1292 1293 1294 1295 // Property descriptor conversion. 1296 1297 var descget 1298 1299 function TestDescriptorGetOrder(handler) { 1300 var p = Proxy.create(handler) 1301 var o = Object.create(p, {b: {value: 0}}) 1302 TestDescriptorGetOrder2(function(n) { return p[n] }, "vV") 1303 TestDescriptorGetOrder2(function(n) { return n in p }, "") 1304 TestDescriptorGetOrder2(function(n) { return o[n] }, "vV") 1305 TestDescriptorGetOrder2(function(n) { return n in o }, "eEcCvVwWgs") 1306 } 1307 1308 function TestDescriptorGetOrder2(f, access) { 1309 descget = "" 1310 assertTrue(f("a")) 1311 assertEquals(access, descget) 1312 descget = "" 1313 assertTrue(f(99)) 1314 assertEquals(access, descget) 1315 descget = "" 1316 assertFalse(!!f("z")) 1317 assertEquals("", descget) 1318 } 1319 1320 TestDescriptorGetOrder({ 1321 getPropertyDescriptor: function(k) { 1322 if (k >= "z") return void 0 1323 // Return a proxy as property descriptor, so that we can log accesses. 1324 return Proxy.create({ 1325 get: function(r, attr) { 1326 descget += attr[0].toUpperCase() 1327 return true 1328 }, 1329 has: function(attr) { 1330 descget += attr[0] 1331 switch (attr) { 1332 case "writable": 1333 case "enumerable": 1334 case "configurable": 1335 case "value": 1336 return true 1337 case "get": 1338 case "set": 1339 return false 1340 default: 1341 assertUnreachable() 1342 } 1343 } 1344 }) 1345 } 1346 }) 1347 1348 1349 1350 // Own Properties (Object.prototype.hasOwnProperty). 1351 1352 var key 1353 1354 function TestHasOwn(handler) { 1355 TestWithProxies(TestHasOwn2, handler) 1356 } 1357 1358 function TestHasOwn2(create, handler) { 1359 var p = create(handler) 1360 assertTrue(Object.prototype.hasOwnProperty.call(p, "a")) 1361 assertEquals("a", key) 1362 assertTrue(Object.prototype.hasOwnProperty.call(p, 99)) 1363 assertEquals("99", key) 1364 assertFalse(Object.prototype.hasOwnProperty.call(p, "z")) 1365 assertEquals("z", key) 1366 } 1367 1368 TestHasOwn({ 1369 hasOwn: function(k) { key = k; return k < "z" } 1370 }) 1371 1372 TestHasOwn({ 1373 hasOwn: function(k) { return this.hasOwn2(k) }, 1374 hasOwn2: function(k) { key = k; return k < "z" } 1375 }) 1376 1377 TestHasOwn({ 1378 getOwnPropertyDescriptor: function(k) { 1379 key = k; return k < "z" ? {value: 42} : void 0 1380 } 1381 }) 1382 1383 TestHasOwn({ 1384 getOwnPropertyDescriptor: function(k) { 1385 return this.getOwnPropertyDescriptor2(k) 1386 }, 1387 getOwnPropertyDescriptor2: function(k) { 1388 key = k; return k < "z" ? {value: 42} : void 0 1389 } 1390 }) 1391 1392 TestHasOwn({ 1393 getOwnPropertyDescriptor: function(k) { 1394 key = k; return k < "z" ? {get value() { return 42 }} : void 0 1395 } 1396 }) 1397 1398 TestHasOwn({ 1399 hasOwn: undefined, 1400 getOwnPropertyDescriptor: function(k) { 1401 key = k; return k < "z" ? {value: 42} : void 0 1402 } 1403 }) 1404 1405 TestHasOwn(Proxy.create({ 1406 get: function(pr, pk) { 1407 return function(k) { key = k; return k < "z" } 1408 } 1409 })) 1410 1411 1412 function TestHasOwnThrow(handler) { 1413 TestWithProxies(TestHasOwnThrow2, handler) 1414 } 1415 1416 function TestHasOwnThrow2(create, handler) { 1417 var p = create(handler) 1418 assertThrows(function(){ Object.prototype.hasOwnProperty.call(p, "a")}, 1419 "myexn") 1420 assertThrows(function(){ Object.prototype.hasOwnProperty.call(p, 99)}, 1421 "myexn") 1422 } 1423 1424 TestHasOwnThrow({ 1425 hasOwn: function(k) { throw "myexn" } 1426 }) 1427 1428 TestHasOwnThrow({ 1429 hasOwn: function(k) { return this.hasOwn2(k) }, 1430 hasOwn2: function(k) { throw "myexn" } 1431 }) 1432 1433 TestHasOwnThrow({ 1434 getOwnPropertyDescriptor: function(k) { throw "myexn" } 1435 }) 1436 1437 TestHasOwnThrow({ 1438 getOwnPropertyDescriptor: function(k) { 1439 return this.getOwnPropertyDescriptor2(k) 1440 }, 1441 getOwnPropertyDescriptor2: function(k) { throw "myexn" } 1442 }) 1443 1444 TestHasOwnThrow({ 1445 hasOwn: undefined, 1446 getOwnPropertyDescriptor: function(k) { throw "myexn" } 1447 }) 1448 1449 TestHasOwnThrow(Proxy.create({ 1450 get: function(pr, pk) { throw "myexn" } 1451 })) 1452 1453 TestHasOwnThrow(Proxy.create({ 1454 get: function(pr, pk) { 1455 return function(k) { throw "myexn" } 1456 } 1457 })) 1458 1459 1460 1461 // Instanceof (instanceof) 1462 1463 function TestProxyInstanceof() { 1464 var o1 = {} 1465 var p1 = Proxy.create({}) 1466 var p2 = Proxy.create({}, o1) 1467 var p3 = Proxy.create({}, p2) 1468 var o2 = Object.create(p2) 1469 1470 var f0 = function() {} 1471 f0.prototype = o1 1472 var f1 = function() {} 1473 f1.prototype = p1 1474 var f2 = function() {} 1475 f2.prototype = p2 1476 var f3 = function() {} 1477 f3.prototype = o2 1478 1479 assertTrue(o1 instanceof Object) 1480 assertFalse(o1 instanceof f0) 1481 assertFalse(o1 instanceof f1) 1482 assertFalse(o1 instanceof f2) 1483 assertFalse(o1 instanceof f3) 1484 assertFalse(p1 instanceof Object) 1485 assertFalse(p1 instanceof f0) 1486 assertFalse(p1 instanceof f1) 1487 assertFalse(p1 instanceof f2) 1488 assertFalse(p1 instanceof f3) 1489 assertTrue(p2 instanceof Object) 1490 assertTrue(p2 instanceof f0) 1491 assertFalse(p2 instanceof f1) 1492 assertFalse(p2 instanceof f2) 1493 assertFalse(p2 instanceof f3) 1494 assertTrue(p3 instanceof Object) 1495 assertTrue(p3 instanceof f0) 1496 assertFalse(p3 instanceof f1) 1497 assertTrue(p3 instanceof f2) 1498 assertFalse(p3 instanceof f3) 1499 assertTrue(o2 instanceof Object) 1500 assertTrue(o2 instanceof f0) 1501 assertFalse(o2 instanceof f1) 1502 assertTrue(o2 instanceof f2) 1503 assertFalse(o2 instanceof f3) 1504 1505 var f = Proxy.createFunction({}, function() {}) 1506 assertTrue(f instanceof Function) 1507 } 1508 1509 TestProxyInstanceof() 1510 1511 1512 function TestInstanceofProxy() { 1513 var o0 = Object.create(null) 1514 var o1 = {} 1515 var o2 = Object.create(o0) 1516 var o3 = Object.create(o1) 1517 var o4 = Object.create(o2) 1518 var o5 = Object.create(o3) 1519 1520 function handler(o) { return {get: function() { return o } } } 1521 var f0 = Proxy.createFunction(handler(o0), function() {}) 1522 var f1 = Proxy.createFunction(handler(o1), function() {}) 1523 var f2 = Proxy.createFunction(handler(o2), function() {}) 1524 var f3 = Proxy.createFunction(handler(o3), function() {}) 1525 var f4 = Proxy.createFunction(handler(o4), function() {}) 1526 var f5 = Proxy.createFunction(handler(o4), function() {}) 1527 1528 assertFalse(null instanceof f0) 1529 assertFalse(o0 instanceof f0) 1530 assertFalse(o0 instanceof f1) 1531 assertFalse(o0 instanceof f2) 1532 assertFalse(o0 instanceof f3) 1533 assertFalse(o0 instanceof f4) 1534 assertFalse(o0 instanceof f5) 1535 assertFalse(o1 instanceof f0) 1536 assertFalse(o1 instanceof f1) 1537 assertFalse(o1 instanceof f2) 1538 assertFalse(o1 instanceof f3) 1539 assertFalse(o1 instanceof f4) 1540 assertFalse(o1 instanceof f5) 1541 assertTrue(o2 instanceof f0) 1542 assertFalse(o2 instanceof f1) 1543 assertFalse(o2 instanceof f2) 1544 assertFalse(o2 instanceof f3) 1545 assertFalse(o2 instanceof f4) 1546 assertFalse(o2 instanceof f5) 1547 assertFalse(o3 instanceof f0) 1548 assertTrue(o3 instanceof f1) 1549 assertFalse(o3 instanceof f2) 1550 assertFalse(o3 instanceof f3) 1551 assertFalse(o3 instanceof f4) 1552 assertFalse(o3 instanceof f5) 1553 assertTrue(o4 instanceof f0) 1554 assertFalse(o4 instanceof f1) 1555 assertTrue(o4 instanceof f2) 1556 assertFalse(o4 instanceof f3) 1557 assertFalse(o4 instanceof f4) 1558 assertFalse(o4 instanceof f5) 1559 assertFalse(o5 instanceof f0) 1560 assertTrue(o5 instanceof f1) 1561 assertFalse(o5 instanceof f2) 1562 assertTrue(o5 instanceof f3) 1563 assertFalse(o5 instanceof f4) 1564 assertFalse(o5 instanceof f5) 1565 1566 var f = Proxy.createFunction({}, function() {}) 1567 var ff = Proxy.createFunction(handler(Function), function() {}) 1568 assertTrue(f instanceof Function) 1569 assertFalse(f instanceof ff) 1570 } 1571 1572 TestInstanceofProxy() 1573 1574 1575 1576 // Prototype (Object.getPrototypeOf, Object.prototype.isPrototypeOf). 1577 1578 function TestPrototype() { 1579 var o1 = {} 1580 var p1 = Proxy.create({}) 1581 var p2 = Proxy.create({}, o1) 1582 var p3 = Proxy.create({}, p2) 1583 var p4 = Proxy.create({}, null) 1584 var o2 = Object.create(p3) 1585 1586 assertSame(Object.getPrototypeOf(o1), Object.prototype) 1587 assertSame(Object.getPrototypeOf(p1), null) 1588 assertSame(Object.getPrototypeOf(p2), o1) 1589 assertSame(Object.getPrototypeOf(p3), p2) 1590 assertSame(Object.getPrototypeOf(p4), null) 1591 assertSame(Object.getPrototypeOf(o2), p3) 1592 1593 assertTrue(Object.prototype.isPrototypeOf(o1)) 1594 assertFalse(Object.prototype.isPrototypeOf(p1)) 1595 assertTrue(Object.prototype.isPrototypeOf(p2)) 1596 assertTrue(Object.prototype.isPrototypeOf(p3)) 1597 assertFalse(Object.prototype.isPrototypeOf(p4)) 1598 assertTrue(Object.prototype.isPrototypeOf(o2)) 1599 assertTrue(Object.prototype.isPrototypeOf.call(Object.prototype, o1)) 1600 assertFalse(Object.prototype.isPrototypeOf.call(Object.prototype, p1)) 1601 assertTrue(Object.prototype.isPrototypeOf.call(Object.prototype, p2)) 1602 assertTrue(Object.prototype.isPrototypeOf.call(Object.prototype, p3)) 1603 assertFalse(Object.prototype.isPrototypeOf.call(Object.prototype, p4)) 1604 assertTrue(Object.prototype.isPrototypeOf.call(Object.prototype, o2)) 1605 assertFalse(Object.prototype.isPrototypeOf.call(o1, o1)) 1606 assertFalse(Object.prototype.isPrototypeOf.call(o1, p1)) 1607 assertTrue(Object.prototype.isPrototypeOf.call(o1, p2)) 1608 assertTrue(Object.prototype.isPrototypeOf.call(o1, p3)) 1609 assertFalse(Object.prototype.isPrototypeOf.call(o1, p4)) 1610 assertTrue(Object.prototype.isPrototypeOf.call(o1, o2)) 1611 assertFalse(Object.prototype.isPrototypeOf.call(p1, p1)) 1612 assertFalse(Object.prototype.isPrototypeOf.call(p1, o1)) 1613 assertFalse(Object.prototype.isPrototypeOf.call(p1, p2)) 1614 assertFalse(Object.prototype.isPrototypeOf.call(p1, p3)) 1615 assertFalse(Object.prototype.isPrototypeOf.call(p1, p4)) 1616 assertFalse(Object.prototype.isPrototypeOf.call(p1, o2)) 1617 assertFalse(Object.prototype.isPrototypeOf.call(p2, p1)) 1618 assertFalse(Object.prototype.isPrototypeOf.call(p2, p2)) 1619 assertTrue(Object.prototype.isPrototypeOf.call(p2, p3)) 1620 assertFalse(Object.prototype.isPrototypeOf.call(p2, p4)) 1621 assertTrue(Object.prototype.isPrototypeOf.call(p2, o2)) 1622 assertFalse(Object.prototype.isPrototypeOf.call(p3, p2)) 1623 assertTrue(Object.prototype.isPrototypeOf.call(p3, o2)) 1624 assertFalse(Object.prototype.isPrototypeOf.call(o2, o1)) 1625 assertFalse(Object.prototype.isPrototypeOf.call(o2, p1)) 1626 assertFalse(Object.prototype.isPrototypeOf.call(o2, p2)) 1627 assertFalse(Object.prototype.isPrototypeOf.call(o2, p3)) 1628 assertFalse(Object.prototype.isPrototypeOf.call(o2, p4)) 1629 assertFalse(Object.prototype.isPrototypeOf.call(o2, o2)) 1630 1631 var f = Proxy.createFunction({}, function() {}) 1632 assertSame(Object.getPrototypeOf(f), Function.prototype) 1633 assertTrue(Object.prototype.isPrototypeOf(f)) 1634 assertTrue(Object.prototype.isPrototypeOf.call(Function.prototype, f)) 1635 } 1636 1637 TestPrototype() 1638 1639 1640 1641 // Property names (Object.getOwnPropertyNames, Object.keys). 1642 1643 function TestPropertyNames(names, handler) { 1644 TestWithProxies(TestPropertyNames2, handler, names) 1645 } 1646 1647 function TestPropertyNames2(create, handler, names) { 1648 var p = create(handler) 1649 assertArrayEquals(names, Object.getOwnPropertyNames(p)) 1650 } 1651 1652 TestPropertyNames([], { 1653 getOwnPropertyNames: function() { return [] } 1654 }) 1655 1656 TestPropertyNames(["a", "zz", " ", "0", "toString"], { 1657 getOwnPropertyNames: function() { return ["a", "zz", " ", 0, "toString"] } 1658 }) 1659 1660 TestPropertyNames(["throw", "function "], { 1661 getOwnPropertyNames: function() { return this.getOwnPropertyNames2() }, 1662 getOwnPropertyNames2: function() { return ["throw", "function "] } 1663 }) 1664 1665 TestPropertyNames(["[object Object]"], { 1666 get getOwnPropertyNames() { 1667 return function() { return [{}] } 1668 } 1669 }) 1670 1671 1672 function TestPropertyNamesThrow(handler) { 1673 TestWithProxies(TestPropertyNamesThrow2, handler) 1674 } 1675 1676 function TestPropertyNamesThrow2(create, handler) { 1677 var p = create(handler) 1678 assertThrows(function(){ Object.getOwnPropertyNames(p) }, "myexn") 1679 } 1680 1681 TestPropertyNamesThrow({ 1682 getOwnPropertyNames: function() { throw "myexn" } 1683 }) 1684 1685 TestPropertyNamesThrow({ 1686 getOwnPropertyNames: function() { return this.getOwnPropertyNames2() }, 1687 getOwnPropertyNames2: function() { throw "myexn" } 1688 }) 1689 1690 1691 function TestKeys(names, handler) { 1692 TestWithProxies(TestKeys2, handler, names) 1693 } 1694 1695 function TestKeys2(create, handler, names) { 1696 var p = create(handler) 1697 assertArrayEquals(names, Object.keys(p)) 1698 } 1699 1700 TestKeys([], { 1701 keys: function() { return [] } 1702 }) 1703 1704 TestKeys(["a", "zz", " ", "0", "toString"], { 1705 keys: function() { return ["a", "zz", " ", 0, "toString"] } 1706 }) 1707 1708 TestKeys(["throw", "function "], { 1709 keys: function() { return this.keys2() }, 1710 keys2: function() { return ["throw", "function "] } 1711 }) 1712 1713 TestKeys(["[object Object]"], { 1714 get keys() { 1715 return function() { return [{}] } 1716 } 1717 }) 1718 1719 TestKeys(["a", "0"], { 1720 getOwnPropertyNames: function() { return ["a", 23, "zz", "", 0] }, 1721 getOwnPropertyDescriptor: function(k) { 1722 return k == "" ? undefined : {enumerable: k.length == 1} 1723 } 1724 }) 1725 1726 TestKeys(["23", "zz", ""], { 1727 getOwnPropertyNames: function() { return this.getOwnPropertyNames2() }, 1728 getOwnPropertyNames2: function() { return ["a", 23, "zz", "", 0] }, 1729 getOwnPropertyDescriptor: function(k) { 1730 return this.getOwnPropertyDescriptor2(k) 1731 }, 1732 getOwnPropertyDescriptor2: function(k) { return {enumerable: k.length != 1} } 1733 }) 1734 1735 TestKeys(["a", "b", "c", "5"], { 1736 get getOwnPropertyNames() { 1737 return function() { return ["0", 4, "a", "b", "c", 5, "ety"] } 1738 }, 1739 get getOwnPropertyDescriptor() { 1740 return function(k) { 1741 return k == "ety" ? undefined : {enumerable: k >= "44"} 1742 } 1743 } 1744 }) 1745 1746 TestKeys([], { 1747 get getOwnPropertyNames() { 1748 return function() { return ["a", "b", "c"] } 1749 }, 1750 getOwnPropertyDescriptor: function(k) { return {} } 1751 }) 1752 1753 1754 function TestKeysThrow(handler) { 1755 TestWithProxies(TestKeysThrow2, handler) 1756 } 1757 1758 function TestKeysThrow2(create, handler) { 1759 var p = create(handler) 1760 assertThrows(function(){ Object.keys(p) }, "myexn") 1761 } 1762 1763 TestKeysThrow({ 1764 keys: function() { throw "myexn" } 1765 }) 1766 1767 TestKeysThrow({ 1768 keys: function() { return this.keys2() }, 1769 keys2: function() { throw "myexn" } 1770 }) 1771 1772 TestKeysThrow({ 1773 getOwnPropertyNames: function() { throw "myexn" }, 1774 getOwnPropertyDescriptor: function(k) { return true } 1775 }) 1776 1777 TestKeysThrow({ 1778 getOwnPropertyNames: function() { return [1, 2] }, 1779 getOwnPropertyDescriptor: function(k) { throw "myexn" } 1780 }) 1781 1782 TestKeysThrow({ 1783 getOwnPropertyNames: function() { return this.getOwnPropertyNames2() }, 1784 getOwnPropertyNames2: function() { throw "myexn" }, 1785 }) 1786 1787 TestKeysThrow({ 1788 getOwnPropertyNames: function() { return this.getOwnPropertyNames2() }, 1789 getOwnPropertyNames2: function() { return [1, 2] }, 1790 getOwnPropertyDescriptor: function(k) { 1791 return this.getOwnPropertyDescriptor2(k) 1792 }, 1793 getOwnPropertyDescriptor2: function(k) { throw "myexn" } 1794 }) 1795 1796 TestKeysThrow({ 1797 get getOwnPropertyNames() { throw "myexn" } 1798 }) 1799 1800 TestKeysThrow({ 1801 get getOwnPropertyNames() { 1802 return function() { throw "myexn" } 1803 }, 1804 }) 1805 1806 TestKeysThrow([], { 1807 get getOwnPropertyNames() { 1808 return function() { return [1, 2] } 1809 }, 1810 getOwnPropertyDescriptor: function(k) { throw "myexn" } 1811 }) 1812 1813 1814 1815 // Fixing (Object.freeze, Object.seal, Object.preventExtensions, 1816 // Object.isFrozen, Object.isSealed, Object.isExtensible) 1817 1818 function TestFix(names, handler) { 1819 var proto = {p: 77} 1820 var assertFixing = function(o, s, f, e) { 1821 assertEquals(s, Object.isSealed(o)) 1822 assertEquals(f, Object.isFrozen(o)) 1823 assertEquals(e, Object.isExtensible(o)) 1824 } 1825 1826 var p1 = Proxy.create(handler, proto) 1827 assertFixing(p1, false, false, true) 1828 Object.seal(p1) 1829 assertFixing(p1, true, names.length === 0, false) 1830 assertArrayEquals(names.sort(), Object.getOwnPropertyNames(p1).sort()) 1831 assertArrayEquals(names.filter(function(x) {return x < "z"}).sort(), 1832 Object.keys(p1).sort()) 1833 assertEquals(proto, Object.getPrototypeOf(p1)) 1834 assertEquals(77, p1.p) 1835 for (var n in p1) { 1836 var desc = Object.getOwnPropertyDescriptor(p1, n) 1837 if (desc !== undefined) assertFalse(desc.configurable) 1838 } 1839 1840 var p2 = Proxy.create(handler, proto) 1841 assertFixing(p2, false, false, true) 1842 Object.freeze(p2) 1843 assertFixing(p2, true, true, false) 1844 assertArrayEquals(names.sort(), Object.getOwnPropertyNames(p2).sort()) 1845 assertArrayEquals(names.filter(function(x) {return x < "z"}).sort(), 1846 Object.keys(p2).sort()) 1847 assertEquals(proto, Object.getPrototypeOf(p2)) 1848 assertEquals(77, p2.p) 1849 for (var n in p2) { 1850 var desc = Object.getOwnPropertyDescriptor(p2, n) 1851 if (desc !== undefined) assertFalse(desc.writable) 1852 if (desc !== undefined) assertFalse(desc.configurable) 1853 } 1854 1855 var p3 = Proxy.create(handler, proto) 1856 assertFixing(p3, false, false, true) 1857 Object.preventExtensions(p3) 1858 assertFixing(p3, names.length === 0, names.length === 0, false) 1859 assertArrayEquals(names.sort(), Object.getOwnPropertyNames(p3).sort()) 1860 assertArrayEquals(names.filter(function(x) {return x < "z"}).sort(), 1861 Object.keys(p3).sort()) 1862 assertEquals(proto, Object.getPrototypeOf(p3)) 1863 assertEquals(77, p3.p) 1864 1865 var p = Proxy.create(handler, proto) 1866 var o = Object.create(p) 1867 assertFixing(p, false, false, true) 1868 assertFixing(o, false, false, true) 1869 Object.freeze(o) 1870 assertFixing(p, false, false, true) 1871 assertFixing(o, true, true, false) 1872 } 1873 1874 TestFix([], { 1875 fix: function() { return {} } 1876 }) 1877 1878 TestFix(["a", "b", "c", "3", "zz"], { 1879 fix: function() { 1880 return { 1881 a: {value: "a", writable: true, configurable: false, enumerable: true}, 1882 b: {value: 33, writable: false, configurable: false, enumerable: true}, 1883 c: {value: 0, writable: true, configurable: true, enumerable: true}, 1884 '3': {value: true, writable: false, configurable: true, enumerable: true}, 1885 zz: {value: 0, enumerable: false} 1886 } 1887 } 1888 }) 1889 1890 TestFix(["a"], { 1891 fix: function() { return this.fix2() }, 1892 fix2: function() { 1893 return {a: {value: 4, writable: true, configurable: true, enumerable: true}} 1894 } 1895 }) 1896 1897 TestFix(["b"], { 1898 get fix() { 1899 return function() { 1900 return {b: {configurable: true, writable: true, enumerable: true}} 1901 } 1902 } 1903 }) 1904 1905 1906 function TestFixFunction(fix) { 1907 var f1 = Proxy.createFunction({ 1908 fix: function() { return {} } 1909 }, function() {}) 1910 fix(f1) 1911 assertEquals(0, f1.length) 1912 1913 var f2 = Proxy.createFunction({ 1914 fix: function() { return {length: {value: 3}} } 1915 }, function() {}) 1916 fix(f2) 1917 assertEquals(3, f2.length) 1918 1919 var f3 = Proxy.createFunction({ 1920 fix: function() { return {length: {value: "huh"}} } 1921 }, function() {}) 1922 fix(f3) 1923 assertEquals(0, f1.length) 1924 } 1925 1926 TestFixFunction(Object.seal) 1927 TestFixFunction(Object.freeze) 1928 TestFixFunction(Object.preventExtensions) 1929 1930 1931 function TestFixThrow(handler) { 1932 TestWithProxies(TestFixThrow2, handler) 1933 } 1934 1935 function TestFixThrow2(create, handler) { 1936 var p = create(handler, {}) 1937 assertThrows(function(){ Object.seal(p) }, "myexn") 1938 assertThrows(function(){ Object.freeze(p) }, "myexn") 1939 assertThrows(function(){ Object.preventExtensions(p) }, "myexn") 1940 } 1941 1942 TestFixThrow({ 1943 fix: function() { throw "myexn" } 1944 }) 1945 1946 TestFixThrow({ 1947 fix: function() { return this.fix2() }, 1948 fix2: function() { throw "myexn" } 1949 }) 1950 1951 TestFixThrow({ 1952 get fix() { throw "myexn" } 1953 }) 1954 1955 TestFixThrow({ 1956 get fix() { 1957 return function() { throw "myexn" } 1958 } 1959 }) 1960 1961 1962 // Freeze a proxy in the middle of operations on it. 1963 // TODO(rossberg): actual behaviour not specified consistently at the moment, 1964 // just make sure that we do not crash. 1965 function TestReentrantFix(f) { 1966 TestWithProxies(f, Object.freeze) 1967 TestWithProxies(f, Object.seal) 1968 TestWithProxies(f, Object.preventExtensions) 1969 } 1970 1971 TestReentrantFix(function(create, freeze) { 1972 var handler = { 1973 get get() { freeze(p); return undefined }, 1974 fix: function() { return {} } 1975 } 1976 var p = create(handler) 1977 // Freeze while getting get trap. 1978 try { p.x } catch (e) { assertInstanceof(e, Error) } 1979 }) 1980 1981 TestReentrantFix(function(create, freeze) { 1982 var handler = { 1983 get: function() { freeze(p); return 3 }, 1984 fix: function() { return {} } 1985 } 1986 var p = create(handler) 1987 // Freeze while executing get trap. 1988 try { p.x } catch (e) { assertInstanceof(e, Error) } 1989 }) 1990 1991 TestReentrantFix(function(create, freeze) { 1992 var handler = { 1993 getPropertyDescriptor: function() { freeze(p); return undefined }, 1994 fix: function() { return {} } 1995 } 1996 var p = create(handler) 1997 // Freeze while executing default get trap. 1998 try { p.x } catch (e) { assertInstanceof(e, Error) } 1999 }) 2000 2001 TestReentrantFix(function(create, freeze) { 2002 var handler = { 2003 getPropertyDescriptor: function() { freeze(p); return {get: function(){}} }, 2004 fix: function() { return {} } 2005 } 2006 var p = create(handler) 2007 var o = Object.create(p) 2008 // Freeze while getting a property from prototype. 2009 try { o.x } catch (e) { assertInstanceof(e, Error) } 2010 }) 2011 2012 TestReentrantFix(function(create, freeze) { 2013 var handler = { 2014 get set() { freeze(p); return undefined }, 2015 fix: function() { return {} } 2016 } 2017 var p = create(handler) 2018 // Freeze while getting set trap. 2019 try { p.x = 4 } catch (e) { assertInstanceof(e, Error) } 2020 }) 2021 2022 TestReentrantFix(function(create, freeze) { 2023 var handler = { 2024 set: function() { freeze(p); return true }, 2025 fix: function() { return {} } 2026 } 2027 var p = create(handler) 2028 // Freeze while executing set trap. 2029 try { p.x = 4 } catch (e) { assertInstanceof(e, Error) } 2030 }) 2031 2032 TestReentrantFix(function(create, freeze) { 2033 var handler = { 2034 getOwnPropertyDescriptor: function() { freeze(p); return undefined }, 2035 fix: function() { return {} } 2036 } 2037 var p = create(handler) 2038 // Freeze while executing default set trap. 2039 try { p.x } catch (e) { assertInstanceof(e, Error) } 2040 }) 2041 2042 TestReentrantFix(function(create, freeze) { 2043 var handler = { 2044 getPropertyDescriptor: function() { freeze(p); return {set: function(){}} }, 2045 fix: function() { return {} } 2046 } 2047 var p = create(handler) 2048 var o = Object.create(p) 2049 // Freeze while setting a property in prototype, dropping the property! 2050 try { o.x = 4 } catch (e) { assertInstanceof(e, Error) } 2051 }) 2052 2053 TestReentrantFix(function(create, freeze) { 2054 var handler = { 2055 getPropertyDescriptor: function() { freeze(p); return {set: function(){}} }, 2056 fix: function() { return {x: {get: function(){}}} } 2057 } 2058 var p = create(handler) 2059 var o = Object.create(p) 2060 // Freeze while setting a property in prototype, making it read-only! 2061 try { o.x = 4 } catch (e) { assertInstanceof(e, Error) } 2062 }) 2063 2064 TestReentrantFix(function(create, freeze) { 2065 var handler = { 2066 get fix() { freeze(p); return function(){} } 2067 } 2068 var p = create(handler) 2069 // Freeze while getting fix trap. 2070 try { Object.freeze(p) } catch (e) { assertInstanceof(e, Error) } 2071 p = create(handler) 2072 try { Object.seal(p) } catch (e) { assertInstanceof(e, Error) } 2073 p = create(handler) 2074 try { Object.preventExtensions(p) } catch (e) { assertInstanceof(e, Error) } 2075 }) 2076 2077 TestReentrantFix(function(create, freeze) { 2078 var handler = { 2079 fix: function() { freeze(p); return {} } 2080 } 2081 var p = create(handler) 2082 // Freeze while executing fix trap. 2083 try { Object.freeze(p) } catch (e) { assertInstanceof(e, Error) } 2084 p = create(handler) 2085 try { Object.seal(p) } catch (e) { assertInstanceof(e, Error) } 2086 p = create(handler) 2087 try { Object.preventExtensions(p) } catch (e) { assertInstanceof(e, Error) } 2088 }) 2089 2090 2091 2092 // String conversion (Object.prototype.toString, 2093 // Object.prototype.toLocaleString, 2094 // Function.prototype.toString) 2095 2096 var key 2097 2098 function TestToString(handler) { 2099 var p = Proxy.create(handler) 2100 key = "" 2101 assertEquals("[object Object]", Object.prototype.toString.call(p)) 2102 assertEquals("", key) 2103 assertEquals("my_proxy", Object.prototype.toLocaleString.call(p)) 2104 assertEquals("toString", key) 2105 2106 var f = Proxy.createFunction(handler, function() {}) 2107 key = "" 2108 assertEquals("[object Function]", Object.prototype.toString.call(f)) 2109 assertEquals("", key) 2110 assertEquals("my_proxy", Object.prototype.toLocaleString.call(f)) 2111 assertEquals("toString", key) 2112 assertDoesNotThrow(function(){ Function.prototype.toString.call(f) }) 2113 2114 var o = Object.create(p) 2115 key = "" 2116 assertEquals("[object Object]", Object.prototype.toString.call(o)) 2117 assertEquals("", key) 2118 assertEquals("my_proxy", Object.prototype.toLocaleString.call(o)) 2119 assertEquals("toString", key) 2120 } 2121 2122 TestToString({ 2123 get: function(r, k) { key = k; return function() { return "my_proxy" } } 2124 }) 2125 2126 TestToString({ 2127 get: function(r, k) { return this.get2(r, k) }, 2128 get2: function(r, k) { key = k; return function() { return "my_proxy" } } 2129 }) 2130 2131 TestToString(Proxy.create({ 2132 get: function(pr, pk) { 2133 return function(r, k) { key = k; return function() { return "my_proxy" } } 2134 } 2135 })) 2136 2137 2138 function TestToStringThrow(handler) { 2139 var p = Proxy.create(handler) 2140 assertEquals("[object Object]", Object.prototype.toString.call(p)) 2141 assertThrows(function(){ Object.prototype.toLocaleString.call(p) }, "myexn") 2142 2143 var f = Proxy.createFunction(handler, function() {}) 2144 assertEquals("[object Function]", Object.prototype.toString.call(f)) 2145 assertThrows(function(){ Object.prototype.toLocaleString.call(f) }, "myexn") 2146 2147 var o = Object.create(p) 2148 assertEquals("[object Object]", Object.prototype.toString.call(o)) 2149 assertThrows(function(){ Object.prototype.toLocaleString.call(o) }, "myexn") 2150 } 2151 2152 TestToStringThrow({ 2153 get: function(r, k) { throw "myexn" } 2154 }) 2155 2156 TestToStringThrow({ 2157 get: function(r, k) { return function() { throw "myexn" } } 2158 }) 2159 2160 TestToStringThrow({ 2161 get: function(r, k) { return this.get2(r, k) }, 2162 get2: function(r, k) { throw "myexn" } 2163 }) 2164 2165 TestToStringThrow(Proxy.create({ 2166 get: function(pr, pk) { throw "myexn" } 2167 })) 2168 2169 TestToStringThrow(Proxy.create({ 2170 get: function(pr, pk) { 2171 return function(r, k) { throw "myexn" } 2172 } 2173 })) 2174 2175 2176 2177 // Value conversion (Object.prototype.toValue) 2178 2179 function TestValueOf(handler) { 2180 TestWithProxies(TestValueOf2, handler) 2181 } 2182 2183 function TestValueOf2(create, handler) { 2184 var p = create(handler) 2185 assertSame(p, Object.prototype.valueOf.call(p)) 2186 } 2187 2188 TestValueOf({}) 2189 2190 2191 2192 // Enumerability (Object.prototype.propertyIsEnumerable) 2193 2194 var key 2195 2196 function TestIsEnumerable(handler) { 2197 TestWithProxies(TestIsEnumerable2, handler) 2198 } 2199 2200 function TestIsEnumerable2(create, handler) { 2201 var p = create(handler) 2202 assertTrue(Object.prototype.propertyIsEnumerable.call(p, "a")) 2203 assertEquals("a", key) 2204 assertTrue(Object.prototype.propertyIsEnumerable.call(p, 2)) 2205 assertEquals("2", key) 2206 assertFalse(Object.prototype.propertyIsEnumerable.call(p, "z")) 2207 assertEquals("z", key) 2208 2209 var o = Object.create(p) 2210 key = "" 2211 assertFalse(Object.prototype.propertyIsEnumerable.call(o, "a")) 2212 assertEquals("", key) // trap not invoked 2213 } 2214 2215 TestIsEnumerable({ 2216 getOwnPropertyDescriptor: function(k) { 2217 key = k; return {enumerable: k < "z", configurable: true} 2218 }, 2219 }) 2220 2221 TestIsEnumerable({ 2222 getOwnPropertyDescriptor: function(k) { 2223 return this.getOwnPropertyDescriptor2(k) 2224 }, 2225 getOwnPropertyDescriptor2: function(k) { 2226 key = k; return {enumerable: k < "z", configurable: true} 2227 }, 2228 }) 2229 2230 TestIsEnumerable({ 2231 getOwnPropertyDescriptor: function(k) { 2232 key = k; return {get enumerable() { return k < "z" }, configurable: true} 2233 }, 2234 }) 2235 2236 TestIsEnumerable(Proxy.create({ 2237 get: function(pr, pk) { 2238 return function(k) { 2239 key = k; return {enumerable: k < "z", configurable: true} 2240 } 2241 } 2242 })) 2243 2244 2245 function TestIsEnumerableThrow(handler) { 2246 TestWithProxies(TestIsEnumerableThrow2, handler) 2247 } 2248 2249 function TestIsEnumerableThrow2(create, handler) { 2250 var p = create(handler) 2251 assertThrows(function(){ Object.prototype.propertyIsEnumerable.call(p, "a") }, 2252 "myexn") 2253 assertThrows(function(){ Object.prototype.propertyIsEnumerable.call(p, 11) }, 2254 "myexn") 2255 } 2256 2257 TestIsEnumerableThrow({ 2258 getOwnPropertyDescriptor: function(k) { throw "myexn" } 2259 }) 2260 2261 TestIsEnumerableThrow({ 2262 getOwnPropertyDescriptor: function(k) { 2263 return this.getOwnPropertyDescriptor2(k) 2264 }, 2265 getOwnPropertyDescriptor2: function(k) { throw "myexn" } 2266 }) 2267 2268 TestIsEnumerableThrow({ 2269 getOwnPropertyDescriptor: function(k) { 2270 return {get enumerable() { throw "myexn" }, configurable: true} 2271 }, 2272 }) 2273 2274 TestIsEnumerableThrow(Proxy.create({ 2275 get: function(pr, pk) { throw "myexn" } 2276 })) 2277 2278 TestIsEnumerableThrow(Proxy.create({ 2279 get: function(pr, pk) { 2280 return function(k) { throw "myexn" } 2281 } 2282 })) 2283 2284 2285 2286 // Constructor functions with proxy prototypes. 2287 2288 function TestConstructorWithProxyPrototype() { 2289 TestWithProxies(TestConstructorWithProxyPrototype2, {}) 2290 } 2291 2292 function TestConstructorWithProxyPrototype2(create, handler) { 2293 function C() {}; 2294 C.prototype = create(handler); 2295 2296 var o = new C; 2297 assertSame(C.prototype, Object.getPrototypeOf(o)); 2298 } 2299 2300 TestConstructorWithProxyPrototype(); 2301