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