// Copyright 2015 the V8 project authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // Tests the interaction of Function.prototype.bind with proxies. // (Helper) var log = []; var logger = {}; var handler = new Proxy({}, logger); logger.get = function(t, trap, r) { return function() { log.push([trap, ...arguments]); return Reflect[trap](...arguments); } }; // Simple case var target = function(a, b, c) { "use strict"; return this }; var proxy = new Proxy(target, handler); var this_value = Symbol(); log.length = 0; result = Function.prototype.bind.call(proxy, this_value, "foo"); assertEquals(2, result.length); assertEquals(target.__proto__, result.__proto__); assertEquals(this_value, result()); assertEquals(5, log.length); for (var i in log) assertSame(target, log[i][1]); assertEquals(["getPrototypeOf", target], log[0]); assertEquals(["getOwnPropertyDescriptor", target, "length"], log[1]); assertEquals(["get", target, "length", proxy], log[2]); assertEquals(["get", target, "name", proxy], log[3]); assertEquals(["apply", target, this_value, ["foo"]], log[4]); assertEquals(new target(), new result()); // Custom prototype log.length = 0; target.__proto__ = {radio: "gaga"}; result = Function.prototype.bind.call(proxy, this_value, "foo"); assertEquals(2, result.length); assertSame(target.__proto__, result.__proto__); assertEquals(this_value, result()); assertEquals(5, log.length); for (var i in log) assertSame(target, log[i][1]); assertEquals(["getPrototypeOf", target], log[0]); assertEquals(["getOwnPropertyDescriptor", target, "length"], log[1]); assertEquals(["get", target, "length", proxy], log[2]); assertEquals(["get", target, "name", proxy], log[3]); assertEquals(["apply", target, this_value, ["foo"]], log[4]); // Custom length handler = { get() {return 42}, getOwnPropertyDescriptor() {return {configurable: true}} }; proxy = new Proxy(target, handler); result = Function.prototype.bind.call(proxy, this_value, "foo"); assertEquals(41, result.length); assertEquals(this_value, result()); // Long length handler = { get() {return Math.pow(2, 100)}, getOwnPropertyDescriptor() {return {configurable: true}} }; proxy = new Proxy(target, handler); result = Function.prototype.bind.call(proxy, this_value, "foo"); assertEquals(Math.pow(2, 100) - 1, result.length); assertEquals(this_value, result()); // Very long length handler = { get() {return 1/0}, getOwnPropertyDescriptor() {return {configurable: true}} }; proxy = new Proxy(target, handler); result = Function.prototype.bind.call(proxy, this_value, "foo"); assertEquals(1/0, result.length); assertEquals(this_value, result()); // Non-integer length handler = { get() {return 4.2}, getOwnPropertyDescriptor() {return {configurable: true}} }; proxy = new Proxy(target, handler); result = Function.prototype.bind.call(proxy, this_value, "foo"); assertEquals(3, result.length); assertEquals(this_value, result()); // Undefined length handler = { get() {}, getOwnPropertyDescriptor() {return {configurable: true}} }; proxy = new Proxy(target, handler); result = Function.prototype.bind.call(proxy, this_value, "foo"); assertEquals(0, result.length); assertEquals(this_value, result()); // Non-callable assertThrows(() => Function.prototype.bind.call(new Proxy({}, {})), TypeError); assertThrows(() => Function.prototype.bind.call(new Proxy([], {})), TypeError); // Non-constructable result = Function.prototype.bind.call(() => 42, this_value, "foo"); assertEquals(42, result()); assertThrows(() => new result());