1// Copyright 2011 the V8 project authors. All rights reserved.
2// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6//     * Redistributions of source code must retain the above copyright
7//       notice, this list of conditions and the following disclaimer.
8//     * Redistributions in binary form must reproduce the above
9//       copyright notice, this list of conditions and the following
10//       disclaimer in the documentation and/or other materials provided
11//       with the distribution.
12//     * Neither the name of Google Inc. nor the names of its
13//       contributors may be used to endorse or promote products derived
14//       from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28
29var should_throw_on_null_and_undefined =
30    [Object.prototype.toLocaleString,
31     Object.prototype.valueOf,
32     Object.prototype.hasOwnProperty,
33     Object.prototype.isPrototypeOf,
34     Object.prototype.propertyIsEnumerable,
35     Array.prototype.concat,
36     Array.prototype.join,
37     Array.prototype.pop,
38     Array.prototype.push,
39     Array.prototype.reverse,
40     Array.prototype.shift,
41     Array.prototype.slice,
42     Array.prototype.sort,
43     Array.prototype.splice,
44     Array.prototype.unshift,
45     Array.prototype.indexOf,
46     Array.prototype.lastIndexOf,
47     Array.prototype.every,
48     Array.prototype.some,
49     Array.prototype.forEach,
50     Array.prototype.map,
51     Array.prototype.filter,
52     Array.prototype.reduce,
53     Array.prototype.reduceRight,
54     String.prototype.charAt,
55     String.prototype.charCodeAt,
56     String.prototype.concat,
57     String.prototype.indexOf,
58     String.prototype.lastIndexOf,
59     String.prototype.localeCompare,
60     String.prototype.match,
61     String.prototype.replace,
62     String.prototype.search,
63     String.prototype.slice,
64     String.prototype.split,
65     String.prototype.substring,
66     String.prototype.toLowerCase,
67     String.prototype.toLocaleLowerCase,
68     String.prototype.toUpperCase,
69     String.prototype.toLocaleUpperCase,
70     String.prototype.trim,
71     Number.prototype.toLocaleString];
72
73// Non generic natives do not work on any input other than the specific
74// type, but since this change will allow call to be invoked with undefined
75// or null as this we still explicitly test that we throw on these here.
76var non_generic =
77    [Array.prototype.toString,
78     Array.prototype.toLocaleString,
79     Function.prototype.toString,
80     Function.prototype.call,
81     Function.prototype.apply,
82     String.prototype.toString,
83     String.prototype.valueOf,
84     Boolean.prototype.toString,
85     Boolean.prototype.valueOf,
86     Number.prototype.toString,
87     Number.prototype.valueOf,
88     Number.prototype.toFixed,
89     Number.prototype.toExponential,
90     Number.prototype.toPrecision,
91     Date.prototype.toString,
92     Date.prototype.toDateString,
93     Date.prototype.toTimeString,
94     Date.prototype.toLocaleString,
95     Date.prototype.toLocaleDateString,
96     Date.prototype.toLocaleTimeString,
97     Date.prototype.valueOf,
98     Date.prototype.getTime,
99     Date.prototype.getFullYear,
100     Date.prototype.getUTCFullYear,
101     Date.prototype.getMonth,
102     Date.prototype.getUTCMonth,
103     Date.prototype.getDate,
104     Date.prototype.getUTCDate,
105     Date.prototype.getDay,
106     Date.prototype.getUTCDay,
107     Date.prototype.getHours,
108     Date.prototype.getUTCHours,
109     Date.prototype.getMinutes,
110     Date.prototype.getUTCMinutes,
111     Date.prototype.getSeconds,
112     Date.prototype.getUTCSeconds,
113     Date.prototype.getMilliseconds,
114     Date.prototype.getUTCMilliseconds,
115     Date.prototype.getTimezoneOffset,
116     Date.prototype.setTime,
117     Date.prototype.setMilliseconds,
118     Date.prototype.setUTCMilliseconds,
119     Date.prototype.setSeconds,
120     Date.prototype.setUTCSeconds,
121     Date.prototype.setMinutes,
122     Date.prototype.setUTCMinutes,
123     Date.prototype.setHours,
124     Date.prototype.setUTCHours,
125     Date.prototype.setDate,
126     Date.prototype.setUTCDate,
127     Date.prototype.setMonth,
128     Date.prototype.setUTCMonth,
129     Date.prototype.setFullYear,
130     Date.prototype.setUTCFullYear,
131     Date.prototype.toUTCString,
132     Date.prototype.toISOString,
133     Date.prototype.toJSON,
134     RegExp.prototype.exec,
135     RegExp.prototype.test,
136     RegExp.prototype.toString,
137     Error.prototype.toString];
138
139
140// Mapping functions.
141var mapping_functions =
142    [Array.prototype.every,
143     Array.prototype.some,
144     Array.prototype.forEach,
145     Array.prototype.map,
146     Array.prototype.filter];
147
148// Reduce functions.
149var reducing_functions =
150    [Array.prototype.reduce,
151     Array.prototype.reduceRight];
152
153// Test that all natives using the ToObject call throw the right exception.
154for (var i = 0; i < should_throw_on_null_and_undefined.length; i++) {
155  // Sanity check that all functions are correct
156  assertEquals(typeof(should_throw_on_null_and_undefined[i]), "function");
157
158  var exception = false;
159  try {
160    // We call all functions with no parameters, which means that essential
161    // parameters will have the undefined value.
162    // The test for whether the "this" value is null or undefined is always
163    // performed before access to the other parameters, so even if the
164    // undefined value is an invalid argument value, it mustn't change
165    // the result of the test.
166    should_throw_on_null_and_undefined[i].call(null);
167  } catch (e) {
168    exception = true;
169    assertTrue("called_on_null_or_undefined" == e.type ||
170               "null_to_object" == e.type);
171  }
172  assertTrue(exception);
173
174  exception = false;
175  try {
176    should_throw_on_null_and_undefined[i].call(undefined);
177  } catch (e) {
178    exception = true;
179    assertTrue("called_on_null_or_undefined" == e.type ||
180               "null_to_object" == e.type);
181  }
182  assertTrue(exception);
183
184  exception = false;
185  try {
186    should_throw_on_null_and_undefined[i].apply(null);
187  } catch (e) {
188    exception = true;
189    assertTrue("called_on_null_or_undefined" == e.type ||
190               "null_to_object" == e.type);
191  }
192  assertTrue(exception);
193
194  exception = false;
195  try {
196    should_throw_on_null_and_undefined[i].apply(undefined);
197  } catch (e) {
198    exception = true;
199    assertTrue("called_on_null_or_undefined" == e.type ||
200               "null_to_object" == e.type);
201  }
202  assertTrue(exception);
203}
204
205// Test that all natives that are non generic throw on null and undefined.
206for (var i = 0; i < non_generic.length; i++) {
207  // Sanity check that all functions are correct
208  assertEquals(typeof(non_generic[i]), "function");
209
210  exception = false;
211  try {
212    non_generic[i].call(null);
213  } catch (e) {
214    exception = true;
215    assertTrue(e instanceof TypeError);
216  }
217  assertTrue(exception);
218
219  exception = false;
220  try {
221    non_generic[i].call(null);
222  } catch (e) {
223    exception = true;
224    assertTrue(e instanceof TypeError);
225  }
226  assertTrue(exception);
227
228  exception = false;
229  try {
230    non_generic[i].apply(null);
231  } catch (e) {
232    exception = true;
233    assertTrue(e instanceof TypeError);
234  }
235  assertTrue(exception);
236
237  exception = false;
238  try {
239    non_generic[i].apply(null);
240  } catch (e) {
241    exception = true;
242    assertTrue(e instanceof TypeError);
243  }
244  assertTrue(exception);
245}
246
247
248// Test that we still throw when calling with thisArg null or undefined
249// through an array mapping function.
250var array = [1,2,3,4,5];
251for (var j = 0; j < mapping_functions.length; j++) {
252  for (var i = 0; i < should_throw_on_null_and_undefined.length; i++) {
253    exception = false;
254    try {
255      mapping_functions[j].call(array,
256                                should_throw_on_null_and_undefined[i],
257                                null);
258    } catch (e) {
259      exception = true;
260      assertTrue("called_on_null_or_undefined" == e.type ||
261                 "null_to_object" == e.type);
262    }
263    assertTrue(exception);
264
265    exception = false;
266    try {
267      mapping_functions[j].call(array,
268                                should_throw_on_null_and_undefined[i],
269                                undefined);
270    } catch (e) {
271      exception = true;
272      assertTrue("called_on_null_or_undefined" == e.type ||
273                 "null_to_object" == e.type);
274    }
275    assertTrue(exception);
276  }
277}
278
279for (var j = 0; j < mapping_functions.length; j++) {
280  for (var i = 0; i < non_generic.length; i++) {
281    exception = false;
282    try {
283      mapping_functions[j].call(array,
284                                non_generic[i],
285                                null);
286    } catch (e) {
287      exception = true;
288      assertTrue(e instanceof TypeError);
289    }
290    assertTrue(exception);
291
292    exception = false;
293    try {
294      mapping_functions[j].call(array,
295                                non_generic[i],
296                                undefined);
297    } catch (e) {
298      exception = true;
299      assertTrue(e instanceof TypeError);
300    }
301    assertTrue(exception);
302  }
303}
304
305
306// Reduce functions do a call with null as this argument.
307for (var j = 0; j < reducing_functions.length; j++) {
308  for (var i = 0; i < should_throw_on_null_and_undefined.length; i++) {
309    exception = false;
310    try {
311      reducing_functions[j].call(array, should_throw_on_null_and_undefined[i]);
312    } catch (e) {
313      exception = true;
314      assertTrue("called_on_null_or_undefined" == e.type ||
315                 "null_to_object" == e.type);
316    }
317    assertTrue(exception);
318
319    exception = false;
320    try {
321      reducing_functions[j].call(array, should_throw_on_null_and_undefined[i]);
322    } catch (e) {
323      exception = true;
324      assertTrue("called_on_null_or_undefined" == e.type ||
325                 "null_to_object" == e.type);
326    }
327    assertTrue(exception);
328  }
329}
330
331for (var j = 0; j < reducing_functions.length; j++) {
332  for (var i = 0; i < non_generic.length; i++) {
333    exception = false;
334    try {
335      reducing_functions[j].call(array, non_generic[i]);
336    } catch (e) {
337      exception = true;
338      assertTrue(e instanceof TypeError);
339    }
340    assertTrue(exception);
341
342    exception = false;
343    try {
344      reducing_functions[j].call(array, non_generic[i]);
345    } catch (e) {
346      exception = true;
347      assertTrue(e instanceof TypeError);
348    }
349    assertTrue(exception);
350  }
351}
352
353
354// Object.prototype.toString()
355assertEquals(Object.prototype.toString.call(null),
356             '[object Null]')
357
358assertEquals(Object.prototype.toString.call(undefined),
359             '[object Undefined]')
360