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// We change the stack size for the ARM64 simulator because at one point this
29// test enters an infinite recursion which goes through the runtime and we
30// overflow the system stack before the simulator stack.
31
32// Flags: --sim-stack-size=500 --allow-natives-syntax
33
34
35// Helper.
36
37function TestWithProxies(test, x, y, z) {
38  // Separate function for nicer stack traces.
39  TestWithObjectProxy(test, x, y, z);
40  TestWithFunctionProxy(test, x, y, z);
41}
42
43function TestWithObjectProxy(test, x, y, z) {
44  test((handler) => { return new Proxy({}, handler) }, x, y, z)
45
46}
47
48function TestWithFunctionProxy(test, x, y, z) {
49  test((handler) => { return new Proxy(() => {}, handler) }, x, y, z)
50}
51
52// ---------------------------------------------------------------------------
53// Getting property descriptors (Object.getOwnPropertyDescriptor).
54
55var key
56
57function TestGetOwnProperty(handler) {
58  TestWithProxies(TestGetOwnProperty2, handler)
59}
60
61function TestGetOwnProperty2(create, handler) {
62  var p = create(handler)
63  assertEquals(42, Object.getOwnPropertyDescriptor(p, "a").value)
64  assertEquals("a", key)
65  assertEquals(42, Object.getOwnPropertyDescriptor(p, 99).value)
66  assertEquals("99", key)
67}
68
69TestGetOwnProperty({
70  getOwnPropertyDescriptor(target, k) {
71    key = k
72    return {value: 42, configurable: true}
73  }
74})
75
76TestGetOwnProperty({
77  getOwnPropertyDescriptor(target, k) {
78    return this.getOwnPropertyDescriptor2(k)
79  },
80  getOwnPropertyDescriptor2(k) {
81    key = k
82    return {value: 42, configurable: true}
83  }
84})
85
86TestGetOwnProperty({
87  getOwnPropertyDescriptor(target, k) {
88    key = k
89    return {get value() { return 42 }, get configurable() { return true }}
90  }
91})
92
93TestGetOwnProperty(new Proxy({}, {
94  get(target, pk, receiver) {
95    return function(t, k) { key = k; return {value: 42, configurable: true} }
96  }
97}))
98
99
100// ---------------------------------------------------------------------------
101function TestGetOwnPropertyThrow(handler) {
102  TestWithProxies(TestGetOwnPropertyThrow2, handler)
103}
104
105function TestGetOwnPropertyThrow2(create, handler) {
106  var p = create(handler)
107  assertThrowsEquals(() => Object.getOwnPropertyDescriptor(p, "a"), "myexn")
108  assertThrowsEquals(() => Object.getOwnPropertyDescriptor(p, 77), "myexn")
109}
110
111TestGetOwnPropertyThrow({
112  getOwnPropertyDescriptor: function(k) { throw "myexn" }
113})
114
115TestGetOwnPropertyThrow({
116  getOwnPropertyDescriptor: function(k) {
117    return this.getOwnPropertyDescriptor2(k)
118  },
119  getOwnPropertyDescriptor2: function(k) { throw "myexn" }
120})
121
122TestGetOwnPropertyThrow({
123  getOwnPropertyDescriptor: function(k) {
124    return {get value() { throw "myexn" }}
125  }
126})
127
128TestGetOwnPropertyThrow(new Proxy({}, {
129  get: function(pr, pk) {
130    return function(k) { throw "myexn" }
131  }
132}))
133
134
135// ---------------------------------------------------------------------------
136// Getters (dot, brackets).
137
138var key
139
140function TestGet(handler) {
141  TestWithProxies(TestGet2, handler)
142}
143
144function TestGet2(create, handler) {
145  var p = create(handler)
146  assertEquals(42, p.a)
147  assertEquals("a", key)
148  assertEquals(42, p["b"])
149  assertEquals("b", key)
150  assertEquals(42, p[99])
151  assertEquals("99", key)
152  assertEquals(42, (function(n) { return p[n] })("c"))
153  assertEquals("c", key)
154  assertEquals(42, (function(n) { return p[n] })(101))
155  assertEquals("101", key)
156
157  var o = Object.create(p, {x: {value: 88}})
158  assertEquals(42, o.a)
159  assertEquals("a", key)
160  assertEquals(42, o["b"])
161  assertEquals("b", key)
162  assertEquals(42, o[99])
163  assertEquals("99", key)
164  assertEquals(88, o.x)
165  assertEquals(88, o["x"])
166  assertEquals(42, (function(n) { return o[n] })("c"))
167  assertEquals("c", key)
168  assertEquals(42, (function(n) { return o[n] })(101))
169  assertEquals("101", key)
170  assertEquals(88, (function(n) { return o[n] })("x"))
171}
172
173TestGet({
174  get(t, k, r) { key = k; return 42 }
175})
176
177TestGet({
178  get(t, k, r) { return this.get2(r, k) },
179  get2(r, k) { key = k; return 42 }
180})
181
182TestGet(new Proxy({}, {
183  get(pt, pk, pr) {
184    return function(t, k, r) { key = k; return 42 }
185  }
186}))
187
188
189// ---------------------------------------------------------------------------
190function TestGetCall(handler) {
191  TestWithProxies(TestGetCall2, handler)
192}
193
194function TestGetCall2(create, handler) {
195  var p = create(handler)
196  assertEquals(55, p.f())
197  assertEquals(55, p["f"]())
198  assertEquals(55, p.f("unused", "arguments"))
199  assertEquals(55, p.f.call(p))
200  assertEquals(55, p["f"].call(p))
201  assertEquals(55, p[101].call(p))
202  assertEquals(55, p.withargs(45, 5))
203  assertEquals(55, p.withargs.call(p, 11, 22))
204  assertEquals(55, (function(n) { return p[n]() })("f"))
205  assertEquals(55, (function(n) { return p[n].call(p) })("f"))
206  assertEquals(55, (function(n) { return p[n](15, 20) })("withargs"))
207  assertEquals(55, (function(n) { return p[n].call(p, 13, 21) })("withargs"))
208  assertEquals("6655", "66" + p)  // calls p.toString
209
210  var o = Object.create(p, {g: {value: function(x) { return x + 88 }}})
211  assertEquals(55, o.f())
212  assertEquals(55, o["f"]())
213  assertEquals(55, o.f("unused", "arguments"))
214  assertEquals(55, o.f.call(o))
215  assertEquals(55, o.f.call(p))
216  assertEquals(55, o["f"].call(p))
217  assertEquals(55, o[101].call(p))
218  assertEquals(55, o.withargs(45, 5))
219  assertEquals(55, o.withargs.call(p, 11, 22))
220  assertEquals(90, o.g(2))
221  assertEquals(91, o.g.call(o, 3))
222  assertEquals(92, o.g.call(p, 4))
223  assertEquals(55, (function(n) { return o[n]() })("f"))
224  assertEquals(55, (function(n) { return o[n].call(o) })("f"))
225  assertEquals(55, (function(n) { return o[n](15, 20) })("withargs"))
226  assertEquals(55, (function(n) { return o[n].call(o, 13, 21) })("withargs"))
227  assertEquals(93, (function(n) { return o[n](5) })("g"))
228  assertEquals(94, (function(n) { return o[n].call(o, 6) })("g"))
229  assertEquals(95, (function(n) { return o[n].call(p, 7) })("g"))
230  assertEquals("6655", "66" + o)  // calls o.toString
231}
232
233TestGetCall({
234  get(t, k, r) { return () => { return 55 } }
235})
236
237TestGetCall({
238  get(t, k, r)  { return this.get2(t, k, r) },
239  get2(t, k, r) { return () => { return 55 } }
240})
241
242TestGetCall({
243  get(t, k, r) {
244    if (k == "gg") {
245      return () => { return 55 }
246    } else if (k == "withargs") {
247      return (n, m) => { return n + m * 2 }
248    } else {
249      return () => { return r.gg() }
250    }
251  }
252})
253
254TestGetCall(new Proxy({}, {
255  get(pt, pk, pr) {
256    return (t, k, r) => { return () => { return 55 } }
257  }
258}))
259
260
261// ---------------------------------------------------------------------------
262function TestGetThrow(handler) {
263  TestWithProxies(TestGetThrow2, handler)
264}
265
266function TestGetThrow2(create, handler) {
267  var p = create(handler)
268  assertThrowsEquals(function(){ p.a }, "myexn")
269  assertThrowsEquals(function(){ p["b"] }, "myexn")
270  assertThrowsEquals(function(){ p[3] }, "myexn")
271  assertThrowsEquals(function(){ (function(n) { p[n] })("c") }, "myexn")
272  assertThrowsEquals(function(){ (function(n) { p[n] })(99) }, "myexn")
273
274  var o = Object.create(p, {x: {value: 88}, '4': {value: 89}})
275  assertThrowsEquals(function(){ o.a }, "myexn")
276  assertThrowsEquals(function(){ o["b"] }, "myexn")
277  assertThrowsEquals(function(){ o[3] }, "myexn")
278  assertThrowsEquals(function(){ (function(n) { o[n] })("c") }, "myexn")
279  assertThrowsEquals(function(){ (function(n) { o[n] })(99) }, "myexn")
280}
281
282TestGetThrow({
283  get(r, k) { throw "myexn" }
284})
285
286TestGetThrow({
287  get(r, k) { return this.get2(r, k) },
288  get2(r, k) { throw "myexn" }
289})
290
291TestGetThrow(new Proxy({}, {
292  get(pr, pk) { throw "myexn" }
293}))
294
295TestGetThrow(new Proxy({}, {
296  get(pr, pk) {
297    return function(r, k) { throw "myexn" }
298  }
299}))
300
301
302// ---------------------------------------------------------------------------
303// Setters.
304
305var key
306var val
307
308function TestSet(handler) {
309  TestWithProxies(TestSet2, handler)
310}
311
312function TestSet2(create, handler) {
313  var p = create(handler)
314  assertEquals(42, p.a = 42)
315  assertEquals("a", key)
316  assertEquals(42, val)
317  assertEquals(43, p["b"] = 43)
318  assertEquals("b", key)
319  assertEquals(43, val)
320  assertEquals(44, p[77] = 44)
321  assertEquals("77", key)
322  assertEquals(44, val)
323
324  assertEquals(45, (function(n) { return p[n] = 45 })("c"))
325  assertEquals("c", key)
326  assertEquals(45, val)
327  assertEquals(46, (function(n) { return p[n] = 46 })(99))
328  assertEquals("99", key)
329  assertEquals(46, val)
330
331  assertEquals(47, p["0"] = 47)
332  assertEquals("0", key)
333  assertEquals(47, val)
334}
335
336TestSet({
337  set: function(r, k, v) { key = k; val = v; return true }
338})
339
340TestSet({
341  set: function(r, k, v) { return this.set2(r, k, v) },
342  set2: function(r, k, v) { key = k; val = v; return true }
343})
344
345TestSet(new Proxy({}, {
346  get(pk, pr) {
347    return (r, k, v) => { key = k; val = v; return true }
348  }
349}))
350
351
352// ---------------------------------------------------------------------------
353function TestSetThrow(handler) {
354  TestWithProxies(TestSetThrow2, handler)
355}
356
357function TestSetThrow2(create, handler) {
358  var p = create(handler)
359  assertThrowsEquals(function(){ p.a = 42 }, "myexn")
360  assertThrowsEquals(function(){ p["b"] = 42 }, "myexn")
361  assertThrowsEquals(function(){ p[22] = 42 }, "myexn")
362  assertThrowsEquals(function(){ (function(n) { p[n] = 45 })("c") }, "myexn")
363  assertThrowsEquals(function(){ (function(n) { p[n] = 46 })(99) }, "myexn")
364}
365
366TestSetThrow({
367  set: function(r, k, v) { throw "myexn" }
368})
369
370TestSetThrow({
371  set: function(r, k, v) { return this.set2(r, k, v) },
372  set2: function(r, k, v) { throw "myexn" }
373})
374
375TestSetThrow({
376  getOwnPropertyDescriptor: function(k) { throw "myexn" },
377  defineProperty: function(k, desc) { key = k; val = desc.value }
378})
379
380TestSetThrow({
381  getOwnPropertyDescriptor: function(k) {
382    return {configurable: true, writable: true}
383  },
384  defineProperty: function(k, desc) { throw "myexn" }
385})
386
387TestSetThrow({
388  getOwnPropertyDescriptor: function(k) {
389    return this.getOwnPropertyDescriptor2(k)
390  },
391  getOwnPropertyDescriptor2: function(k) { throw "myexn" },
392  defineProperty: function(k, desc) { this.defineProperty2(k, desc) },
393  defineProperty2: function(k, desc) { key = k; val = desc.value }
394})
395
396TestSetThrow({
397  getOwnPropertyDescriptor: function(k) {
398    return this.getOwnPropertyDescriptor2(k)
399  },
400  getOwnPropertyDescriptor2: function(k) {
401    return {configurable: true, writable: true}
402  },
403  defineProperty: function(k, desc) { this.defineProperty2(k, desc) },
404  defineProperty2: function(k, desc) { throw "myexn" }
405})
406
407TestSetThrow({
408  getOwnPropertyDescriptor: function(k) { throw "myexn" },
409  defineProperty: function(k, desc) { key = k; val = desc.value }
410})
411
412TestSetThrow({
413  getOwnPropertyDescriptor: function(k) {
414    return {
415      get configurable() { return true },
416      get writable() { return true }
417    }
418  },
419  defineProperty: function(k, desc) { throw "myexn" }
420})
421
422TestSetThrow({
423  getOwnPropertyDescriptor: function(k) { throw "myexn" }
424})
425
426TestSetThrow({
427  getOwnPropertyDescriptor: function(k) { throw "myexn" },
428  defineProperty: function(k, desc) { key = k; val = desc.value }
429})
430
431TestSetThrow(new Proxy({}, {
432  get: function(pr, pk) { throw "myexn" }
433}))
434
435TestSetThrow(new Proxy({}, {
436  get: function(pr, pk) {
437    return function(r, k, v) { throw "myexn" }
438  }
439}))
440
441// ---------------------------------------------------------------------------
442
443// Evil proxy-induced side-effects shouldn't crash.
444TestWithProxies(function(create) {
445  var calls = 0
446  var handler = {
447    getPropertyDescriptor: function() {
448      ++calls
449      return (calls % 2 == 1)
450        ? {get: function() { return 5 }, configurable: true}
451        : {set: function() { return false }, configurable: true}
452    }
453  }
454  var p = create(handler)
455  var o = Object.create(p)
456  // Make proxy prototype property read-only after CanPut check.
457  try { o.x = 4 } catch (e) { assertInstanceof(e, Error) }
458})
459
460TestWithProxies(function(create) {
461  var handler = {
462    getPropertyDescriptor: function() {
463      Object.defineProperty(o, "x", {get: function() { return 5 }});
464      return {set: function() {}}
465    }
466  }
467  var p = create(handler)
468  var o = Object.create(p)
469  // Make object property read-only after CanPut check.
470  try { o.x = 4 } catch (e) { assertInstanceof(e, Error) }
471})
472
473
474// ---------------------------------------------------------------------------
475// Property definition (Object.defineProperty and Object.defineProperties).
476
477var key
478var desc
479
480function TestDefine(handler) {
481  TestWithProxies(TestDefine2, handler)
482}
483
484function TestDefine2(create, handler) {
485  var p = create(handler)
486  assertEquals(p, Object.defineProperty(p, "a", {value: 44}))
487  assertEquals("a", key)
488  assertEquals(1, Object.getOwnPropertyNames(desc).length)
489  assertEquals(44, desc.value)
490
491  assertEquals(p, Object.defineProperty(p, "b", {value: 45, writable: false}))
492  assertEquals("b", key)
493  assertEquals(2, Object.getOwnPropertyNames(desc).length)
494  assertEquals(45, desc.value)
495  assertEquals(false, desc.writable)
496
497  assertEquals(p, Object.defineProperty(p, "c", {value: 46, enumerable: false}))
498  assertEquals("c", key)
499  assertEquals(2, Object.getOwnPropertyNames(desc).length)
500  assertEquals(46, desc.value)
501  assertEquals(false, desc.enumerable)
502
503  assertEquals(p, Object.defineProperty(p, 101, {value: 47, enumerable: false}))
504  assertEquals("101", key)
505  assertEquals(2, Object.getOwnPropertyNames(desc).length)
506  assertEquals(47, desc.value)
507  assertEquals(false, desc.enumerable)
508
509  var attributes = {configurable: true, mine: 66, minetoo: 23}
510  assertEquals(p, Object.defineProperty(p, "d", attributes))
511  assertEquals("d", key);
512  // Modifying the attributes object after the fact should have no effect.
513  attributes.configurable = false
514  attributes.mine = 77
515  delete attributes.minetoo;
516  assertEquals(1, Object.getOwnPropertyNames(desc).length)
517  assertEquals(true, desc.configurable)
518  assertEquals(undefined, desc.mine)
519  assertEquals(undefined, desc.minetoo)
520
521  assertEquals(p, Object.defineProperty(p, "e", {get: function(){ return 5 }}))
522  assertEquals("e", key)
523  assertEquals(1, Object.getOwnPropertyNames(desc).length)
524  assertEquals(5, desc.get())
525
526  assertEquals(p, Object.defineProperty(p, "zzz", {}))
527  assertEquals("zzz", key)
528  assertEquals(0, Object.getOwnPropertyNames(desc).length)
529
530  var props = {
531    '11': {},
532    blub: {get: function() { return true }},
533    '': {get value() { return 20 }},
534    last: {value: 21, configurable: true, mine: "eyes"}
535  }
536  Object.defineProperty(props, "hidden", {value: "hidden", enumerable: false})
537  assertEquals(p, Object.defineProperties(p, props))
538  assertEquals("last", key)
539  assertEquals(2, Object.getOwnPropertyNames(desc).length)
540  assertEquals(21, desc.value)
541  assertEquals(true, desc.configurable)
542  assertEquals(undefined, desc.mine)  // Arguably a bug in the spec...
543
544  var props = {bla: {get value() { throw "myexn" }}}
545  assertThrowsEquals(function(){ Object.defineProperties(p, props) }, "myexn")
546}
547
548TestDefine({
549  defineProperty(t, k, d) { key = k; desc = d; return true }
550})
551
552TestDefine({
553  defineProperty(t, k, d) { return this.defineProperty2(k, d) },
554  defineProperty2(k, d) { key = k; desc = d; return true }
555})
556
557
558// ---------------------------------------------------------------------------
559function TestDefineThrow(handler) {
560  TestWithProxies(TestDefineThrow2, handler)
561}
562
563function TestDefineThrow2(create, handler) {
564  var p = create(handler)
565  assertThrowsEquals(() => Object.defineProperty(p, "a", {value: 44}), "myexn")
566  assertThrowsEquals(() => Object.defineProperty(p, 0, {value: 44}), "myexn")
567
568  var d1 = create({
569    get: function(r, k) { throw "myexn" },
570    getOwnPropertyNames: function() { return ["value"] }
571  })
572  assertThrowsEquals(function(){ Object.defineProperty(p, "p", d1) }, "myexn")
573  var d2 = create({
574    get: function(r, k) { return 77 },
575    getOwnPropertyNames: function() { throw "myexn" }
576  })
577  assertThrowsEquals(function(){ Object.defineProperty(p, "p", d2) }, "myexn")
578
579  var props = {bla: {get value() { throw "otherexn" }}}
580  assertThrowsEquals(() => Object.defineProperties(p, props), "otherexn")
581}
582
583TestDefineThrow({
584  defineProperty: function(k, d) { throw "myexn" }
585})
586
587TestDefineThrow({
588  defineProperty: function(k, d) { return this.defineProperty2(k, d) },
589  defineProperty2: function(k, d) { throw "myexn" }
590})
591
592TestDefineThrow(new Proxy({}, {
593  get: function(pr, pk) { throw "myexn" }
594}))
595
596TestDefineThrow(new Proxy({}, {
597  get: function(pr, pk) {
598    return function(k, d) { throw "myexn" }
599  }
600}))
601
602
603
604// ---------------------------------------------------------------------------
605// Property deletion (delete).
606
607var key
608
609function TestDelete(handler) {
610  TestWithProxies(TestDelete2, handler)
611}
612
613function TestDelete2(create, handler) {
614  var p = create(handler)
615  assertEquals(true, delete p.a)
616  assertEquals("a", key)
617  assertEquals(true, delete p["b"])
618  assertEquals("b", key)
619  assertEquals(true, delete p[1])
620  assertEquals("1", key)
621
622  assertEquals(false, delete p.z1)
623  assertEquals("z1", key)
624  assertEquals(false, delete p["z2"])
625  assertEquals("z2", key);
626
627  (function() {
628    "use strict"
629    assertEquals(true, delete p.c)
630    assertEquals("c", key)
631    assertEquals(true, delete p["d"])
632    assertEquals("d", key)
633    assertEquals(true, delete p[2])
634    assertEquals("2", key)
635
636    assertThrows(function(){ delete p.z3 }, TypeError)
637    assertEquals("z3", key)
638    assertThrows(function(){ delete p["z4"] }, TypeError)
639    assertEquals("z4", key)
640  })()
641}
642
643TestDelete({
644  deleteProperty(target, k) { key = k; return k < "z" }
645})
646
647TestDelete({
648  deleteProperty(target, k) { return this.delete2(k) },
649  delete2: function(k) { key = k; return k < "z" }
650})
651
652TestDelete(new Proxy({}, {
653  get(pt, pk, pr) {
654    return (target, k) => { key = k; return k < "z" }
655  }
656}))
657
658
659// ---------------------------------------------------------------------------
660function TestDeleteThrow(handler) {
661  TestWithProxies(TestDeleteThrow2, handler)
662}
663
664function TestDeleteThrow2(create, handler) {
665  var p = create(handler)
666  assertThrowsEquals(function(){ delete p.a }, "myexn")
667  assertThrowsEquals(function(){ delete p["b"] }, "myexn");
668  assertThrowsEquals(function(){ delete p[3] }, "myexn");
669
670  (function() {
671    "use strict"
672    assertThrowsEquals(function(){ delete p.c }, "myexn")
673    assertThrowsEquals(function(){ delete p["d"] }, "myexn")
674    assertThrowsEquals(function(){ delete p[4] }, "myexn");
675  })()
676}
677
678TestDeleteThrow({
679  deleteProperty(t, k) { throw "myexn" }
680})
681
682TestDeleteThrow({
683  deleteProperty(t, k) { return this.delete2(k) },
684  delete2(k) { throw "myexn" }
685})
686
687TestDeleteThrow(new Proxy({}, {
688  get(pt, pk, pr) { throw "myexn" }
689}))
690
691TestDeleteThrow(new Proxy({}, {
692  get(pt, pk, pr) {
693    return (k) => { throw "myexn" }
694  }
695}))
696
697
698// ---------------------------------------------------------------------------
699// Property descriptors (Object.getOwnPropertyDescriptor).
700
701function TestDescriptor(handler) {
702  TestWithProxies(TestDescriptor2, handler)
703}
704
705function TestDescriptor2(create, handler) {
706  var p = create(handler)
707  var descs = [
708    {configurable: true},
709    {value: 34, enumerable: true, configurable: true},
710    {value: 3, writable: false, mine: "eyes", configurable: true},
711    {get value() { return 20 }, get configurable() { return true }},
712    {get: function() { "get" }, set: function() { "set" }, configurable: true}
713  ]
714  for (var i = 0; i < descs.length; ++i) {
715    assertEquals(p, Object.defineProperty(p, i, descs[i]))
716    var desc = Object.getOwnPropertyDescriptor(p, i)
717    for (prop in descs[i]) {
718      // TODO(rossberg): Ignore user attributes as long as the spec isn't
719      // fixed suitably.
720      if (prop != "mine") assertEquals(descs[i][prop], desc[prop])
721    }
722    assertEquals(undefined, Object.getOwnPropertyDescriptor(p, "absent"))
723  }
724}
725
726TestDescriptor({
727  defineProperty(t, k, d) { this["__" + k] = d; return true },
728  getOwnPropertyDescriptor(t, k) { return this["__" + k] }
729})
730
731TestDescriptor({
732  defineProperty(t, k, d) { this["__" + k] = d; return true },
733  getOwnPropertyDescriptor(t, k) {
734    return this.getOwnPropertyDescriptor2(k)
735  },
736  getOwnPropertyDescriptor2: function(k) { return this["__" + k] }
737})
738
739
740// ---------------------------------------------------------------------------
741function TestDescriptorThrow(handler) {
742  TestWithProxies(TestDescriptorThrow2, handler)
743}
744
745function TestDescriptorThrow2(create, handler) {
746  var p = create(handler)
747  assertThrowsEquals(() => Object.getOwnPropertyDescriptor(p, "a"), "myexn")
748}
749
750TestDescriptorThrow({
751  getOwnPropertyDescriptor: function(k) { throw "myexn" }
752})
753
754TestDescriptorThrow({
755  getOwnPropertyDescriptor: function(k) {
756    return this.getOwnPropertyDescriptor2(k)
757  },
758  getOwnPropertyDescriptor2: function(k) { throw "myexn" }
759})
760
761
762
763// ---------------------------------------------------------------------------
764// Comparison.
765
766function TestComparison(eq) {
767  TestWithProxies(TestComparison2, eq)
768}
769
770function TestComparison2(create, eq) {
771  var p1 = create({})
772  var p2 = create({})
773
774  assertTrue(eq(p1, p1))
775  assertTrue(eq(p2, p2))
776  assertTrue(!eq(p1, p2))
777  assertTrue(!eq(p1, {}))
778  assertTrue(!eq({}, p2))
779  assertTrue(!eq({}, {}))
780}
781
782TestComparison(function(o1, o2) { return o1 == o2 })
783TestComparison(function(o1, o2) { return o1 === o2 })
784TestComparison(function(o1, o2) { return !(o1 != o2) })
785TestComparison(function(o1, o2) { return !(o1 !== o2) })
786
787
788
789// Type (typeof).
790
791function TestTypeof() {
792  assertEquals("object", typeof new Proxy({},{}))
793  assertTrue(typeof new Proxy({}, {}) == "object")
794  assertTrue("object" == typeof new Proxy({},{}))
795
796  assertEquals("function", typeof new Proxy(function() {}, {}))
797  assertTrue(typeof new Proxy(function() {}, {}) == "function")
798  assertTrue("function" == typeof new Proxy(function() {},{}))
799}
800
801TestTypeof()
802
803
804
805// ---------------------------------------------------------------------------
806// Membership test (in).
807
808var key
809
810function TestIn(handler) {
811  TestWithProxies(TestIn2, handler)
812}
813
814function TestIn2(create, handler) {
815  var p = create(handler)
816  assertTrue("a" in p)
817  assertEquals("a", key)
818  assertTrue(99 in p)
819  assertEquals("99", key)
820  assertFalse("z" in p)
821  assertEquals("z", key)
822
823  assertEquals(2, ("a" in p) ? 2 : 0)
824  assertEquals(0, !("a" in p) ? 2 : 0)
825  assertEquals(0, ("zzz" in p) ? 2 : 0)
826  assertEquals(2, !("zzz" in p) ? 2 : 0)
827
828  // Test compilation in conditionals.
829  if ("b" in p) {
830  } else {
831    assertTrue(false)
832  }
833  assertEquals("b", key)
834
835  if ("zz" in p) {
836    assertTrue(false)
837  }
838  assertEquals("zz", key)
839
840  if (!("c" in p)) {
841    assertTrue(false)
842  }
843  assertEquals("c", key)
844
845  if (!("zzz" in p)) {
846  } else {
847    assertTrue(false)
848  }
849  assertEquals("zzz", key)
850}
851
852TestIn({
853  has(t, k) { key = k; return k < "z" }
854})
855
856TestIn({
857  has(t, k) { return this.has2(k) },
858  has2(k) { key = k; return k < "z" }
859})
860
861TestIn(new Proxy({},{
862  get(pt, pk, pr) {
863    return (t, k) => { key = k; return k < "z" }
864  }
865}))
866
867
868// ---------------------------------------------------------------------------
869function TestInThrow(handler) {
870  TestWithProxies(TestInThrow2, handler)
871}
872
873function TestInThrow2(create, handler) {
874  var p = create(handler)
875  assertThrowsEquals(function(){ return "a" in p }, "myexn")
876  assertThrowsEquals(function(){ return 99 in p }, "myexn")
877  assertThrowsEquals(function(){ return !("a" in p) }, "myexn")
878  assertThrowsEquals(function(){ return ("a" in p) ? 2 : 3 }, "myexn")
879  assertThrowsEquals(function(){ if ("b" in p) {} }, "myexn")
880  assertThrowsEquals(function(){ if (!("b" in p)) {} }, "myexn")
881  assertThrowsEquals(function(){ if ("zzz" in p) {} }, "myexn")
882}
883
884TestInThrow({
885  has: function(k) { throw "myexn" }
886})
887
888TestInThrow({
889  has: function(k) { return this.has2(k) },
890  has2: function(k) { throw "myexn" }
891})
892
893TestInThrow(new Proxy({},{
894  get: function(pr, pk) { throw "myexn" }
895}))
896
897TestInThrow(new Proxy({},{
898  get: function(pr, pk) {
899    return function(k) { throw "myexn" }
900  }
901}))
902
903
904
905// ---------------------------------------------------------------------------
906// Own Properties (Object.prototype.hasOwnProperty).
907
908var key
909
910function TestHasOwn(handler) {
911  TestWithProxies(TestHasOwn2, handler)
912}
913
914function TestHasOwn2(create, handler) {
915  var p = create(handler)
916  assertTrue(Object.prototype.hasOwnProperty.call(p, "a"))
917  assertEquals("a", key)
918  assertTrue(Object.prototype.hasOwnProperty.call(p, 99))
919  assertEquals("99", key)
920  assertFalse(Object.prototype.hasOwnProperty.call(p, "z"))
921  assertEquals("z", key)
922}
923
924TestHasOwn({
925  getOwnPropertyDescriptor(t, k) {
926    key = k; if (k < "z") return {configurable: true}
927  },
928  has() { assertUnreachable() }
929})
930
931TestHasOwn({
932  getOwnPropertyDescriptor(t, k) { return this.getOwnPropertyDescriptor2(k) },
933  getOwnPropertyDescriptor2(k) {
934    key = k; if (k < "z") return {configurable: true}
935  }
936})
937
938
939
940// ---------------------------------------------------------------------------
941function TestHasOwnThrow(handler) {
942  TestWithProxies(TestHasOwnThrow2, handler)
943}
944
945function TestHasOwnThrow2(create, handler) {
946  var p = create(handler)
947  assertThrowsEquals(function(){ Object.prototype.hasOwnProperty.call(p, "a")},
948    "myexn")
949  assertThrowsEquals(function(){ Object.prototype.hasOwnProperty.call(p, 99)},
950    "myexn")
951}
952
953TestHasOwnThrow({
954  getOwnPropertyDescriptor(t, k) { throw "myexn" }
955})
956
957TestHasOwnThrow({
958  getOwnPropertyDescriptor(t, k) { return this.getOwnPropertyDescriptor2(k) },
959  getOwnPropertyDescriptor2(k) { throw "myexn" }
960});
961
962
963// ---------------------------------------------------------------------------
964// Instanceof (instanceof)
965
966(function TestProxyInstanceof() {
967  var o1 = {}
968  var p1 = new Proxy({}, {})
969  var p2 = new Proxy(o1, {})
970  var p3 = new Proxy(p2, {})
971  var o2 = Object.create(p2)
972
973  var f0 = function() {}
974  f0.prototype = o1
975  var f1 = function() {}
976  f1.prototype = p1
977  var f2 = function() {}
978  f2.prototype = p2
979  var f3 = function() {}
980  f3.prototype = o2
981
982  assertTrue(o1 instanceof Object)
983  assertFalse(o1 instanceof f0)
984  assertFalse(o1 instanceof f1)
985  assertFalse(o1 instanceof f2)
986  assertFalse(o1 instanceof f3)
987  assertTrue(p1 instanceof Object)
988  assertFalse(p1 instanceof f0)
989  assertFalse(p1 instanceof f1)
990  assertFalse(p1 instanceof f2)
991  assertFalse(p1 instanceof f3)
992  assertTrue(p2 instanceof Object)
993  assertFalse(p2 instanceof f0)
994  assertFalse(p2 instanceof f1)
995  assertFalse(p2 instanceof f2)
996  assertFalse(p2 instanceof f3)
997  assertTrue(p3 instanceof Object)
998  assertFalse(p3 instanceof f0)
999  assertFalse(p3 instanceof f1)
1000  assertFalse(p3 instanceof f2)
1001  assertFalse(p3 instanceof f3)
1002  assertTrue(o2 instanceof Object)
1003  assertFalse(o2 instanceof f0)
1004  assertFalse(o2 instanceof f1)
1005  assertTrue(o2 instanceof f2)
1006  assertFalse(o2 instanceof f3)
1007
1008  var f = new Proxy(function() {}, {})
1009  assertTrue(f instanceof Function)
1010})();
1011
1012
1013(function TestInstanceofProxy() {
1014  var o0 = Object.create(null)
1015  var o1 = {}
1016  var o2 = Object.create(o0)
1017  var o3 = Object.create(o1)
1018  var o4 = Object.create(o2)
1019  var o5 = Object.create(o3)
1020
1021  function handler(o) {
1022    return {
1023      get: function(r, p) {
1024        // We want to test prototype lookup, so ensure the proxy
1025        // offers OrdinaryHasInstance behavior.
1026        if (p === Symbol.hasInstance) {
1027          return undefined;
1028        }
1029        return o;
1030      }
1031    }
1032  }
1033
1034  var f0 = new Proxy(function() {}, handler(o0))
1035  var f1 = new Proxy(function() {}, handler(o1))
1036  var f2 = new Proxy(function() {}, handler(o2))
1037  var f3 = new Proxy(function() {}, handler(o3))
1038  var f4 = new Proxy(function() {}, handler(o4))
1039  var f5 = new Proxy(function() {}, handler(o4))
1040
1041  assertFalse(null instanceof f0)
1042  assertFalse(o0 instanceof f0)
1043  assertFalse(o0 instanceof f1)
1044  assertFalse(o0 instanceof f2)
1045  assertFalse(o0 instanceof f3)
1046  assertFalse(o0 instanceof f4)
1047  assertFalse(o0 instanceof f5)
1048  assertFalse(o1 instanceof f0)
1049  assertFalse(o1 instanceof f1)
1050  assertFalse(o1 instanceof f2)
1051  assertFalse(o1 instanceof f3)
1052  assertFalse(o1 instanceof f4)
1053  assertFalse(o1 instanceof f5)
1054  assertTrue(o2 instanceof f0)
1055  assertFalse(o2 instanceof f1)
1056  assertFalse(o2 instanceof f2)
1057  assertFalse(o2 instanceof f3)
1058  assertFalse(o2 instanceof f4)
1059  assertFalse(o2 instanceof f5)
1060  assertFalse(o3 instanceof f0)
1061  assertTrue(o3 instanceof f1)
1062  assertFalse(o3 instanceof f2)
1063  assertFalse(o3 instanceof f3)
1064  assertFalse(o3 instanceof f4)
1065  assertFalse(o3 instanceof f5)
1066  assertTrue(o4 instanceof f0)
1067  assertFalse(o4 instanceof f1)
1068  assertTrue(o4 instanceof f2)
1069  assertFalse(o4 instanceof f3)
1070  assertFalse(o4 instanceof f4)
1071  assertFalse(o4 instanceof f5)
1072  assertFalse(o5 instanceof f0)
1073  assertTrue(o5 instanceof f1)
1074  assertFalse(o5 instanceof f2)
1075  assertTrue(o5 instanceof f3)
1076  assertFalse(o5 instanceof f4)
1077  assertFalse(o5 instanceof f5)
1078
1079  var f = new Proxy(function() {}, {})
1080  var ff = new Proxy(function() {}, handler(Function))
1081  assertTrue(f instanceof Function)
1082  assertFalse(f instanceof ff)
1083})();
1084
1085
1086// ---------------------------------------------------------------------------
1087// Prototype (Object.getPrototypeOf, Object.prototype.isPrototypeOf).
1088
1089(function TestPrototype() {
1090  var o1 = {}
1091  var p1 = new Proxy({}, {})
1092  var p2 = new Proxy(o1, {})
1093  var p3 = new Proxy(p2, {})
1094  var o2 = Object.create(p3)
1095
1096  assertSame(Object.getPrototypeOf(o1), Object.prototype)
1097  assertSame(Object.getPrototypeOf(p1), Object.prototype)
1098  assertSame(Object.getPrototypeOf(p2), Object.prototype)
1099  assertSame(Object.getPrototypeOf(p3), Object.prototype)
1100  assertSame(Object.getPrototypeOf(o2), p3)
1101
1102  assertTrue(Object.prototype.isPrototypeOf(o1))
1103  assertTrue(Object.prototype.isPrototypeOf(p1))
1104  assertTrue(Object.prototype.isPrototypeOf(p2))
1105  assertTrue(Object.prototype.isPrototypeOf(p3))
1106  assertTrue(Object.prototype.isPrototypeOf(o2))
1107  assertTrue(Object.prototype.isPrototypeOf.call(Object.prototype, o1))
1108  assertTrue(Object.prototype.isPrototypeOf.call(Object.prototype, p1))
1109  assertTrue(Object.prototype.isPrototypeOf.call(Object.prototype, p2))
1110  assertTrue(Object.prototype.isPrototypeOf.call(Object.prototype, p3))
1111  assertTrue(Object.prototype.isPrototypeOf.call(Object.prototype, o2))
1112  assertFalse(Object.prototype.isPrototypeOf.call(o1, o1))
1113  assertFalse(Object.prototype.isPrototypeOf.call(o1, p1))
1114  assertFalse(Object.prototype.isPrototypeOf.call(o1, p2))
1115  assertFalse(Object.prototype.isPrototypeOf.call(o1, p3))
1116  assertFalse(Object.prototype.isPrototypeOf.call(o1, o2))
1117  assertFalse(Object.prototype.isPrototypeOf.call(p1, p1))
1118  assertFalse(Object.prototype.isPrototypeOf.call(p1, o1))
1119  assertFalse(Object.prototype.isPrototypeOf.call(p1, p2))
1120  assertFalse(Object.prototype.isPrototypeOf.call(p1, p3))
1121  assertFalse(Object.prototype.isPrototypeOf.call(p1, o2))
1122  assertFalse(Object.prototype.isPrototypeOf.call(p2, p1))
1123  assertFalse(Object.prototype.isPrototypeOf.call(p2, p2))
1124  assertFalse(Object.prototype.isPrototypeOf.call(p2, p3))
1125  assertFalse(Object.prototype.isPrototypeOf.call(p2, o2))
1126  assertFalse(Object.prototype.isPrototypeOf.call(p3, p2))
1127  assertTrue(Object.prototype.isPrototypeOf.call(p3, o2))
1128  assertFalse(Object.prototype.isPrototypeOf.call(o2, o1))
1129  assertFalse(Object.prototype.isPrototypeOf.call(o2, p1))
1130  assertFalse(Object.prototype.isPrototypeOf.call(o2, p2))
1131  assertFalse(Object.prototype.isPrototypeOf.call(o2, p3))
1132  assertFalse(Object.prototype.isPrototypeOf.call(o2, o2))
1133
1134  var f = new Proxy(function() {}, {})
1135  assertSame(Object.getPrototypeOf(f), Function.prototype)
1136  assertTrue(Object.prototype.isPrototypeOf(f))
1137  assertTrue(Object.prototype.isPrototypeOf.call(Function.prototype, f))
1138})();
1139
1140
1141// ---------------------------------------------------------------------------
1142function TestPropertyNamesThrow(handler) {
1143  TestWithProxies(TestPropertyNamesThrow2, handler)
1144}
1145
1146function TestPropertyNamesThrow2(create, handler) {
1147  var p = create(handler)
1148  assertThrowsEquals(function(){ Object.getOwnPropertyNames(p) }, "myexn")
1149}
1150
1151TestPropertyNamesThrow({
1152  ownKeys() { throw "myexn" }
1153})
1154
1155TestPropertyNamesThrow({
1156  ownKeys() { return this.getOwnPropertyNames2() },
1157  getOwnPropertyNames2() { throw "myexn" }
1158})
1159
1160// ---------------------------------------------------------------------------
1161
1162function TestKeys(names, handler) {
1163  var p = new Proxy({}, handler);
1164  assertArrayEquals(names, Object.keys(p))
1165}
1166
1167TestKeys([], {
1168  ownKeys() { return [] }
1169})
1170
1171TestKeys([], {
1172  ownKeys() { return ["a", "zz", " ", "0", "toString"] }
1173})
1174
1175TestKeys(["a", "zz", " ", "0", "toString"], {
1176  ownKeys() { return ["a", "zz", " ", "0", "toString"] },
1177  getOwnPropertyDescriptor(t, p) {
1178    return {configurable: true, enumerable: true}
1179  }
1180})
1181
1182TestKeys([], {
1183  ownKeys() { return this.keys2() },
1184  keys2() { return ["throw", "function "] }
1185})
1186
1187TestKeys(["throw", "function "], {
1188  ownKeys() { return this.keys2() },
1189  keys2() { return ["throw", "function "] },
1190  getOwnPropertyDescriptor(t, p) {
1191    return {configurable: true, enumerable: true}
1192  }
1193})
1194
1195TestKeys(["a", "0"], {
1196  ownKeys() { return ["a", "23", "zz", "", "0"] },
1197  getOwnPropertyDescriptor(t, k) {
1198    return k == "" ?
1199        undefined :
1200        { configurable: true, enumerable: k.length == 1}
1201  }
1202})
1203
1204TestKeys(["23", "zz", ""], {
1205  ownKeys() { return this.getOwnPropertyNames2() },
1206  getOwnPropertyNames2() { return ["a", "23", "zz", "", "0"] },
1207  getOwnPropertyDescriptor(t, k) {
1208    return this.getOwnPropertyDescriptor2(k)
1209  },
1210  getOwnPropertyDescriptor2(k) {
1211    return {configurable: true, enumerable: k.length != 1 }
1212  }
1213})
1214
1215TestKeys([], {
1216  get ownKeys() {
1217    return function() { return ["a", "b", "c"] }
1218  },
1219  getOwnPropertyDescriptor: function(k) { return {configurable: true} }
1220})
1221
1222
1223// ---------------------------------------------------------------------------
1224function TestKeysThrow(handler) {
1225  TestWithProxies(TestKeysThrow2, handler)
1226}
1227
1228function TestKeysThrow2(create, handler) {
1229  var p = create(handler);
1230  assertThrowsEquals(function(){ Object.keys(p) }, "myexn");
1231}
1232
1233TestKeysThrow({
1234  ownKeys() { throw "myexn" }
1235})
1236
1237TestKeysThrow({
1238  ownKeys() { return this.keys2() },
1239  keys2() { throw "myexn" }
1240})
1241
1242TestKeysThrow({
1243  ownKeys() { return ['1'] },
1244  getOwnPropertyDescriptor: function() { throw "myexn" },
1245})
1246
1247TestKeysThrow({
1248  ownKeys() { return this.getOwnPropertyNames2() },
1249  getOwnPropertyNames2() { return ['1', '2'] },
1250  getOwnPropertyDescriptor(k) {
1251    return this.getOwnPropertyDescriptor2(k)
1252  },
1253  getOwnPropertyDescriptor2(k) { throw "myexn" }
1254})
1255
1256TestKeysThrow({
1257  get ownKeys() { throw "myexn" }
1258})
1259
1260TestKeysThrow({
1261  get ownKeys() {
1262    return function() { throw "myexn" }
1263  },
1264})
1265
1266TestKeysThrow({
1267  get ownKeys() {
1268    return function() { return ['1', '2'] }
1269  },
1270  getOwnPropertyDescriptor(k) { throw "myexn" }
1271})
1272
1273
1274
1275// ---------------------------------------------------------------------------
1276// String conversion (Object.prototype.toString,
1277//                    Object.prototype.toLocaleString,
1278//                    Function.prototype.toString)
1279
1280var key
1281
1282function TestToString(handler) {
1283  var p = new Proxy({}, handler)
1284  key = ""
1285  assertEquals("[object Object]", Object.prototype.toString.call(p))
1286  assertEquals(Symbol.toStringTag, key)
1287  assertEquals("my_proxy", Object.prototype.toLocaleString.call(p))
1288  assertEquals("toString", key)
1289
1290  var f = new Proxy(function() {}, handler)
1291  key = ""
1292  assertEquals("[object Function]", Object.prototype.toString.call(f))
1293  assertEquals(Symbol.toStringTag, key)
1294  assertEquals("my_proxy", Object.prototype.toLocaleString.call(f))
1295  assertEquals("toString", key)
1296  assertThrows(function(){ Function.prototype.toString.call(f) })
1297
1298  var o = Object.create(p)
1299  key = ""
1300  assertEquals("[object Object]", Object.prototype.toString.call(o))
1301  assertEquals(Symbol.toStringTag, key)
1302  assertEquals("my_proxy", Object.prototype.toLocaleString.call(o))
1303  assertEquals("toString", key)
1304}
1305
1306TestToString({
1307  get: function(r, k) { key = k; return function() { return "my_proxy" } }
1308})
1309
1310TestToString({
1311  get: function(r, k) { return this.get2(r, k) },
1312  get2: function(r, k) { key = k; return function() { return "my_proxy" } }
1313})
1314
1315TestToString(new Proxy({}, {
1316  get: function(pr, pk) {
1317    return function(r, k) { key = k; return function() { return "my_proxy" } }
1318  }
1319}))
1320
1321
1322function TestToStringThrow(handler) {
1323  var p = new Proxy({}, handler)
1324  assertThrowsEquals(() => Object.prototype.toString.call(p), "myexn")
1325  assertThrowsEquals(() => Object.prototype.toLocaleString.call(p), "myexn")
1326
1327  var f = new Proxy(function(){}, handler)
1328  assertThrowsEquals(() => Object.prototype.toString.call(f), "myexn")
1329  assertThrowsEquals(() => Object.prototype.toLocaleString.call(f), "myexn")
1330
1331  var o = Object.create(p)
1332  assertThrowsEquals(() => Object.prototype.toString.call(o), "myexn")
1333  assertThrowsEquals(() => Object.prototype.toLocaleString.call(o), "myexn")
1334}
1335
1336TestToStringThrow({
1337  get: function(r, k) { throw "myexn" }
1338})
1339
1340TestToStringThrow({
1341  get: function(r, k) { return this.get2(r, k) },
1342  get2: function(r, k) { throw "myexn" }
1343})
1344
1345TestToStringThrow(new Proxy({}, {
1346  get: function(pr, pk) { throw "myexn" }
1347}))
1348
1349TestToStringThrow(new Proxy({}, {
1350  get: function(pr, pk) {
1351    return function(r, k) { throw "myexn" }
1352  }
1353}))
1354
1355
1356// ---------------------------------------------------------------------------
1357// Value conversion (Object.prototype.toValue)
1358
1359function TestValueOf(handler) {
1360  TestWithProxies(TestValueOf2, handler)
1361}
1362
1363function TestValueOf2(create, handler) {
1364  var p = create(handler)
1365  assertSame(p, Object.prototype.valueOf.call(p))
1366}
1367
1368TestValueOf({})
1369
1370
1371
1372// ---------------------------------------------------------------------------
1373// Enumerability (Object.prototype.propertyIsEnumerable)
1374
1375var key
1376
1377function TestIsEnumerable(handler) {
1378  TestWithProxies(TestIsEnumerable2, handler)
1379}
1380
1381function TestIsEnumerable2(create, handler) {
1382  var p = create(handler)
1383  assertTrue(Object.prototype.propertyIsEnumerable.call(p, "a"))
1384  assertEquals("a", key)
1385  assertTrue(Object.prototype.propertyIsEnumerable.call(p, 2))
1386  assertEquals("2", key)
1387  assertFalse(Object.prototype.propertyIsEnumerable.call(p, "z"))
1388  assertEquals("z", key)
1389
1390  var o = Object.create(p)
1391  key = ""
1392  assertFalse(Object.prototype.propertyIsEnumerable.call(o, "a"))
1393  assertEquals("", key)  // trap not invoked
1394}
1395
1396TestIsEnumerable({
1397  getOwnPropertyDescriptor(t, k) {
1398    key = k;
1399    return {enumerable: k < "z", configurable: true}
1400  },
1401})
1402
1403TestIsEnumerable({
1404  getOwnPropertyDescriptor: function(t, k) {
1405    return this.getOwnPropertyDescriptor2(k)
1406  },
1407  getOwnPropertyDescriptor2: function(k) {
1408    key = k;
1409    return {enumerable: k < "z", configurable: true}
1410  },
1411})
1412
1413TestIsEnumerable({
1414  getOwnPropertyDescriptor: function(t, k) {
1415    key = k;
1416    return {get enumerable() { return k < "z" }, configurable: true}
1417  },
1418})
1419
1420TestIsEnumerable(new Proxy({}, {
1421  get: function(pt, pk, pr) {
1422    return function(t, k) {
1423      key = k;
1424      return {enumerable: k < "z", configurable: true}
1425    }
1426  }
1427}))
1428
1429
1430// ---------------------------------------------------------------------------
1431function TestIsEnumerableThrow(handler) {
1432  TestWithProxies(TestIsEnumerableThrow2, handler)
1433}
1434
1435function TestIsEnumerableThrow2(create, handler) {
1436  var p = create(handler)
1437  assertThrowsEquals(() => Object.prototype.propertyIsEnumerable.call(p, "a"),
1438      "myexn")
1439  assertThrowsEquals(() => Object.prototype.propertyIsEnumerable.call(p, 11),
1440      "myexn")
1441}
1442
1443TestIsEnumerableThrow({
1444  getOwnPropertyDescriptor: function(k) { throw "myexn" }
1445})
1446
1447TestIsEnumerableThrow({
1448  getOwnPropertyDescriptor: function(k) {
1449    return this.getOwnPropertyDescriptor2(k)
1450  },
1451  getOwnPropertyDescriptor2: function(k) { throw "myexn" }
1452})
1453
1454TestIsEnumerableThrow({
1455  getOwnPropertyDescriptor: function(k) {
1456    return {get enumerable() { throw "myexn" }, configurable: true}
1457  },
1458})
1459
1460TestIsEnumerableThrow(new Proxy({}, {
1461  get: function(pr, pk) { throw "myexn" }
1462}))
1463
1464TestIsEnumerableThrow(new Proxy({}, {
1465  get: function(pr, pk) {
1466    return function(k) { throw "myexn" }
1467  }
1468}));
1469
1470
1471
1472// ---------------------------------------------------------------------------
1473// Constructor functions with proxy prototypes.
1474
1475(function TestConstructorWithProxyPrototype() {
1476  TestWithProxies(TestConstructorWithProxyPrototype2, {})
1477})();
1478
1479function TestConstructorWithProxyPrototype2(create, handler) {
1480  function C() {};
1481  C.prototype = create(handler);
1482
1483  var o = new C;
1484  assertSame(C.prototype, Object.getPrototypeOf(o));
1485};
1486
1487
1488(function TestOptWithProxyPrototype() {
1489  var handler = {
1490    get(t, k) {
1491      return 10;
1492    }
1493  };
1494
1495  function C() {};
1496  C.prototype = new Proxy({}, handler);
1497  var o = new C();
1498
1499  function f() {
1500    return o.x;
1501  }
1502  assertEquals(10, f());
1503  assertEquals(10, f());
1504  %OptimizeFunctionOnNextCall(f);
1505  assertEquals(10, f());
1506})();
1507