1// Copyright 2015 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5// Flags: --harmony-proxies --harmony-reflect
6
7// Tests the interaction of Function.prototype.bind with proxies.
8
9
10// (Helper)
11
12var log = [];
13var logger = {};
14var handler = new Proxy({}, logger);
15
16logger.get = function(t, trap, r) {
17  return function() {
18    log.push([trap, ...arguments]);
19    return Reflect[trap](...arguments);
20  }
21};
22
23
24// Simple case
25
26var target = function(a, b, c) { "use strict"; return this };
27var proxy = new Proxy(target, handler);
28var this_value = Symbol();
29
30log.length = 0;
31result = Function.prototype.bind.call(proxy, this_value, "foo");
32assertEquals(2, result.length);
33assertEquals(target.__proto__, result.__proto__);
34assertEquals(this_value, result());
35assertEquals(5, log.length);
36for (var i in log) assertSame(target, log[i][1]);
37assertEquals(["getPrototypeOf", target], log[0]);
38assertEquals(["getOwnPropertyDescriptor", target, "length"], log[1]);
39assertEquals(["get", target, "length", proxy], log[2]);
40assertEquals(["get", target, "name", proxy], log[3]);
41assertEquals(["apply", target, this_value, ["foo"]], log[4]);
42assertEquals(new target(), new result());
43
44
45// Custom prototype
46
47log.length = 0;
48target.__proto__ = {radio: "gaga"};
49result = Function.prototype.bind.call(proxy, this_value, "foo");
50assertEquals(2, result.length);
51assertSame(target.__proto__, result.__proto__);
52assertEquals(this_value, result());
53assertEquals(5, log.length);
54for (var i in log) assertSame(target, log[i][1]);
55assertEquals(["getPrototypeOf", target], log[0]);
56assertEquals(["getOwnPropertyDescriptor", target, "length"], log[1]);
57assertEquals(["get", target, "length", proxy], log[2]);
58assertEquals(["get", target, "name", proxy], log[3]);
59assertEquals(["apply", target, this_value, ["foo"]], log[4]);
60
61
62// Custom length
63
64handler = {
65  get() {return 42},
66  getOwnPropertyDescriptor() {return {configurable: true}}
67};
68proxy = new Proxy(target, handler);
69
70result = Function.prototype.bind.call(proxy, this_value, "foo");
71assertEquals(41, result.length);
72assertEquals(this_value, result());
73
74
75// Long length
76
77handler = {
78  get() {return Math.pow(2, 100)},
79  getOwnPropertyDescriptor() {return {configurable: true}}
80};
81proxy = new Proxy(target, handler);
82
83result = Function.prototype.bind.call(proxy, this_value, "foo");
84assertEquals(Math.pow(2, 100) - 1, result.length);
85assertEquals(this_value, result());
86
87
88// Very long length
89
90handler = {
91  get() {return 1/0},
92  getOwnPropertyDescriptor() {return {configurable: true}}
93};
94proxy = new Proxy(target, handler);
95
96result = Function.prototype.bind.call(proxy, this_value, "foo");
97assertEquals(1/0, result.length);
98assertEquals(this_value, result());
99
100
101// Non-integer length
102
103handler = {
104  get() {return 4.2},
105  getOwnPropertyDescriptor() {return {configurable: true}}
106};
107proxy = new Proxy(target, handler);
108
109result = Function.prototype.bind.call(proxy, this_value, "foo");
110assertEquals(3, result.length);
111assertEquals(this_value, result());
112
113
114// Undefined length
115
116handler = {
117  get() {},
118  getOwnPropertyDescriptor() {return {configurable: true}}
119};
120proxy = new Proxy(target, handler);
121
122result = Function.prototype.bind.call(proxy, this_value, "foo");
123assertEquals(0, result.length);
124assertEquals(this_value, result());
125
126
127// Non-callable
128
129assertThrows(() => Function.prototype.bind.call(new Proxy({}, {})), TypeError);
130assertThrows(() => Function.prototype.bind.call(new Proxy([], {})), TypeError);
131
132
133// Non-constructable
134
135result = Function.prototype.bind.call(() => 42, this_value, "foo");
136assertEquals(42, result());
137assertThrows(() => new result());
138