|
1 /* |
|
2 * Any copyright is dedicated to the Public Domain. |
|
3 * http://creativecommons.org/licenses/publicdomain/ |
|
4 */ |
|
5 |
|
6 var gTestfile = 'function-bind.js'; |
|
7 var BUGNUMBER = 429507; |
|
8 var summary = "ES5: Function.prototype.bind"; |
|
9 |
|
10 print(BUGNUMBER + ": " + summary); |
|
11 |
|
12 /************** |
|
13 * BEGIN TEST * |
|
14 **************/ |
|
15 |
|
16 // ad-hoc testing |
|
17 |
|
18 assertEq(Function.prototype.hasOwnProperty("bind"), true); |
|
19 |
|
20 var bind = Function.prototype.bind; |
|
21 assertEq(bind.length, 1); |
|
22 |
|
23 |
|
24 var strictReturnThis = function() { "use strict"; return this; }; |
|
25 |
|
26 assertEq(strictReturnThis.bind(undefined)(), undefined); |
|
27 assertEq(strictReturnThis.bind(null)(), null); |
|
28 |
|
29 var obj = {}; |
|
30 assertEq(strictReturnThis.bind(obj)(), obj); |
|
31 |
|
32 assertEq(strictReturnThis.bind(NaN)(), NaN); |
|
33 |
|
34 assertEq(strictReturnThis.bind(true)(), true); |
|
35 assertEq(strictReturnThis.bind(false)(), false); |
|
36 |
|
37 assertEq(strictReturnThis.bind("foopy")(), "foopy"); |
|
38 |
|
39 |
|
40 // rigorous, step-by-step testing |
|
41 |
|
42 function expectThrowTypeError(fun) |
|
43 { |
|
44 try |
|
45 { |
|
46 var r = fun(); |
|
47 throw new Error("didn't throw TypeError, returned " + r); |
|
48 } |
|
49 catch (e) |
|
50 { |
|
51 assertEq(e instanceof TypeError, true, |
|
52 "didn't throw TypeError, got: " + e); |
|
53 } |
|
54 } |
|
55 |
|
56 /* |
|
57 * 1. Let Target be the this value. |
|
58 * 2. If IsCallable(Target) is false, throw a TypeError exception. |
|
59 */ |
|
60 expectThrowTypeError(function() { bind.call(null); }); |
|
61 expectThrowTypeError(function() { bind.call(undefined); }); |
|
62 expectThrowTypeError(function() { bind.call(NaN); }); |
|
63 expectThrowTypeError(function() { bind.call(0); }); |
|
64 expectThrowTypeError(function() { bind.call(-0); }); |
|
65 expectThrowTypeError(function() { bind.call(17); }); |
|
66 expectThrowTypeError(function() { bind.call(42); }); |
|
67 expectThrowTypeError(function() { bind.call("foobar"); }); |
|
68 expectThrowTypeError(function() { bind.call(true); }); |
|
69 expectThrowTypeError(function() { bind.call(false); }); |
|
70 expectThrowTypeError(function() { bind.call([]); }); |
|
71 expectThrowTypeError(function() { bind.call({}); }); |
|
72 |
|
73 |
|
74 /* |
|
75 * 3. Let A be a new (possibly empty) internal list of all of the argument |
|
76 * values provided after thisArg (arg1, arg2 etc), in order. |
|
77 * 4. Let F be a new native ECMAScript object . |
|
78 * 5. Set all the internal methods, except for [[Get]], of F as specified in |
|
79 * 8.12. |
|
80 * 6. Set the [[Get]] internal property of F as specified in 15.3.5.4. |
|
81 * 7. Set the [[TargetFunction]] internal property of F to Target. |
|
82 * 8. Set the [[BoundThis]] internal property of F to the value of thisArg. |
|
83 * 9. Set the [[BoundArgs]] internal property of F to A. |
|
84 */ |
|
85 // throughout |
|
86 |
|
87 |
|
88 /* 10. Set the [[Class]] internal property of F to "Function". */ |
|
89 var toString = Object.prototype.toString; |
|
90 assertEq(toString.call(function(){}), "[object Function]"); |
|
91 assertEq(toString.call(function a(){}), "[object Function]"); |
|
92 assertEq(toString.call(function(a){}), "[object Function]"); |
|
93 assertEq(toString.call(function a(b){}), "[object Function]"); |
|
94 assertEq(toString.call(function(){}.bind()), "[object Function]"); |
|
95 assertEq(toString.call(function a(){}.bind()), "[object Function]"); |
|
96 assertEq(toString.call(function(a){}.bind()), "[object Function]"); |
|
97 assertEq(toString.call(function a(b){}.bind()), "[object Function]"); |
|
98 |
|
99 |
|
100 /* |
|
101 * 11. Set the [[Prototype]] internal property of F to the standard built-in |
|
102 * Function prototype object as specified in 15.3.3.1. |
|
103 */ |
|
104 assertEq(Object.getPrototypeOf(bind.call(function(){})), Function.prototype); |
|
105 assertEq(Object.getPrototypeOf(bind.call(function a(){})), Function.prototype); |
|
106 assertEq(Object.getPrototypeOf(bind.call(function(a){})), Function.prototype); |
|
107 assertEq(Object.getPrototypeOf(bind.call(function a(b){})), Function.prototype); |
|
108 |
|
109 |
|
110 /* |
|
111 * 12. Set the [[Call]] internal property of F as described in 15.3.4.5.1. |
|
112 */ |
|
113 var a = Array.bind(1, 2); |
|
114 assertEq(a().length, 2); |
|
115 assertEq(a(4).length, 2); |
|
116 assertEq(a(4, 8).length, 3); |
|
117 |
|
118 function t() { return this; } |
|
119 var bt = t.bind(t); |
|
120 assertEq(bt(), t); |
|
121 |
|
122 function callee() { return arguments.callee; } |
|
123 var call = callee.bind(); |
|
124 assertEq(call(), callee); |
|
125 assertEq(new call(), callee); |
|
126 |
|
127 |
|
128 /* |
|
129 * 13. Set the [[Construct]] internal property of F as described in 15.3.4.5.2. |
|
130 */ |
|
131 function Point(x, y) |
|
132 { |
|
133 this.x = x; |
|
134 this.y = y; |
|
135 } |
|
136 var YAxisPoint = Point.bind(null, 0) |
|
137 |
|
138 assertEq(YAxisPoint.hasOwnProperty("prototype"), false); |
|
139 var p = new YAxisPoint(5); |
|
140 assertEq(p.x, 0); |
|
141 assertEq(p.y, 5); |
|
142 assertEq(p instanceof Point, true); |
|
143 assertEq(p instanceof YAxisPoint, true); |
|
144 assertEq(Object.prototype.toString.call(YAxisPoint), "[object Function]"); |
|
145 assertEq(YAxisPoint.length, 1); |
|
146 |
|
147 |
|
148 /* |
|
149 * 14. Set the [[HasInstance]] internal property of F as described in |
|
150 * 15.3.4.5.3. |
|
151 */ |
|
152 function JoinArguments() |
|
153 { |
|
154 this.args = Array.prototype.join.call(arguments, ", "); |
|
155 } |
|
156 |
|
157 var Join1 = JoinArguments.bind(null, 1); |
|
158 var Join2 = Join1.bind(null, 2); |
|
159 var Join3 = Join2.bind(null, 3); |
|
160 var Join4 = Join3.bind(null, 4); |
|
161 var Join5 = Join4.bind(null, 5); |
|
162 var Join6 = Join5.bind(null, 6); |
|
163 |
|
164 var r = new Join6(7); |
|
165 assertEq(r instanceof Join6, true); |
|
166 assertEq(r instanceof Join5, true); |
|
167 assertEq(r instanceof Join4, true); |
|
168 assertEq(r instanceof Join3, true); |
|
169 assertEq(r instanceof Join2, true); |
|
170 assertEq(r instanceof Join1, true); |
|
171 assertEq(r instanceof JoinArguments, true); |
|
172 assertEq(r.args, "1, 2, 3, 4, 5, 6, 7"); |
|
173 |
|
174 |
|
175 /* |
|
176 * 15. If the [[Class]] internal property of Target is "Function", then |
|
177 * a. Let L be the length property of Target minus the length of A. |
|
178 * b. Set the length own property of F to either 0 or L, whichever is larger. |
|
179 * 16. Else set the length own property of F to 0. |
|
180 */ |
|
181 function none() { return arguments.length; } |
|
182 assertEq(none.bind(1, 2)(3, 4), 3); |
|
183 assertEq(none.bind(1, 2)(), 1); |
|
184 assertEq(none.bind(1)(2, 3), 2); |
|
185 assertEq(none.bind().length, 0); |
|
186 assertEq(none.bind(null).length, 0); |
|
187 assertEq(none.bind(null, 1).length, 0); |
|
188 assertEq(none.bind(null, 1, 2).length, 0); |
|
189 |
|
190 function one(a) { } |
|
191 assertEq(one.bind().length, 1); |
|
192 assertEq(one.bind(null).length, 1); |
|
193 assertEq(one.bind(null, 1).length, 0); |
|
194 assertEq(one.bind(null, 1, 2).length, 0); |
|
195 |
|
196 // retch |
|
197 var br = Object.create(null, { length: { value: 0 } }); |
|
198 try |
|
199 { |
|
200 br = bind.call(/a/g, /a/g, "aaaa"); |
|
201 } |
|
202 catch (e) { /* nothing */ } |
|
203 assertEq(br.length, 0); |
|
204 |
|
205 |
|
206 /* |
|
207 * 17. Set the attributes of the length own property of F to the values |
|
208 * specified in 15.3.5.1. |
|
209 */ |
|
210 var len1Desc = |
|
211 Object.getOwnPropertyDescriptor(function(a, b, c){}.bind(), "length"); |
|
212 assertEq(len1Desc.value, 3); |
|
213 assertEq(len1Desc.writable, false); |
|
214 assertEq(len1Desc.enumerable, false); |
|
215 assertEq(len1Desc.configurable, false); |
|
216 |
|
217 var len2Desc = |
|
218 Object.getOwnPropertyDescriptor(function(a, b, c){}.bind(null, 2), "length"); |
|
219 assertEq(len2Desc.value, 2); |
|
220 assertEq(len2Desc.writable, false); |
|
221 assertEq(len2Desc.enumerable, false); |
|
222 assertEq(len2Desc.configurable, false); |
|
223 |
|
224 |
|
225 /* |
|
226 * 18. Set the [[Extensible]] internal property of F to true. |
|
227 */ |
|
228 var bound = (function() { }).bind(); |
|
229 |
|
230 var isExtensible = Object.isExtensible || function() { return true; }; |
|
231 assertEq(isExtensible(bound), true); |
|
232 |
|
233 bound.foo = 17; |
|
234 var fooDesc = Object.getOwnPropertyDescriptor(bound, "foo"); |
|
235 assertEq(fooDesc.value, 17); |
|
236 assertEq(fooDesc.writable, true); |
|
237 assertEq(fooDesc.enumerable, true); |
|
238 assertEq(fooDesc.configurable, true); |
|
239 |
|
240 |
|
241 /* |
|
242 * 19. Let thrower be the [[ThrowTypeError]] function Object (13.2.3). |
|
243 * 20. Call the [[DefineOwnProperty]] internal method of F with arguments |
|
244 * "caller", PropertyDescriptor {[[Get]]: thrower, [[Set]]: thrower, |
|
245 * [[Enumerable]]: false, [[Configurable]]: false}, and false. |
|
246 * 21. Call the [[DefineOwnProperty]] internal method of F with arguments |
|
247 * "arguments", PropertyDescriptor {[[Get]]: thrower, [[Set]]: thrower, |
|
248 * [[Enumerable]]: false, [[Configurable]]: false}, and false. |
|
249 */ |
|
250 function f() { "use strict"; } |
|
251 var canonicalTTE = Object.getOwnPropertyDescriptor(f, "caller").get; |
|
252 |
|
253 var tte; |
|
254 |
|
255 var boundf = f.bind(); |
|
256 |
|
257 var boundfCaller = Object.getOwnPropertyDescriptor(boundf, "caller"); |
|
258 assertEq("get" in boundfCaller, true); |
|
259 assertEq("set" in boundfCaller, true); |
|
260 tte = boundfCaller.get; |
|
261 assertEq(tte, canonicalTTE); |
|
262 assertEq(tte, boundfCaller.set); |
|
263 |
|
264 var boundfArguments = Object.getOwnPropertyDescriptor(boundf, "arguments"); |
|
265 assertEq("get" in boundfArguments, true); |
|
266 assertEq("set" in boundfArguments, true); |
|
267 tte = boundfArguments.get; |
|
268 assertEq(tte, canonicalTTE); |
|
269 assertEq(tte, boundfArguments.set); |
|
270 |
|
271 |
|
272 /* 22. Return F. */ |
|
273 var passim = function p(){}.bind(1); |
|
274 assertEq(typeof passim, "function"); |
|
275 |
|
276 |
|
277 /******************************************************************************/ |
|
278 |
|
279 if (typeof reportCompare === "function") |
|
280 reportCompare(true, true); |
|
281 |
|
282 print("All tests passed!"); |