Home | History | Annotate | Download | only in harmony
      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