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