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 key
    576 var val
    577 
    578 function TestSetForDerived(handler) {
    579   TestWithProxies(TestSetForDerived2, handler)
    580 }
    581 
    582 function TestSetForDerived2(create, handler) {
    583   var p = create(handler)
    584   var o = Object.create(p, {x: {value: 88, writable: true},
    585                             '1': {value: 89, writable: true}})
    586 
    587   key = ""
    588   assertEquals(48, o.x = 48)
    589   assertEquals("", key)  // trap not invoked
    590   assertEquals(48, o.x)
    591 
    592   assertEquals(47, o[1] = 47)
    593   assertEquals("", key)  // trap not invoked
    594   assertEquals(47, o[1])
    595 
    596   assertEquals(49, o.y = 49)
    597   assertEquals("y", key)
    598   assertEquals(49, o.y)
    599 
    600   assertEquals(50, o[2] = 50)
    601   assertEquals("2", key)
    602   assertEquals(50, o[2])
    603 
    604   assertEquals(44, o.p_writable = 44)
    605   assertEquals("p_writable", key)
    606   assertEquals(44, o.p_writable)
    607 
    608   assertEquals(45, o.p_nonwritable = 45)
    609   assertEquals("p_nonwritable", key)
    610   assertEquals(45, o.p_nonwritable)
    611 
    612   assertEquals(46, o.p_setter = 46)
    613   assertEquals("p_setter", key)
    614   assertEquals(46, val)  // written to parent
    615   assertFalse(Object.prototype.hasOwnProperty.call(o, "p_setter"))
    616 
    617   val = ""
    618   assertEquals(47, o.p_nosetter = 47)
    619   assertEquals("p_nosetter", key)
    620   assertEquals("", val)  // not written at all
    621   assertFalse(Object.prototype.hasOwnProperty.call(o, "p_nosetter"));
    622 
    623   key = ""
    624   assertThrows(function(){ "use strict"; o.p_nosetter = 50 }, TypeError)
    625   assertEquals("p_nosetter", key)
    626   assertEquals("", val)  // not written at all
    627 
    628   assertThrows(function(){ o.p_nonconf = 53 }, TypeError)
    629   assertEquals("p_nonconf", key)
    630 
    631   assertThrows(function(){ o.p_throw = 51 }, "myexn")
    632   assertEquals("p_throw", key)
    633 
    634   assertThrows(function(){ o.p_setterthrow = 52 }, "myexn")
    635   assertEquals("p_setterthrow", key)
    636 }
    637 
    638 TestSetForDerived({
    639   getPropertyDescriptor: function(k) {
    640     key = k;
    641     switch (k) {
    642       case "p_writable": return {writable: true, configurable: true}
    643       case "p_nonwritable": return {writable: false, configurable: true}
    644       case "p_setter":return {set: function(x) { val = x }, configurable: true}
    645       case "p_nosetter": return {get: function() { return 1 }, configurable: true}
    646       case "p_nonconf":return {}
    647       case "p_throw": throw "myexn"
    648       case "p_setterthrow": return {set: function(x) { throw "myexn" }}
    649       default: return undefined
    650     }
    651   }
    652 })
    653 
    654 
    655 // Evil proxy-induced side-effects shouldn't crash.
    656 // TODO(rossberg): proper behaviour isn't really spec'ed yet, so ignore results.
    657 
    658 TestWithProxies(function(create) {
    659   var calls = 0
    660   var handler = {
    661     getPropertyDescriptor: function() {
    662       ++calls
    663       return (calls % 2 == 1)
    664         ? {get: function() { return 5 }, configurable: true}
    665         : {set: function() { return false }, configurable: true}
    666     }
    667   }
    668   var p = create(handler)
    669   var o = Object.create(p)
    670   // Make proxy prototype property read-only after CanPut check.
    671   try { o.x = 4 } catch (e) { assertInstanceof(e, Error) }
    672 })
    673 
    674 TestWithProxies(function(create) {
    675   var handler = {
    676     getPropertyDescriptor: function() {
    677       Object.defineProperty(o, "x", {get: function() { return 5 }});
    678       return {set: function() {}}
    679     }
    680   }
    681   var p = create(handler)
    682   var o = Object.create(p)
    683   // Make object property read-only after CanPut check.
    684   try { o.x = 4 } catch (e) { assertInstanceof(e, Error) }
    685 })
    686 
    687 
    688 
    689 // TODO(rossberg): TestSetReject, returning false
    690 // TODO(rossberg): TestGetProperty, TestSetProperty
    691 
    692 
    693 
    694 // Property definition (Object.defineProperty and Object.defineProperties).
    695 
    696 var key
    697 var desc
    698 
    699 function TestDefine(handler) {
    700   TestWithProxies(TestDefine2, handler)
    701 }
    702 
    703 function TestDefine2(create, handler) {
    704   var p = create(handler)
    705   assertEquals(p, Object.defineProperty(p, "a", {value: 44}))
    706   assertEquals("a", key)
    707   assertEquals(1, Object.getOwnPropertyNames(desc).length)
    708   assertEquals(44, desc.value)
    709 
    710   assertEquals(p, Object.defineProperty(p, "b", {value: 45, writable: false}))
    711   assertEquals("b", key)
    712   assertEquals(2, Object.getOwnPropertyNames(desc).length)
    713   assertEquals(45, desc.value)
    714   assertEquals(false, desc.writable)
    715 
    716   assertEquals(p, Object.defineProperty(p, "c", {value: 46, enumerable: false}))
    717   assertEquals("c", key)
    718   assertEquals(2, Object.getOwnPropertyNames(desc).length)
    719   assertEquals(46, desc.value)
    720   assertEquals(false, desc.enumerable)
    721 
    722   assertEquals(p, Object.defineProperty(p, 101, {value: 47, enumerable: false}))
    723   assertEquals("101", key)
    724   assertEquals(2, Object.getOwnPropertyNames(desc).length)
    725   assertEquals(47, desc.value)
    726   assertEquals(false, desc.enumerable)
    727 
    728   var attributes = {configurable: true, mine: 66, minetoo: 23}
    729   assertEquals(p, Object.defineProperty(p, "d", attributes))
    730   assertEquals("d", key)
    731   // Modifying the attributes object after the fact should have no effect.
    732   attributes.configurable = false
    733   attributes.mine = 77
    734   delete attributes.minetoo
    735   assertEquals(3, Object.getOwnPropertyNames(desc).length)
    736   assertEquals(true, desc.configurable)
    737   assertEquals(66, desc.mine)
    738   assertEquals(23, desc.minetoo)
    739 
    740   assertEquals(p, Object.defineProperty(p, "e", {get: function(){ return 5 }}))
    741   assertEquals("e", key)
    742   assertEquals(1, Object.getOwnPropertyNames(desc).length)
    743   assertEquals(5, desc.get())
    744 
    745   assertEquals(p, Object.defineProperty(p, "zzz", {}))
    746   assertEquals("zzz", key)
    747   assertEquals(0, Object.getOwnPropertyNames(desc).length)
    748 
    749   var d = create({
    750     get: function(r, k) { return (k === "value") ? 77 : void 0 },
    751     getOwnPropertyNames: function() { return ["value"] },
    752     enumerate: function() { return ["value"] }
    753   })
    754   assertEquals(1, Object.getOwnPropertyNames(d).length)
    755   assertEquals(77, d.value)
    756   assertEquals(p, Object.defineProperty(p, "p", d))
    757   assertEquals("p", key)
    758   assertEquals(1, Object.getOwnPropertyNames(desc).length)
    759   assertEquals(77, desc.value)
    760 
    761   var props = {
    762     '11': {},
    763     blub: {get: function() { return true }},
    764     '': {get value() { return 20 }},
    765     last: {value: 21, configurable: true, mine: "eyes"}
    766   }
    767   Object.defineProperty(props, "hidden", {value: "hidden", enumerable: false})
    768   assertEquals(p, Object.defineProperties(p, props))
    769   assertEquals("last", key)
    770   assertEquals(2, Object.getOwnPropertyNames(desc).length)
    771   assertEquals(21, desc.value)
    772   assertEquals(true, desc.configurable)
    773   assertEquals(undefined, desc.mine)  // Arguably a bug in the spec...
    774 
    775   var props = {bla: {get value() { throw "myexn" }}}
    776   assertThrows(function(){ Object.defineProperties(p, props) }, "myexn")
    777 }
    778 
    779 TestDefine({
    780   defineProperty: function(k, d) { key = k; desc = d; return true }
    781 })
    782 
    783 TestDefine({
    784   defineProperty: function(k, d) { return this.defineProperty2(k, d) },
    785   defineProperty2: function(k, d) { key = k; desc = d; return true }
    786 })
    787 
    788 TestDefine(Proxy.create({
    789   get: function(pr, pk) {
    790     return function(k, d) { key = k; desc = d; return true }
    791   }
    792 }))
    793 
    794 
    795 function TestDefineThrow(handler) {
    796   TestWithProxies(TestDefineThrow2, handler)
    797 }
    798 
    799 function TestDefineThrow2(create, handler) {
    800   var p = create(handler)
    801   assertThrows(function(){ Object.defineProperty(p, "a", {value: 44})}, "myexn")
    802   assertThrows(function(){ Object.defineProperty(p, 0, {value: 44})}, "myexn")
    803 
    804   var d1 = create({
    805     get: function(r, k) { throw "myexn" },
    806     getOwnPropertyNames: function() { return ["value"] }
    807   })
    808   assertThrows(function(){ Object.defineProperty(p, "p", d1) }, "myexn")
    809   var d2 = create({
    810     get: function(r, k) { return 77 },
    811     getOwnPropertyNames: function() { throw "myexn" }
    812   })
    813   assertThrows(function(){ Object.defineProperty(p, "p", d2) }, "myexn")
    814 
    815   var props = {bla: {get value() { throw "otherexn" }}}
    816   assertThrows(function(){ Object.defineProperties(p, props) }, "otherexn")
    817 }
    818 
    819 TestDefineThrow({
    820   defineProperty: function(k, d) { throw "myexn" }
    821 })
    822 
    823 TestDefineThrow({
    824   defineProperty: function(k, d) { return this.defineProperty2(k, d) },
    825   defineProperty2: function(k, d) { throw "myexn" }
    826 })
    827 
    828 TestDefineThrow(Proxy.create({
    829   get: function(pr, pk) { throw "myexn" }
    830 }))
    831 
    832 TestDefineThrow(Proxy.create({
    833   get: function(pr, pk) {
    834     return function(k, d) { throw "myexn" }
    835   }
    836 }))
    837 
    838 
    839 
    840 // Property deletion (delete).
    841 
    842 var key
    843 
    844 function TestDelete(handler) {
    845   TestWithProxies(TestDelete2, handler)
    846 }
    847 
    848 function TestDelete2(create, handler) {
    849   var p = create(handler)
    850   assertEquals(true, delete p.a)
    851   assertEquals("a", key)
    852   assertEquals(true, delete p["b"])
    853   assertEquals("b", key)
    854   assertEquals(true, delete p[1])
    855   assertEquals("1", key)
    856 
    857   assertEquals(false, delete p.z1)
    858   assertEquals("z1", key)
    859   assertEquals(false, delete p["z2"])
    860   assertEquals("z2", key);
    861 
    862   (function() {
    863     "use strict"
    864     assertEquals(true, delete p.c)
    865     assertEquals("c", key)
    866     assertEquals(true, delete p["d"])
    867     assertEquals("d", key)
    868     assertEquals(true, delete p[2])
    869     assertEquals("2", key)
    870 
    871     assertThrows(function(){ delete p.z3 }, TypeError)
    872     assertEquals("z3", key)
    873     assertThrows(function(){ delete p["z4"] }, TypeError)
    874     assertEquals("z4", key)
    875   })()
    876 }
    877 
    878 TestDelete({
    879   delete: function(k) { key = k; return k < "z" }
    880 })
    881 
    882 TestDelete({
    883   delete: function(k) { return this.delete2(k) },
    884   delete2: function(k) { key = k; return k < "z" }
    885 })
    886 
    887 TestDelete(Proxy.create({
    888   get: function(pr, pk) {
    889     return function(k) { key = k; return k < "z" }
    890   }
    891 }))
    892 
    893 
    894 function TestDeleteThrow(handler) {
    895   TestWithProxies(TestDeleteThrow2, handler)
    896 }
    897 
    898 function TestDeleteThrow2(create, handler) {
    899   var p = create(handler)
    900   assertThrows(function(){ delete p.a }, "myexn")
    901   assertThrows(function(){ delete p["b"] }, "myexn");
    902   assertThrows(function(){ delete p[3] }, "myexn");
    903 
    904   (function() {
    905     "use strict"
    906     assertThrows(function(){ delete p.c }, "myexn")
    907     assertThrows(function(){ delete p["d"] }, "myexn")
    908     assertThrows(function(){ delete p[4] }, "myexn");
    909   })()
    910 }
    911 
    912 TestDeleteThrow({
    913   delete: function(k) { throw "myexn" }
    914 })
    915 
    916 TestDeleteThrow({
    917   delete: function(k) { return this.delete2(k) },
    918   delete2: function(k) { throw "myexn" }
    919 })
    920 
    921 TestDeleteThrow(Proxy.create({
    922   get: function(pr, pk) { throw "myexn" }
    923 }))
    924 
    925 TestDeleteThrow(Proxy.create({
    926   get: function(pr, pk) {
    927     return function(k) { throw "myexn" }
    928   }
    929 }))
    930 
    931 
    932 
    933 // Property descriptors (Object.getOwnPropertyDescriptor).
    934 
    935 function TestDescriptor(handler) {
    936   TestWithProxies(TestDescriptor2, handler)
    937 }
    938 
    939 function TestDescriptor2(create, handler) {
    940   var p = create(handler)
    941   var descs = [
    942     {configurable: true},
    943     {value: 34, enumerable: true, configurable: true},
    944     {value: 3, writable: false, mine: "eyes", configurable: true},
    945     {get value() { return 20 }, get configurable() { return true }},
    946     {get: function() { "get" }, set: function() { "set" }, configurable: true}
    947   ]
    948   for (var i = 0; i < descs.length; ++i) {
    949     assertEquals(p, Object.defineProperty(p, i, descs[i]))
    950     var desc = Object.getOwnPropertyDescriptor(p, i)
    951     for (prop in descs[i]) {
    952       // TODO(rossberg): Ignore user attributes as long as the spec isn't
    953       // fixed suitably.
    954       if (prop != "mine") assertEquals(descs[i][prop], desc[prop])
    955     }
    956     assertEquals(undefined, Object.getOwnPropertyDescriptor(p, "absent"))
    957   }
    958 }
    959 
    960 TestDescriptor({
    961   defineProperty: function(k, d) { this["__" + k] = d; return true },
    962   getOwnPropertyDescriptor: function(k) { return this["__" + k] }
    963 })
    964 
    965 TestDescriptor({
    966   defineProperty: function(k, d) { this["__" + k] = d; return true },
    967   getOwnPropertyDescriptor: function(k) {
    968     return this.getOwnPropertyDescriptor2(k)
    969   },
    970   getOwnPropertyDescriptor2: function(k) { return this["__" + k] }
    971 })
    972 
    973 
    974 function TestDescriptorThrow(handler) {
    975   TestWithProxies(TestDescriptorThrow2, handler)
    976 }
    977 
    978 function TestDescriptorThrow2(create, handler) {
    979   var p = create(handler)
    980   assertThrows(function(){ Object.getOwnPropertyDescriptor(p, "a") }, "myexn")
    981 }
    982 
    983 TestDescriptorThrow({
    984   getOwnPropertyDescriptor: function(k) { throw "myexn" }
    985 })
    986 
    987 TestDescriptorThrow({
    988   getOwnPropertyDescriptor: function(k) {
    989     return this.getOwnPropertyDescriptor2(k)
    990   },
    991   getOwnPropertyDescriptor2: function(k) { throw "myexn" }
    992 })
    993 
    994 
    995 
    996 // Comparison.
    997 
    998 function TestComparison(eq) {
    999   TestWithProxies(TestComparison2, eq)
   1000 }
   1001 
   1002 function TestComparison2(create, eq) {
   1003   var p1 = create({})
   1004   var p2 = create({})
   1005 
   1006   assertTrue(eq(p1, p1))
   1007   assertTrue(eq(p2, p2))
   1008   assertTrue(!eq(p1, p2))
   1009   assertTrue(!eq(p1, {}))
   1010   assertTrue(!eq({}, p2))
   1011   assertTrue(!eq({}, {}))
   1012 }
   1013 
   1014 TestComparison(function(o1, o2) { return o1 == o2 })
   1015 TestComparison(function(o1, o2) { return o1 === o2 })
   1016 TestComparison(function(o1, o2) { return !(o1 != o2) })
   1017 TestComparison(function(o1, o2) { return !(o1 !== o2) })
   1018 
   1019 
   1020 
   1021 // Type (typeof).
   1022 
   1023 function TestTypeof() {
   1024   assertEquals("object", typeof Proxy.create({}))
   1025   assertTrue(typeof Proxy.create({}) == "object")
   1026   assertTrue("object" == typeof Proxy.create({}))
   1027 
   1028   assertEquals("function", typeof Proxy.createFunction({}, function() {}))
   1029   assertTrue(typeof Proxy.createFunction({}, function() {}) == "function")
   1030   assertTrue("function" == typeof Proxy.createFunction({}, function() {}))
   1031 }
   1032 
   1033 TestTypeof()
   1034 
   1035 
   1036 
   1037 // Membership test (in).
   1038 
   1039 var key
   1040 
   1041 function TestIn(handler) {
   1042   TestWithProxies(TestIn2, handler)
   1043 }
   1044 
   1045 function TestIn2(create, handler) {
   1046   var p = create(handler)
   1047   assertTrue("a" in p)
   1048   assertEquals("a", key)
   1049   assertTrue(99 in p)
   1050   assertEquals("99", key)
   1051   assertFalse("z" in p)
   1052   assertEquals("z", key)
   1053 
   1054   assertEquals(2, ("a" in p) ? 2 : 0)
   1055   assertEquals(0, !("a" in p) ? 2 : 0)
   1056   assertEquals(0, ("zzz" in p) ? 2 : 0)
   1057   assertEquals(2, !("zzz" in p) ? 2 : 0)
   1058 
   1059   // Test compilation in conditionals.
   1060   if ("b" in p) {
   1061   } else {
   1062     assertTrue(false)
   1063   }
   1064   assertEquals("b", key)
   1065 
   1066   if ("zz" in p) {
   1067     assertTrue(false)
   1068   }
   1069   assertEquals("zz", key)
   1070 
   1071   if (!("c" in p)) {
   1072     assertTrue(false)
   1073   }
   1074   assertEquals("c", key)
   1075 
   1076   if (!("zzz" in p)) {
   1077   } else {
   1078     assertTrue(false)
   1079   }
   1080   assertEquals("zzz", key)
   1081 }
   1082 
   1083 TestIn({
   1084   has: function(k) { key = k; return k < "z" }
   1085 })
   1086 
   1087 TestIn({
   1088   has: function(k) { return this.has2(k) },
   1089   has2: function(k) { key = k; return k < "z" }
   1090 })
   1091 
   1092 TestIn({
   1093   getPropertyDescriptor: function(k) {
   1094     key = k; return k < "z" ? {value: 42} : void 0
   1095   }
   1096 })
   1097 
   1098 TestIn({
   1099   getPropertyDescriptor: function(k) { return this.getPropertyDescriptor2(k) },
   1100   getPropertyDescriptor2: function(k) {
   1101     key = k; return k < "z" ? {value: 42} : void 0
   1102   }
   1103 })
   1104 
   1105 TestIn({
   1106   getPropertyDescriptor: function(k) {
   1107     key = k; return k < "z" ? {get value() { return 42 }} : void 0
   1108   }
   1109 })
   1110 
   1111 TestIn({
   1112   has: undefined,
   1113   getPropertyDescriptor: function(k) {
   1114     key = k; return k < "z" ? {value: 42} : void 0
   1115   }
   1116 })
   1117 
   1118 TestIn(Proxy.create({
   1119   get: function(pr, pk) {
   1120     return function(k) { key = k; return k < "z" }
   1121   }
   1122 }))
   1123 
   1124 
   1125 function TestInThrow(handler) {
   1126   TestWithProxies(TestInThrow2, handler)
   1127 }
   1128 
   1129 function TestInThrow2(create, handler) {
   1130   var p = create(handler)
   1131   assertThrows(function(){ return "a" in o }, "myexn")
   1132   assertThrows(function(){ return 99 in o }, "myexn")
   1133   assertThrows(function(){ return !("a" in o) }, "myexn")
   1134   assertThrows(function(){ return ("a" in o) ? 2 : 3 }, "myexn")
   1135   assertThrows(function(){ if ("b" in o) {} }, "myexn")
   1136   assertThrows(function(){ if (!("b" in o)) {} }, "myexn")
   1137   assertThrows(function(){ if ("zzz" in o) {} }, "myexn")
   1138 }
   1139 
   1140 TestInThrow({
   1141   has: function(k) { throw "myexn" }
   1142 })
   1143 
   1144 TestInThrow({
   1145   has: function(k) { return this.has2(k) },
   1146   has2: function(k) { throw "myexn" }
   1147 })
   1148 
   1149 TestInThrow({
   1150   getPropertyDescriptor: function(k) { throw "myexn" }
   1151 })
   1152 
   1153 TestInThrow({
   1154   getPropertyDescriptor: function(k) { return this.getPropertyDescriptor2(k) },
   1155   getPropertyDescriptor2: function(k) { throw "myexn" }
   1156 })
   1157 
   1158 TestInThrow({
   1159   has: undefined,
   1160   getPropertyDescriptor: function(k) { throw "myexn" }
   1161 })
   1162 
   1163 TestInThrow(Proxy.create({
   1164   get: function(pr, pk) { throw "myexn" }
   1165 }))
   1166 
   1167 TestInThrow(Proxy.create({
   1168   get: function(pr, pk) {
   1169     return function(k) { throw "myexn" }
   1170   }
   1171 }))
   1172 
   1173 
   1174 function TestInForDerived(handler) {
   1175   TestWithProxies(TestInForDerived2, handler)
   1176 }
   1177 
   1178 function TestInForDerived2(create, handler) {
   1179   var p = create(handler)
   1180   var o = Object.create(p)
   1181 
   1182   assertTrue("a" in o)
   1183   assertEquals("a", key)
   1184   assertTrue(99 in o)
   1185   assertEquals("99", key)
   1186   assertFalse("z" in o)
   1187   assertEquals("z", key)
   1188 
   1189   assertEquals(2, ("a" in o) ? 2 : 0)
   1190   assertEquals(0, !("a" in o) ? 2 : 0)
   1191   assertEquals(0, ("zzz" in o) ? 2 : 0)
   1192   assertEquals(2, !("zzz" in o) ? 2 : 0)
   1193 
   1194   if ("b" in o) {
   1195   } else {
   1196     assertTrue(false)
   1197   }
   1198   assertEquals("b", key)
   1199 
   1200   if ("zz" in o) {
   1201     assertTrue(false)
   1202   }
   1203   assertEquals("zz", key)
   1204 
   1205   if (!("c" in o)) {
   1206     assertTrue(false)
   1207   }
   1208   assertEquals("c", key)
   1209 
   1210   if (!("zzz" in o)) {
   1211   } else {
   1212     assertTrue(false)
   1213   }
   1214   assertEquals("zzz", key)
   1215 }
   1216 
   1217 TestInForDerived({
   1218   getPropertyDescriptor: function(k) {
   1219     key = k; return k < "z" ? {value: 42, configurable: true} : void 0
   1220   }
   1221 })
   1222 
   1223 TestInForDerived({
   1224   getPropertyDescriptor: function(k) { return this.getPropertyDescriptor2(k) },
   1225   getPropertyDescriptor2: function(k) {
   1226     key = k; return k < "z" ? {value: 42, configurable: true} : void 0
   1227   }
   1228 })
   1229 
   1230 TestInForDerived({
   1231   getPropertyDescriptor: function(k) {
   1232     key = k;
   1233     return k < "z" ? {get value() { return 42 }, configurable: true} : void 0
   1234   }
   1235 })
   1236 
   1237 /* TODO(rossberg): this will work once we implement the newest proposal
   1238  * regarding default traps for getPropertyDescriptor.
   1239 TestInForDerived({
   1240   getOwnPropertyDescriptor: function(k) {
   1241     key = k; return k < "z" ? {value: 42, configurable: true} : void 0
   1242   }
   1243 })
   1244 
   1245 TestInForDerived({
   1246   getOwnPropertyDescriptor: function(k) {
   1247     return this.getOwnPropertyDescriptor2(k)
   1248   },
   1249   getOwnPropertyDescriptor2: function(k) {
   1250     key = k; return k < "z" ? {value: 42, configurable: true} : void 0
   1251   }
   1252 })
   1253 
   1254 TestInForDerived({
   1255   getOwnPropertyDescriptor: function(k) {
   1256     key = k;
   1257     return k < "z" ? {get value() { return 42 }, configurable: true} : void 0
   1258   }
   1259 })
   1260 */
   1261 
   1262 TestInForDerived(Proxy.create({
   1263   get: function(pr, pk) {
   1264     return function(k) {
   1265       key = k; return k < "z" ? {value: 42, configurable: true} : void 0
   1266     }
   1267   }
   1268 }))
   1269 
   1270 
   1271 
   1272 // Property descriptor conversion.
   1273 
   1274 var descget
   1275 
   1276 function TestDescriptorGetOrder(handler) {
   1277   var p = Proxy.create(handler)
   1278   var o = Object.create(p, {b: {value: 0}})
   1279   TestDescriptorGetOrder2(function(n) { return p[n] }, "vV")
   1280   TestDescriptorGetOrder2(function(n) { return n in p }, "")
   1281   TestDescriptorGetOrder2(function(n) { return o[n] }, "vV")
   1282   TestDescriptorGetOrder2(function(n) { return n in o }, "eEcCvVwWgs")
   1283 }
   1284 
   1285 function TestDescriptorGetOrder2(f, access) {
   1286   descget = ""
   1287   assertTrue(f("a"))
   1288   assertEquals(access, descget)
   1289   descget = ""
   1290   assertTrue(f(99))
   1291   assertEquals(access, descget)
   1292   descget = ""
   1293   assertFalse(!!f("z"))
   1294   assertEquals("", descget)
   1295 }
   1296 
   1297 TestDescriptorGetOrder({
   1298   getPropertyDescriptor: function(k) {
   1299     if (k >= "z") return void 0
   1300     // Return a proxy as property descriptor, so that we can log accesses.
   1301     return Proxy.create({
   1302       get: function(r, attr) {
   1303         descget += attr[0].toUpperCase()
   1304         return true
   1305       },
   1306       has: function(attr) {
   1307         descget += attr[0]
   1308         switch (attr) {
   1309           case "writable":
   1310           case "enumerable":
   1311           case "configurable":
   1312           case "value":
   1313             return true
   1314           case "get":
   1315           case "set":
   1316             return false
   1317           default:
   1318             assertUnreachable()
   1319         }
   1320       }
   1321     })
   1322   }
   1323 })
   1324 
   1325 
   1326 
   1327 // Own Properties (Object.prototype.hasOwnProperty).
   1328 
   1329 var key
   1330 
   1331 function TestHasOwn(handler) {
   1332   TestWithProxies(TestHasOwn2, handler)
   1333 }
   1334 
   1335 function TestHasOwn2(create, handler) {
   1336   var p = create(handler)
   1337   assertTrue(Object.prototype.hasOwnProperty.call(p, "a"))
   1338   assertEquals("a", key)
   1339   assertTrue(Object.prototype.hasOwnProperty.call(p, 99))
   1340   assertEquals("99", key)
   1341   assertFalse(Object.prototype.hasOwnProperty.call(p, "z"))
   1342   assertEquals("z", key)
   1343 }
   1344 
   1345 TestHasOwn({
   1346   hasOwn: function(k) { key = k; return k < "z" }
   1347 })
   1348 
   1349 TestHasOwn({
   1350   hasOwn: function(k) { return this.hasOwn2(k) },
   1351   hasOwn2: function(k) { key = k; return k < "z" }
   1352 })
   1353 
   1354 TestHasOwn({
   1355   getOwnPropertyDescriptor: function(k) {
   1356     key = k; return k < "z" ? {value: 42} : void 0
   1357   }
   1358 })
   1359 
   1360 TestHasOwn({
   1361   getOwnPropertyDescriptor: function(k) {
   1362     return this.getOwnPropertyDescriptor2(k)
   1363   },
   1364   getOwnPropertyDescriptor2: function(k) {
   1365     key = k; return k < "z" ? {value: 42} : void 0
   1366   }
   1367 })
   1368 
   1369 TestHasOwn({
   1370   getOwnPropertyDescriptor: function(k) {
   1371     key = k; return k < "z" ? {get value() { return 42 }} : void 0
   1372   }
   1373 })
   1374 
   1375 TestHasOwn({
   1376   hasOwn: undefined,
   1377   getOwnPropertyDescriptor: function(k) {
   1378     key = k; return k < "z" ? {value: 42} : void 0
   1379   }
   1380 })
   1381 
   1382 TestHasOwn(Proxy.create({
   1383   get: function(pr, pk) {
   1384     return function(k) { key = k; return k < "z" }
   1385   }
   1386 }))
   1387 
   1388 
   1389 function TestHasOwnThrow(handler) {
   1390   TestWithProxies(TestHasOwnThrow2, handler)
   1391 }
   1392 
   1393 function TestHasOwnThrow2(create, handler) {
   1394   var p = create(handler)
   1395   assertThrows(function(){ Object.prototype.hasOwnProperty.call(p, "a")},
   1396     "myexn")
   1397   assertThrows(function(){ Object.prototype.hasOwnProperty.call(p, 99)},
   1398     "myexn")
   1399 }
   1400 
   1401 TestHasOwnThrow({
   1402   hasOwn: function(k) { throw "myexn" }
   1403 })
   1404 
   1405 TestHasOwnThrow({
   1406   hasOwn: function(k) { return this.hasOwn2(k) },
   1407   hasOwn2: function(k) { throw "myexn" }
   1408 })
   1409 
   1410 TestHasOwnThrow({
   1411   getOwnPropertyDescriptor: function(k) { throw "myexn" }
   1412 })
   1413 
   1414 TestHasOwnThrow({
   1415   getOwnPropertyDescriptor: function(k) {
   1416     return this.getOwnPropertyDescriptor2(k)
   1417   },
   1418   getOwnPropertyDescriptor2: function(k) { throw "myexn" }
   1419 })
   1420 
   1421 TestHasOwnThrow({
   1422   hasOwn: undefined,
   1423   getOwnPropertyDescriptor: function(k) { throw "myexn" }
   1424 })
   1425 
   1426 TestHasOwnThrow(Proxy.create({
   1427   get: function(pr, pk) { throw "myexn" }
   1428 }))
   1429 
   1430 TestHasOwnThrow(Proxy.create({
   1431   get: function(pr, pk) {
   1432     return function(k) { throw "myexn" }
   1433   }
   1434 }))
   1435 
   1436 
   1437 
   1438 // Instanceof (instanceof)
   1439 
   1440 function TestProxyInstanceof() {
   1441   var o1 = {}
   1442   var p1 = Proxy.create({})
   1443   var p2 = Proxy.create({}, o1)
   1444   var p3 = Proxy.create({}, p2)
   1445   var o2 = Object.create(p2)
   1446 
   1447   var f0 = function() {}
   1448   f0.prototype = o1
   1449   var f1 = function() {}
   1450   f1.prototype = p1
   1451   var f2 = function() {}
   1452   f2.prototype = p2
   1453   var f3 = function() {}
   1454   f3.prototype = o2
   1455 
   1456   assertTrue(o1 instanceof Object)
   1457   assertFalse(o1 instanceof f0)
   1458   assertFalse(o1 instanceof f1)
   1459   assertFalse(o1 instanceof f2)
   1460   assertFalse(o1 instanceof f3)
   1461   assertFalse(p1 instanceof Object)
   1462   assertFalse(p1 instanceof f0)
   1463   assertFalse(p1 instanceof f1)
   1464   assertFalse(p1 instanceof f2)
   1465   assertFalse(p1 instanceof f3)
   1466   assertTrue(p2 instanceof Object)
   1467   assertTrue(p2 instanceof f0)
   1468   assertFalse(p2 instanceof f1)
   1469   assertFalse(p2 instanceof f2)
   1470   assertFalse(p2 instanceof f3)
   1471   assertTrue(p3 instanceof Object)
   1472   assertTrue(p3 instanceof f0)
   1473   assertFalse(p3 instanceof f1)
   1474   assertTrue(p3 instanceof f2)
   1475   assertFalse(p3 instanceof f3)
   1476   assertTrue(o2 instanceof Object)
   1477   assertTrue(o2 instanceof f0)
   1478   assertFalse(o2 instanceof f1)
   1479   assertTrue(o2 instanceof f2)
   1480   assertFalse(o2 instanceof f3)
   1481 
   1482   var f = Proxy.createFunction({}, function() {})
   1483   assertTrue(f instanceof Function)
   1484 }
   1485 
   1486 TestProxyInstanceof()
   1487 
   1488 
   1489 function TestInstanceofProxy() {
   1490   var o0 = Object.create(null)
   1491   var o1 = {}
   1492   var o2 = Object.create(o0)
   1493   var o3 = Object.create(o1)
   1494   var o4 = Object.create(o2)
   1495   var o5 = Object.create(o3)
   1496 
   1497   function handler(o) { return {get: function() { return o } } }
   1498   var f0 = Proxy.createFunction(handler(o0), function() {})
   1499   var f1 = Proxy.createFunction(handler(o1), function() {})
   1500   var f2 = Proxy.createFunction(handler(o2), function() {})
   1501   var f3 = Proxy.createFunction(handler(o3), function() {})
   1502   var f4 = Proxy.createFunction(handler(o4), function() {})
   1503   var f5 = Proxy.createFunction(handler(o4), function() {})
   1504 
   1505   assertFalse(null instanceof f0)
   1506   assertFalse(o0 instanceof f0)
   1507   assertFalse(o0 instanceof f1)
   1508   assertFalse(o0 instanceof f2)
   1509   assertFalse(o0 instanceof f3)
   1510   assertFalse(o0 instanceof f4)
   1511   assertFalse(o0 instanceof f5)
   1512   assertFalse(o1 instanceof f0)
   1513   assertFalse(o1 instanceof f1)
   1514   assertFalse(o1 instanceof f2)
   1515   assertFalse(o1 instanceof f3)
   1516   assertFalse(o1 instanceof f4)
   1517   assertFalse(o1 instanceof f5)
   1518   assertTrue(o2 instanceof f0)
   1519   assertFalse(o2 instanceof f1)
   1520   assertFalse(o2 instanceof f2)
   1521   assertFalse(o2 instanceof f3)
   1522   assertFalse(o2 instanceof f4)
   1523   assertFalse(o2 instanceof f5)
   1524   assertFalse(o3 instanceof f0)
   1525   assertTrue(o3 instanceof f1)
   1526   assertFalse(o3 instanceof f2)
   1527   assertFalse(o3 instanceof f3)
   1528   assertFalse(o3 instanceof f4)
   1529   assertFalse(o3 instanceof f5)
   1530   assertTrue(o4 instanceof f0)
   1531   assertFalse(o4 instanceof f1)
   1532   assertTrue(o4 instanceof f2)
   1533   assertFalse(o4 instanceof f3)
   1534   assertFalse(o4 instanceof f4)
   1535   assertFalse(o4 instanceof f5)
   1536   assertFalse(o5 instanceof f0)
   1537   assertTrue(o5 instanceof f1)
   1538   assertFalse(o5 instanceof f2)
   1539   assertTrue(o5 instanceof f3)
   1540   assertFalse(o5 instanceof f4)
   1541   assertFalse(o5 instanceof f5)
   1542 
   1543   var f = Proxy.createFunction({}, function() {})
   1544   var ff = Proxy.createFunction(handler(Function), function() {})
   1545   assertTrue(f instanceof Function)
   1546   assertFalse(f instanceof ff)
   1547 }
   1548 
   1549 TestInstanceofProxy()
   1550 
   1551 
   1552 
   1553 // Prototype (Object.getPrototypeOf, Object.prototype.isPrototypeOf).
   1554 
   1555 function TestPrototype() {
   1556   var o1 = {}
   1557   var p1 = Proxy.create({})
   1558   var p2 = Proxy.create({}, o1)
   1559   var p3 = Proxy.create({}, p2)
   1560   var p4 = Proxy.create({}, null)
   1561   var o2 = Object.create(p3)
   1562 
   1563   assertSame(Object.getPrototypeOf(o1), Object.prototype)
   1564   assertSame(Object.getPrototypeOf(p1), null)
   1565   assertSame(Object.getPrototypeOf(p2), o1)
   1566   assertSame(Object.getPrototypeOf(p3), p2)
   1567   assertSame(Object.getPrototypeOf(p4), null)
   1568   assertSame(Object.getPrototypeOf(o2), p3)
   1569 
   1570   assertTrue(Object.prototype.isPrototypeOf(o1))
   1571   assertFalse(Object.prototype.isPrototypeOf(p1))
   1572   assertTrue(Object.prototype.isPrototypeOf(p2))
   1573   assertTrue(Object.prototype.isPrototypeOf(p3))
   1574   assertFalse(Object.prototype.isPrototypeOf(p4))
   1575   assertTrue(Object.prototype.isPrototypeOf(o2))
   1576   assertTrue(Object.prototype.isPrototypeOf.call(Object.prototype, o1))
   1577   assertFalse(Object.prototype.isPrototypeOf.call(Object.prototype, p1))
   1578   assertTrue(Object.prototype.isPrototypeOf.call(Object.prototype, p2))
   1579   assertTrue(Object.prototype.isPrototypeOf.call(Object.prototype, p3))
   1580   assertFalse(Object.prototype.isPrototypeOf.call(Object.prototype, p4))
   1581   assertTrue(Object.prototype.isPrototypeOf.call(Object.prototype, o2))
   1582   assertFalse(Object.prototype.isPrototypeOf.call(o1, o1))
   1583   assertFalse(Object.prototype.isPrototypeOf.call(o1, p1))
   1584   assertTrue(Object.prototype.isPrototypeOf.call(o1, p2))
   1585   assertTrue(Object.prototype.isPrototypeOf.call(o1, p3))
   1586   assertFalse(Object.prototype.isPrototypeOf.call(o1, p4))
   1587   assertTrue(Object.prototype.isPrototypeOf.call(o1, o2))
   1588   assertFalse(Object.prototype.isPrototypeOf.call(p1, p1))
   1589   assertFalse(Object.prototype.isPrototypeOf.call(p1, o1))
   1590   assertFalse(Object.prototype.isPrototypeOf.call(p1, p2))
   1591   assertFalse(Object.prototype.isPrototypeOf.call(p1, p3))
   1592   assertFalse(Object.prototype.isPrototypeOf.call(p1, p4))
   1593   assertFalse(Object.prototype.isPrototypeOf.call(p1, o2))
   1594   assertFalse(Object.prototype.isPrototypeOf.call(p2, p1))
   1595   assertFalse(Object.prototype.isPrototypeOf.call(p2, p2))
   1596   assertTrue(Object.prototype.isPrototypeOf.call(p2, p3))
   1597   assertFalse(Object.prototype.isPrototypeOf.call(p2, p4))
   1598   assertTrue(Object.prototype.isPrototypeOf.call(p2, o2))
   1599   assertFalse(Object.prototype.isPrototypeOf.call(p3, p2))
   1600   assertTrue(Object.prototype.isPrototypeOf.call(p3, o2))
   1601   assertFalse(Object.prototype.isPrototypeOf.call(o2, o1))
   1602   assertFalse(Object.prototype.isPrototypeOf.call(o2, p1))
   1603   assertFalse(Object.prototype.isPrototypeOf.call(o2, p2))
   1604   assertFalse(Object.prototype.isPrototypeOf.call(o2, p3))
   1605   assertFalse(Object.prototype.isPrototypeOf.call(o2, p4))
   1606   assertFalse(Object.prototype.isPrototypeOf.call(o2, o2))
   1607 
   1608   var f = Proxy.createFunction({}, function() {})
   1609   assertSame(Object.getPrototypeOf(f), Function.prototype)
   1610   assertTrue(Object.prototype.isPrototypeOf(f))
   1611   assertTrue(Object.prototype.isPrototypeOf.call(Function.prototype, f))
   1612 }
   1613 
   1614 TestPrototype()
   1615 
   1616 
   1617 
   1618 // Property names (Object.getOwnPropertyNames, Object.keys).
   1619 
   1620 function TestPropertyNames(names, handler) {
   1621   TestWithProxies(TestPropertyNames2, handler, names)
   1622 }
   1623 
   1624 function TestPropertyNames2(create, handler, names) {
   1625   var p = create(handler)
   1626   assertArrayEquals(names, Object.getOwnPropertyNames(p))
   1627 }
   1628 
   1629 TestPropertyNames([], {
   1630   getOwnPropertyNames: function() { return [] }
   1631 })
   1632 
   1633 TestPropertyNames(["a", "zz", " ", "0"], {
   1634   getOwnPropertyNames: function() { return ["a", "zz", " ", 0] }
   1635 })
   1636 
   1637 TestPropertyNames(["throw", "function "], {
   1638   getOwnPropertyNames: function() { return this.getOwnPropertyNames2() },
   1639   getOwnPropertyNames2: function() { return ["throw", "function "] }
   1640 })
   1641 
   1642 TestPropertyNames(["[object Object]"], {
   1643   get getOwnPropertyNames() {
   1644     return function() { return [{}] }
   1645   }
   1646 })
   1647 
   1648 
   1649 function TestPropertyNamesThrow(handler) {
   1650   TestWithProxies(TestPropertyNamesThrow2, handler)
   1651 }
   1652 
   1653 function TestPropertyNamesThrow2(create, handler) {
   1654   var p = create(handler)
   1655   assertThrows(function(){ Object.getOwnPropertyNames(p) }, "myexn")
   1656 }
   1657 
   1658 TestPropertyNamesThrow({
   1659   getOwnPropertyNames: function() { throw "myexn" }
   1660 })
   1661 
   1662 TestPropertyNamesThrow({
   1663   getOwnPropertyNames: function() { return this.getOwnPropertyNames2() },
   1664   getOwnPropertyNames2: function() { throw "myexn" }
   1665 })
   1666 
   1667 
   1668 function TestKeys(names, handler) {
   1669   TestWithProxies(TestKeys2, handler, names)
   1670 }
   1671 
   1672 function TestKeys2(create, handler, names) {
   1673   var p = create(handler)
   1674   assertArrayEquals(names, Object.keys(p))
   1675 }
   1676 
   1677 TestKeys([], {
   1678   keys: function() { return [] }
   1679 })
   1680 
   1681 TestKeys(["a", "zz", " ", "0"], {
   1682   keys: function() { return ["a", "zz", " ", 0] }
   1683 })
   1684 
   1685 TestKeys(["throw", "function "], {
   1686   keys: function() { return this.keys2() },
   1687   keys2: function() { return ["throw", "function "] }
   1688 })
   1689 
   1690 TestKeys(["[object Object]"], {
   1691   get keys() {
   1692     return function() { return [{}] }
   1693   }
   1694 })
   1695 
   1696 TestKeys(["a", "0"], {
   1697   getOwnPropertyNames: function() { return ["a", 23, "zz", "", 0] },
   1698   getOwnPropertyDescriptor: function(k) {
   1699     return k == "" ? undefined : {enumerable: k.length == 1}
   1700   }
   1701 })
   1702 
   1703 TestKeys(["23", "zz", ""], {
   1704   getOwnPropertyNames: function() { return this.getOwnPropertyNames2() },
   1705   getOwnPropertyNames2: function() { return ["a", 23, "zz", "", 0] },
   1706   getOwnPropertyDescriptor: function(k) {
   1707     return this.getOwnPropertyDescriptor2(k)
   1708   },
   1709   getOwnPropertyDescriptor2: function(k) { return {enumerable: k.length != 1} }
   1710 })
   1711 
   1712 TestKeys(["a", "b", "c", "5"], {
   1713   get getOwnPropertyNames() {
   1714     return function() { return ["0", 4, "a", "b", "c", 5, "ety"] }
   1715   },
   1716   get getOwnPropertyDescriptor() {
   1717     return function(k) {
   1718       return k == "ety" ? undefined : {enumerable: k >= "44"}
   1719     }
   1720   }
   1721 })
   1722 
   1723 TestKeys([], {
   1724   get getOwnPropertyNames() {
   1725     return function() { return ["a", "b", "c"] }
   1726   },
   1727   getOwnPropertyDescriptor: function(k) { return {} }
   1728 })
   1729 
   1730 
   1731 function TestKeysThrow(handler) {
   1732   TestWithProxies(TestKeysThrow2, handler)
   1733 }
   1734 
   1735 function TestKeysThrow2(create, handler) {
   1736   var p = create(handler)
   1737   assertThrows(function(){ Object.keys(p) }, "myexn")
   1738 }
   1739 
   1740 TestKeysThrow({
   1741   keys: function() { throw "myexn" }
   1742 })
   1743 
   1744 TestKeysThrow({
   1745   keys: function() { return this.keys2() },
   1746   keys2: function() { throw "myexn" }
   1747 })
   1748 
   1749 TestKeysThrow({
   1750   getOwnPropertyNames: function() { throw "myexn" },
   1751   getOwnPropertyDescriptor: function(k) { return true }
   1752 })
   1753 
   1754 TestKeysThrow({
   1755   getOwnPropertyNames: function() { return [1, 2] },
   1756   getOwnPropertyDescriptor: function(k) { throw "myexn" }
   1757 })
   1758 
   1759 TestKeysThrow({
   1760   getOwnPropertyNames: function() { return this.getOwnPropertyNames2() },
   1761   getOwnPropertyNames2: function() { throw "myexn" },
   1762 })
   1763 
   1764 TestKeysThrow({
   1765   getOwnPropertyNames: function() { return this.getOwnPropertyNames2() },
   1766   getOwnPropertyNames2: function() { return [1, 2] },
   1767   getOwnPropertyDescriptor: function(k) {
   1768     return this.getOwnPropertyDescriptor2(k)
   1769   },
   1770   getOwnPropertyDescriptor2: function(k) { throw "myexn" }
   1771 })
   1772 
   1773 TestKeysThrow({
   1774   get getOwnPropertyNames() { throw "myexn" }
   1775 })
   1776 
   1777 TestKeysThrow({
   1778   get getOwnPropertyNames() {
   1779     return function() { throw "myexn" }
   1780   },
   1781 })
   1782 
   1783 TestKeysThrow([], {
   1784   get getOwnPropertyNames() {
   1785     return function() { return [1, 2] }
   1786   },
   1787   getOwnPropertyDescriptor: function(k) { throw "myexn" }
   1788 })
   1789 
   1790 
   1791 
   1792 // Fixing (Object.freeze, Object.seal, Object.preventExtensions,
   1793 //         Object.isFrozen, Object.isSealed, Object.isExtensible)
   1794 
   1795 function TestFix(names, handler) {
   1796   var proto = {p: 77}
   1797   var assertFixing = function(o, s, f, e) {
   1798     assertEquals(s, Object.isSealed(o))
   1799     assertEquals(f, Object.isFrozen(o))
   1800     assertEquals(e, Object.isExtensible(o))
   1801   }
   1802 
   1803   var p1 = Proxy.create(handler, proto)
   1804   assertFixing(p1, false, false, true)
   1805   Object.seal(p1)
   1806   assertFixing(p1, true, names.length === 0, false)
   1807   assertArrayEquals(names.sort(), Object.getOwnPropertyNames(p1).sort())
   1808   assertArrayEquals(names.filter(function(x) {return x < "z"}).sort(),
   1809                     Object.keys(p1).sort())
   1810   assertEquals(proto, Object.getPrototypeOf(p1))
   1811   assertEquals(77, p1.p)
   1812   for (var n in p1) {
   1813     var desc = Object.getOwnPropertyDescriptor(p1, n)
   1814     if (desc !== undefined) assertFalse(desc.configurable)
   1815   }
   1816 
   1817   var p2 = Proxy.create(handler, proto)
   1818   assertFixing(p2, false, false, true)
   1819   Object.freeze(p2)
   1820   assertFixing(p2, true, true, false)
   1821   assertArrayEquals(names.sort(), Object.getOwnPropertyNames(p2).sort())
   1822   assertArrayEquals(names.filter(function(x) {return x < "z"}).sort(),
   1823                     Object.keys(p2).sort())
   1824   assertEquals(proto, Object.getPrototypeOf(p2))
   1825   assertEquals(77, p2.p)
   1826   for (var n in p2) {
   1827     var desc = Object.getOwnPropertyDescriptor(p2, n)
   1828     if (desc !== undefined) assertFalse(desc.writable)
   1829     if (desc !== undefined) assertFalse(desc.configurable)
   1830   }
   1831 
   1832   var p3 = Proxy.create(handler, proto)
   1833   assertFixing(p3, false, false, true)
   1834   Object.preventExtensions(p3)
   1835   assertFixing(p3, names.length === 0, names.length === 0, false)
   1836   assertArrayEquals(names.sort(), Object.getOwnPropertyNames(p3).sort())
   1837   assertArrayEquals(names.filter(function(x) {return x < "z"}).sort(),
   1838                     Object.keys(p3).sort())
   1839   assertEquals(proto, Object.getPrototypeOf(p3))
   1840   assertEquals(77, p3.p)
   1841 
   1842   var p = Proxy.create(handler, proto)
   1843   var o = Object.create(p)
   1844   assertFixing(p, false, false, true)
   1845   assertFixing(o, false, false, true)
   1846   Object.freeze(o)
   1847   assertFixing(p, false, false, true)
   1848   assertFixing(o, true, true, false)
   1849 }
   1850 
   1851 TestFix([], {
   1852   fix: function() { return {} }
   1853 })
   1854 
   1855 TestFix(["a", "b", "c", "3", "zz"], {
   1856   fix: function() {
   1857     return {
   1858       a: {value: "a", writable: true, configurable: false, enumerable: true},
   1859       b: {value: 33, writable: false, configurable: false, enumerable: true},
   1860       c: {value: 0, writable: true, configurable: true, enumerable: true},
   1861       '3': {value: true, writable: false, configurable: true, enumerable: true},
   1862       zz: {value: 0, enumerable: false}
   1863     }
   1864   }
   1865 })
   1866 
   1867 TestFix(["a"], {
   1868   fix: function() { return this.fix2() },
   1869   fix2: function() {
   1870     return {a: {value: 4, writable: true, configurable: true, enumerable: true}}
   1871   }
   1872 })
   1873 
   1874 TestFix(["b"], {
   1875   get fix() {
   1876     return function() {
   1877       return {b: {configurable: true, writable: true, enumerable: true}}
   1878     }
   1879   }
   1880 })
   1881 
   1882 
   1883 function TestFixFunction(fix) {
   1884   var f1 = Proxy.createFunction({
   1885     fix: function() { return {} }
   1886   }, function() {})
   1887   fix(f1)
   1888   assertEquals(0, f1.length)
   1889 
   1890   var f2 = Proxy.createFunction({
   1891     fix: function() { return {length: {value: 3}} }
   1892   }, function() {})
   1893   fix(f2)
   1894   assertEquals(3, f2.length)
   1895 
   1896   var f3 = Proxy.createFunction({
   1897     fix: function() { return {length: {value: "huh"}} }
   1898   }, function() {})
   1899   fix(f3)
   1900   assertEquals(0, f1.length)
   1901 }
   1902 
   1903 TestFixFunction(Object.seal)
   1904 TestFixFunction(Object.freeze)
   1905 TestFixFunction(Object.preventExtensions)
   1906 
   1907 
   1908 function TestFixThrow(handler) {
   1909   TestWithProxies(TestFixThrow2, handler)
   1910 }
   1911 
   1912 function TestFixThrow2(create, handler) {
   1913   var p = create(handler, {})
   1914   assertThrows(function(){ Object.seal(p) }, "myexn")
   1915   assertThrows(function(){ Object.freeze(p) }, "myexn")
   1916   assertThrows(function(){ Object.preventExtensions(p) }, "myexn")
   1917 }
   1918 
   1919 TestFixThrow({
   1920   fix: function() { throw "myexn" }
   1921 })
   1922 
   1923 TestFixThrow({
   1924   fix: function() { return this.fix2() },
   1925   fix2: function() { throw "myexn" }
   1926 })
   1927 
   1928 TestFixThrow({
   1929   get fix() { throw "myexn" }
   1930 })
   1931 
   1932 TestFixThrow({
   1933   get fix() {
   1934     return function() { throw "myexn" }
   1935   }
   1936 })
   1937 
   1938 
   1939 // Freeze a proxy in the middle of operations on it.
   1940 // TODO(rossberg): actual behaviour not specified consistently at the moment,
   1941 // just make sure that we do not crash.
   1942 function TestReentrantFix(f) {
   1943   TestWithProxies(f, Object.freeze)
   1944   TestWithProxies(f, Object.seal)
   1945   TestWithProxies(f, Object.preventExtensions)
   1946 }
   1947 
   1948 TestReentrantFix(function(create, freeze) {
   1949   var handler = {
   1950     get get() { freeze(p); return undefined },
   1951     fix: function() { return {} }
   1952   }
   1953   var p = create(handler)
   1954   // Freeze while getting get trap.
   1955   try { p.x } catch (e) { assertInstanceof(e, Error) }
   1956 })
   1957 
   1958 TestReentrantFix(function(create, freeze) {
   1959   var handler = {
   1960     get: function() { freeze(p); return 3 },
   1961     fix: function() { return {} }
   1962   }
   1963   var p = create(handler)
   1964   // Freeze while executing get trap.
   1965   try { p.x } catch (e) { assertInstanceof(e, Error) }
   1966 })
   1967 
   1968 TestReentrantFix(function(create, freeze) {
   1969   var handler = {
   1970     getPropertyDescriptor: function() { freeze(p); return undefined },
   1971     fix: function() { return {} }
   1972   }
   1973   var p = create(handler)
   1974   // Freeze while executing default get trap.
   1975   try { p.x } catch (e) { assertInstanceof(e, Error) }
   1976 })
   1977 
   1978 TestReentrantFix(function(create, freeze) {
   1979   var handler = {
   1980     getPropertyDescriptor: function() { freeze(p); return {get: function(){}} },
   1981     fix: function() { return {} }
   1982   }
   1983   var p = create(handler)
   1984   var o = Object.create(p)
   1985   // Freeze while getting a property from prototype.
   1986   try { o.x } catch (e) { assertInstanceof(e, Error) }
   1987 })
   1988 
   1989 TestReentrantFix(function(create, freeze) {
   1990   var handler = {
   1991     get set() { freeze(p); return undefined },
   1992     fix: function() { return {} }
   1993   }
   1994   var p = create(handler)
   1995   // Freeze while getting set trap.
   1996   try { p.x = 4 } catch (e) { assertInstanceof(e, Error) }
   1997 })
   1998 
   1999 TestReentrantFix(function(create, freeze) {
   2000   var handler = {
   2001     set: function() { freeze(p); return true },
   2002     fix: function() { return {} }
   2003   }
   2004   var p = create(handler)
   2005   // Freeze while executing set trap.
   2006   try { p.x = 4 } catch (e) { assertInstanceof(e, Error) }
   2007 })
   2008 
   2009 TestReentrantFix(function(create, freeze) {
   2010   var handler = {
   2011     getOwnPropertyDescriptor: function() { freeze(p); return undefined },
   2012     fix: function() { return {} }
   2013   }
   2014   var p = create(handler)
   2015   // Freeze while executing default set trap.
   2016   try { p.x } catch (e) { assertInstanceof(e, Error) }
   2017 })
   2018 
   2019 TestReentrantFix(function(create, freeze) {
   2020   var handler = {
   2021     getPropertyDescriptor: function() { freeze(p); return {set: function(){}} },
   2022     fix: function() { return {} }
   2023   }
   2024   var p = create(handler)
   2025   var o = Object.create(p)
   2026   // Freeze while setting a property in prototype, dropping the property!
   2027   try { o.x = 4 } catch (e) { assertInstanceof(e, Error) }
   2028 })
   2029 
   2030 TestReentrantFix(function(create, freeze) {
   2031   var handler = {
   2032     getPropertyDescriptor: function() { freeze(p); return {set: function(){}} },
   2033     fix: function() { return {x: {get: function(){}}} }
   2034   }
   2035   var p = create(handler)
   2036   var o = Object.create(p)
   2037   // Freeze while setting a property in prototype, making it read-only!
   2038   try { o.x = 4 } catch (e) { assertInstanceof(e, Error) }
   2039 })
   2040 
   2041 TestReentrantFix(function(create, freeze) {
   2042   var handler = {
   2043     get fix() { freeze(p); return function(){} }
   2044   }
   2045   var p = create(handler)
   2046   // Freeze while getting fix trap.
   2047   try { Object.freeze(p) } catch (e) { assertInstanceof(e, Error) }
   2048   p = create(handler)
   2049   try { Object.seal(p) } catch (e) { assertInstanceof(e, Error) }
   2050   p = create(handler)
   2051   try { Object.preventExtensions(p) } catch (e) { assertInstanceof(e, Error) }
   2052 })
   2053 
   2054 TestReentrantFix(function(create, freeze) {
   2055   var handler = {
   2056     fix: function() { freeze(p); return {} }
   2057   }
   2058   var p = create(handler)
   2059   // Freeze while executing fix trap.
   2060   try { Object.freeze(p) } catch (e) { assertInstanceof(e, Error) }
   2061   p = create(handler)
   2062   try { Object.seal(p) } catch (e) { assertInstanceof(e, Error) }
   2063   p = create(handler)
   2064   try { Object.preventExtensions(p) } catch (e) { assertInstanceof(e, Error) }
   2065 })
   2066 
   2067 
   2068 
   2069 // String conversion (Object.prototype.toString,
   2070 //                    Object.prototype.toLocaleString,
   2071 //                    Function.prototype.toString)
   2072 
   2073 var key
   2074 
   2075 function TestToString(handler) {
   2076   var p = Proxy.create(handler)
   2077   key = ""
   2078   assertEquals("[object Object]", Object.prototype.toString.call(p))
   2079   assertEquals("", key)
   2080   assertEquals("my_proxy", Object.prototype.toLocaleString.call(p))
   2081   assertEquals("toString", key)
   2082 
   2083   var f = Proxy.createFunction(handler, function() {})
   2084   key = ""
   2085   assertEquals("[object Function]", Object.prototype.toString.call(f))
   2086   assertEquals("", key)
   2087   assertEquals("my_proxy", Object.prototype.toLocaleString.call(f))
   2088   assertEquals("toString", key)
   2089   assertDoesNotThrow(function(){ Function.prototype.toString.call(f) })
   2090 
   2091   var o = Object.create(p)
   2092   key = ""
   2093   assertEquals("[object Object]", Object.prototype.toString.call(o))
   2094   assertEquals("", key)
   2095   assertEquals("my_proxy", Object.prototype.toLocaleString.call(o))
   2096   assertEquals("toString", key)
   2097 }
   2098 
   2099 TestToString({
   2100   get: function(r, k) { key = k; return function() { return "my_proxy" } }
   2101 })
   2102 
   2103 TestToString({
   2104   get: function(r, k) { return this.get2(r, k) },
   2105   get2: function(r, k) { key = k; return function() { return "my_proxy" } }
   2106 })
   2107 
   2108 TestToString(Proxy.create({
   2109   get: function(pr, pk) {
   2110     return function(r, k) { key = k; return function() { return "my_proxy" } }
   2111   }
   2112 }))
   2113 
   2114 
   2115 function TestToStringThrow(handler) {
   2116   var p = Proxy.create(handler)
   2117   assertEquals("[object Object]", Object.prototype.toString.call(p))
   2118   assertThrows(function(){ Object.prototype.toLocaleString.call(p) }, "myexn")
   2119 
   2120   var f = Proxy.createFunction(handler, function() {})
   2121   assertEquals("[object Function]", Object.prototype.toString.call(f))
   2122   assertThrows(function(){ Object.prototype.toLocaleString.call(f) }, "myexn")
   2123 
   2124   var o = Object.create(p)
   2125   assertEquals("[object Object]", Object.prototype.toString.call(o))
   2126   assertThrows(function(){ Object.prototype.toLocaleString.call(o) }, "myexn")
   2127 }
   2128 
   2129 TestToStringThrow({
   2130   get: function(r, k) { throw "myexn" }
   2131 })
   2132 
   2133 TestToStringThrow({
   2134   get: function(r, k) { return function() { throw "myexn" } }
   2135 })
   2136 
   2137 TestToStringThrow({
   2138   get: function(r, k) { return this.get2(r, k) },
   2139   get2: function(r, k) { throw "myexn" }
   2140 })
   2141 
   2142 TestToStringThrow(Proxy.create({
   2143   get: function(pr, pk) { throw "myexn" }
   2144 }))
   2145 
   2146 TestToStringThrow(Proxy.create({
   2147   get: function(pr, pk) {
   2148     return function(r, k) { throw "myexn" }
   2149   }
   2150 }))
   2151 
   2152 
   2153 
   2154 // Value conversion (Object.prototype.toValue)
   2155 
   2156 function TestValueOf(handler) {
   2157   TestWithProxies(TestValueOf2, handler)
   2158 }
   2159 
   2160 function TestValueOf2(create, handler) {
   2161   var p = create(handler)
   2162   assertSame(p, Object.prototype.valueOf.call(p))
   2163 }
   2164 
   2165 TestValueOf({})
   2166 
   2167 
   2168 
   2169 // Enumerability (Object.prototype.propertyIsEnumerable)
   2170 
   2171 var key
   2172 
   2173 function TestIsEnumerable(handler) {
   2174   TestWithProxies(TestIsEnumerable2, handler)
   2175 }
   2176 
   2177 function TestIsEnumerable2(create, handler) {
   2178   var p = create(handler)
   2179   assertTrue(Object.prototype.propertyIsEnumerable.call(p, "a"))
   2180   assertEquals("a", key)
   2181   assertTrue(Object.prototype.propertyIsEnumerable.call(p, 2))
   2182   assertEquals("2", key)
   2183   assertFalse(Object.prototype.propertyIsEnumerable.call(p, "z"))
   2184   assertEquals("z", key)
   2185 
   2186   var o = Object.create(p)
   2187   key = ""
   2188   assertFalse(Object.prototype.propertyIsEnumerable.call(o, "a"))
   2189   assertEquals("", key)  // trap not invoked
   2190 }
   2191 
   2192 TestIsEnumerable({
   2193   getOwnPropertyDescriptor: function(k) {
   2194     key = k; return {enumerable: k < "z", configurable: true}
   2195   },
   2196 })
   2197 
   2198 TestIsEnumerable({
   2199   getOwnPropertyDescriptor: function(k) {
   2200     return this.getOwnPropertyDescriptor2(k)
   2201   },
   2202   getOwnPropertyDescriptor2: function(k) {
   2203     key = k; return {enumerable: k < "z", configurable: true}
   2204   },
   2205 })
   2206 
   2207 TestIsEnumerable({
   2208   getOwnPropertyDescriptor: function(k) {
   2209     key = k; return {get enumerable() { return k < "z" }, configurable: true}
   2210   },
   2211 })
   2212 
   2213 TestIsEnumerable(Proxy.create({
   2214   get: function(pr, pk) {
   2215     return function(k) {
   2216       key = k; return {enumerable: k < "z", configurable: true}
   2217     }
   2218   }
   2219 }))
   2220 
   2221 
   2222 function TestIsEnumerableThrow(handler) {
   2223   TestWithProxies(TestIsEnumerableThrow2, handler)
   2224 }
   2225 
   2226 function TestIsEnumerableThrow2(create, handler) {
   2227   var p = create(handler)
   2228   assertThrows(function(){ Object.prototype.propertyIsEnumerable.call(p, "a") },
   2229     "myexn")
   2230   assertThrows(function(){ Object.prototype.propertyIsEnumerable.call(p, 11) },
   2231     "myexn")
   2232 }
   2233 
   2234 TestIsEnumerableThrow({
   2235   getOwnPropertyDescriptor: function(k) { throw "myexn" }
   2236 })
   2237 
   2238 TestIsEnumerableThrow({
   2239   getOwnPropertyDescriptor: function(k) {
   2240     return this.getOwnPropertyDescriptor2(k)
   2241   },
   2242   getOwnPropertyDescriptor2: function(k) { throw "myexn" }
   2243 })
   2244 
   2245 TestIsEnumerableThrow({
   2246   getOwnPropertyDescriptor: function(k) {
   2247     return {get enumerable() { throw "myexn" }, configurable: true}
   2248   },
   2249 })
   2250 
   2251 TestIsEnumerableThrow(Proxy.create({
   2252   get: function(pr, pk) { throw "myexn" }
   2253 }))
   2254 
   2255 TestIsEnumerableThrow(Proxy.create({
   2256   get: function(pr, pk) {
   2257     return function(k) { throw "myexn" }
   2258   }
   2259 }))
   2260 
   2261 
   2262 
   2263 // Constructor functions with proxy prototypes.
   2264 
   2265 function TestConstructorWithProxyPrototype() {
   2266   TestWithProxies(TestConstructorWithProxyPrototype2, {})
   2267 }
   2268 
   2269 function TestConstructorWithProxyPrototype2(create, handler) {
   2270   function C() {};
   2271   C.prototype = create(handler);
   2272 
   2273   var o = new C;
   2274   assertSame(C.prototype, o.__proto__);
   2275   assertSame(C.prototype, Object.getPrototypeOf(o));
   2276 }
   2277 
   2278 TestConstructorWithProxyPrototype();
   2279