1// Copyright 2013 the V8 project authors. All rights reserved.
2// Copyright (C) 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
3//
4// Redistribution and use in source and binary forms, with or without
5// modification, are permitted provided that the following conditions
6// are met:
7// 1.  Redistributions of source code must retain the above copyright
8//     notice, this list of conditions and the following disclaimer.
9// 2.  Redistributions in binary form must reproduce the above copyright
10//     notice, this list of conditions and the following disclaimer in the
11//     documentation and/or other materials provided with the distribution.
12//
13// THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY
14// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
15// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
16// DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY
17// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
18// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
19// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
20// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
22// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23
24description('Tests to ensure that Function.apply works correctly for Arrays, arguments and array-like objects.');
25
26function argumentsApply1(a, b, c)
27{
28    function t(a, b, c)
29    {
30        return a;
31    }
32    return t.apply(null, arguments);
33}
34
35function argumentsApply2(a, b, c)
36{
37    function t(a, b, c)
38    {
39        return b;
40    }
41    return t.apply(null, arguments);
42}
43
44function argumentsApply3(a, b, c)
45{
46    function t(a, b, c)
47    {
48        return c;
49    }
50    return t.apply(null, arguments);
51}
52
53function argumentsApplyLength(a, b, c)
54{
55    function t(a, b, c)
56    {
57        return arguments.length;
58    }
59    return t.apply(null, arguments);
60}
61var executedAdditionalArgument = false;
62function argumentsApplyExcessArguments(a, b, c)
63{
64    function t(a, b, c)
65    {
66        return arguments.length;
67    }
68    return t.apply(null, arguments, executedAdditionalArgument = true);
69}
70
71shouldBe("argumentsApply1(1, 2, 3)", "1");
72shouldBe("argumentsApply2(1, 2, 3)", "2");
73shouldBe("argumentsApply3(1, 2, 3)", "3");
74shouldBe("argumentsApplyLength(1, 2, 3)", "3");
75shouldBe("argumentsApplyExcessArguments(1, 2, 3)", "3");
76shouldBeTrue("executedAdditionalArgument");
77
78function arrayApply1(array)
79{
80    function t(a, b, c)
81    {
82        return a;
83    }
84    return t.apply(null, array);
85}
86
87function arrayApply2(array)
88{
89    function t(a, b, c)
90    {
91        return b;
92    }
93    return t.apply(null, array);
94}
95
96function arrayApply3(array)
97{
98    function t(a, b, c)
99    {
100        return c;
101    }
102    return t.apply(null, array);
103}
104
105function arrayApplyLength(array)
106{
107    function t(a, b, c)
108    {
109        return arguments.length;
110    }
111    return t.apply(null, array);
112}
113
114shouldBe("arrayApply1([1, 2, 3])", "1");
115shouldBe("arrayApply2([1, 2, 3])", "2");
116shouldBe("arrayApply3([1, 2, 3])", "3");
117shouldBe("arrayApplyLength([1, 2, 3])", "3");
118
119
120function argumentsApplyDelete1(a, b, c)
121{
122    function t(a, b, c)
123    {
124        return a;
125    }
126    delete arguments[1];
127    return t.apply(null, arguments);
128}
129
130function argumentsApplyDelete2(a, b, c)
131{
132    function t(a, b, c)
133    {
134        return b;
135    }
136    delete arguments[1];
137    return t.apply(null, arguments);
138}
139
140function argumentsApplyDelete3(a, b, c)
141{
142    function t(a, b, c)
143    {
144        return c;
145    }
146    delete arguments[1];
147    return t.apply(null, arguments);
148}
149
150function argumentsApplyDeleteLength(a, b, c)
151{
152    function t(a, b, c)
153    {
154        return arguments.length;
155    }
156    delete arguments[1];
157    return t.apply(null, arguments);
158}
159
160shouldBe("argumentsApplyDelete1(1, 2, 3)", "1");
161shouldBe("argumentsApplyDelete2(1, 2, 3)", "undefined");
162shouldBe("argumentsApplyDelete3(1, 2, 3)", "3");
163shouldBe("argumentsApplyDeleteLength(1, 2, 3)", "3");
164
165
166function arrayApplyDelete1(array)
167{
168    function t(a, b, c)
169    {
170        return a;
171    }
172    delete array[1];
173    return t.apply(null, array);
174}
175
176function arrayApplyDelete2(array)
177{
178    function t(a, b, c)
179    {
180        return b;
181    }
182    delete array[1];
183    return t.apply(null, array);
184}
185
186function arrayApplyDelete3(array)
187{
188    function t(a, b, c)
189    {
190        return c;
191    }
192    delete array[1];
193    return t.apply(null, array);
194}
195
196function arrayApplyDeleteLength(array)
197{
198    function t(a, b, c)
199    {
200        return arguments.length;
201    }
202    delete array[1];
203    return t.apply(null, array);
204}
205
206shouldBe("arrayApplyDelete1([1, 2, 3])", "1");
207shouldBe("arrayApplyDelete2([1, 2, 3])", "undefined");
208shouldBe("arrayApplyDelete3([1, 2, 3])", "3");
209shouldBe("arrayApplyDeleteLength([1, 2, 3])", "3");
210
211
212function argumentsApplyChangeLength1()
213{
214    function f() {
215        return arguments.length;
216    };
217    arguments.length = 2;
218    return f.apply(null, arguments);
219}
220
221
222function argumentsApplyChangeLength2()
223{
224    function f(a) {
225        return arguments.length;
226    };
227    arguments.length = 2;
228    return f.apply(null, arguments);
229}
230
231
232function argumentsApplyChangeLength3()
233{
234    function f(a, b, c) {
235        return arguments.length;
236    };
237    arguments.length = 2;
238    return f.apply(null, arguments);
239};
240
241function argumentsApplyChangeLength4()
242{
243    function f() {
244        return arguments.length;
245    };
246    arguments.length = 0;
247    return f.apply(null, arguments);
248};
249
250function argumentsApplyChangeLength5()
251{
252    function f() {
253        return arguments.length;
254    };
255    arguments.length = "Not A Number";
256    return f.apply(null, arguments);
257}
258
259shouldBe("argumentsApplyChangeLength1(1)", "2");
260shouldBe("argumentsApplyChangeLength2(1)", "2");
261shouldBe("argumentsApplyChangeLength3(1)", "2");
262shouldBe("argumentsApplyChangeLength4(1)", "0");
263shouldBe("argumentsApplyChangeLength5(1)", "0");
264
265function arrayApplyChangeLength1()
266{
267    function f() {
268        return arguments.length;
269    };
270    var array = [];
271    array.length = 2;
272    return f.apply(null, array);
273}
274
275function arrayApplyChangeLength2()
276{
277    function f(a) {
278        return arguments.length;
279    };
280    var array = [];
281    array.length = 2;
282    return f.apply(null, array);
283}
284
285function arrayApplyChangeLength3()
286{
287    function f(a, b, c) {
288        return arguments.length;
289    };
290    var array = [];
291    array.length = 2;
292    return f.apply(null, array);
293}
294
295function arrayApplyChangeLength4()
296{
297    function f() {
298        return arguments.length;
299    };
300    var array = [1];
301    array.length = 0;
302    return f.apply(null, array);
303};
304
305shouldBe("arrayApplyChangeLength1()", "2");
306shouldBe("arrayApplyChangeLength2()", "2");
307shouldBe("arrayApplyChangeLength3()", "2");
308shouldBe("arrayApplyChangeLength4()", "0");
309
310shouldBe("var a = []; a.length = 0xFFFE; [].constructor.apply('', a).length", "0xFFFE");
311shouldBe("var a = []; a.length = 0xFFFF; [].constructor.apply('', a).length", "0xFFFF");
312shouldBe("var a = []; a.length = 0x10000; [].constructor.apply('', a).length", "0x10000");
313shouldThrow("var a = []; a.length = 0x10001; [].constructor.apply('', a).length");
314shouldThrow("var a = []; a.length = 0xFFFFFFFE; [].constructor.apply('', a).length");
315shouldThrow("var a = []; a.length = 0xFFFFFFFF; [].constructor.apply('', a).length");
316
317// ES5 permits apply with array-like objects.
318shouldBe("(function(a,b,c,d){ return d ? -1 : (a+b+c); }).apply(undefined, {length:3, 0:100, 1:20, 2:3})", '123');
319