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