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
72// Non generic natives do not work on any input other than the specific
73// type, but since this change will allow call to be invoked with undefined
74// or null as this we still explicitly test that we throw on these here.
75var non_generic =
76    [Array.prototype.toString,
77     Array.prototype.toLocaleString,
78     Function.prototype.toString,
79     Function.prototype.call,
80     Function.prototype.apply,
81     String.prototype.toString,
82     String.prototype.valueOf,
83     Boolean.prototype.toString,
84     Boolean.prototype.valueOf,
85     Number.prototype.toString,
86     Number.prototype.valueOf,
87     Number.prototype.toFixed,
88     Number.prototype.toExponential,
89     Number.prototype.toPrecision,
90     Date.prototype.toString,
91     Date.prototype.toDateString,
92     Date.prototype.toTimeString,
93     Date.prototype.toLocaleString,
94     Date.prototype.toLocaleDateString,
95     Date.prototype.toLocaleTimeString,
96     Date.prototype.valueOf,
97     Date.prototype.getTime,
98     Date.prototype.getFullYear,
99     Date.prototype.getUTCFullYear,
100     Date.prototype.getMonth,
101     Date.prototype.getUTCMonth,
102     Date.prototype.getDate,
103     Date.prototype.getUTCDate,
104     Date.prototype.getDay,
105     Date.prototype.getUTCDay,
106     Date.prototype.getHours,
107     Date.prototype.getUTCHours,
108     Date.prototype.getMinutes,
109     Date.prototype.getUTCMinutes,
110     Date.prototype.getSeconds,
111     Date.prototype.getUTCSeconds,
112     Date.prototype.getMilliseconds,
113     Date.prototype.getUTCMilliseconds,
114     Date.prototype.getTimezoneOffset,
115     Date.prototype.setTime,
116     Date.prototype.setMilliseconds,
117     Date.prototype.setUTCMilliseconds,
118     Date.prototype.setSeconds,
119     Date.prototype.setUTCSeconds,
120     Date.prototype.setMinutes,
121     Date.prototype.setUTCMinutes,
122     Date.prototype.setHours,
123     Date.prototype.setUTCHours,
124     Date.prototype.setDate,
125     Date.prototype.setUTCDate,
126     Date.prototype.setMonth,
127     Date.prototype.setUTCMonth,
128     Date.prototype.setFullYear,
129     Date.prototype.setUTCFullYear,
130     Date.prototype.toUTCString,
131     Date.prototype.toISOString,
132     Date.prototype.toJSON,
133     RegExp.prototype.exec,
134     RegExp.prototype.test,
135     RegExp.prototype.toString,
136     Error.prototype.toString];
137
138
139// Mapping functions.
140var mapping_functions =
141    [Array.prototype.every,
142     Array.prototype.some,
143     Array.prototype.forEach,
144     Array.prototype.map,
145     Array.prototype.filter];
146
147// Reduce functions.
148var reducing_functions =
149    [Array.prototype.reduce,
150     Array.prototype.reduceRight];
151
152function checkExpectedMessage(e) {
153  assertTrue(e.message.indexOf("called on null or undefined") >= 0 ||
154      e.message.indexOf("invoked on undefined or null value") >= 0 ||
155      e.message.indexOf("Cannot convert undefined or null to object") >= 0);
156}
157
158// Test that all natives using the ToObject call throw the right exception.
159for (var i = 0; i < should_throw_on_null_and_undefined.length; i++) {
160  // Sanity check that all functions are correct
161  assertEquals(typeof(should_throw_on_null_and_undefined[i]), "function");
162
163  var exception = false;
164  try {
165    // We call all functions with no parameters, which means that essential
166    // parameters will have the undefined value.
167    // The test for whether the "this" value is null or undefined is always
168    // performed before access to the other parameters, so even if the
169    // undefined value is an invalid argument value, it mustn't change
170    // the result of the test.
171    should_throw_on_null_and_undefined[i].call(null);
172  } catch (e) {
173    exception = true;
174    checkExpectedMessage(e);
175  }
176  assertTrue(exception);
177
178  exception = false;
179  try {
180    should_throw_on_null_and_undefined[i].call(undefined);
181  } catch (e) {
182    exception = true;
183    checkExpectedMessage(e);
184  }
185  assertTrue(exception);
186
187  exception = false;
188  try {
189    should_throw_on_null_and_undefined[i].apply(null);
190  } catch (e) {
191    exception = true;
192    checkExpectedMessage(e);
193  }
194  assertTrue(exception);
195
196  exception = false;
197  try {
198    should_throw_on_null_and_undefined[i].apply(undefined);
199  } catch (e) {
200    exception = true;
201    checkExpectedMessage(e);
202  }
203  assertTrue(exception);
204}
205
206// Test that all natives that are non generic throw on null and undefined.
207for (var i = 0; i < non_generic.length; i++) {
208  // Sanity check that all functions are correct
209  assertEquals(typeof(non_generic[i]), "function");
210
211  exception = false;
212  try {
213    non_generic[i].call(null);
214  } catch (e) {
215    exception = true;
216    assertTrue(e instanceof TypeError);
217  }
218  assertTrue(exception);
219
220  exception = false;
221  try {
222    non_generic[i].call(null);
223  } catch (e) {
224    exception = true;
225    assertTrue(e instanceof TypeError);
226  }
227  assertTrue(exception);
228
229  exception = false;
230  try {
231    non_generic[i].apply(null);
232  } catch (e) {
233    exception = true;
234    assertTrue(e instanceof TypeError);
235  }
236  assertTrue(exception);
237
238  exception = false;
239  try {
240    non_generic[i].apply(null);
241  } catch (e) {
242    exception = true;
243    assertTrue(e instanceof TypeError);
244  }
245  assertTrue(exception);
246}
247
248
249// Test that we still throw when calling with thisArg null or undefined
250// through an array mapping function.
251var array = [1,2,3,4,5];
252for (var j = 0; j < mapping_functions.length; j++) {
253  for (var i = 0; i < should_throw_on_null_and_undefined.length; i++) {
254    exception = false;
255    try {
256      mapping_functions[j].call(array,
257                                should_throw_on_null_and_undefined[i],
258                                null);
259    } catch (e) {
260      exception = true;
261      checkExpectedMessage(e);
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      checkExpectedMessage(e);
273    }
274    assertTrue(exception);
275  }
276}
277
278for (var j = 0; j < mapping_functions.length; j++) {
279  for (var i = 0; i < non_generic.length; i++) {
280    exception = false;
281    try {
282      mapping_functions[j].call(array,
283                                non_generic[i],
284                                null);
285    } catch (e) {
286      exception = true;
287      assertTrue(e instanceof TypeError);
288    }
289    assertTrue(exception);
290
291    exception = false;
292    try {
293      mapping_functions[j].call(array,
294                                non_generic[i],
295                                undefined);
296    } catch (e) {
297      exception = true;
298      assertTrue(e instanceof TypeError);
299    }
300    assertTrue(exception);
301  }
302}
303
304
305// Reduce functions do a call with null as this argument.
306for (var j = 0; j < reducing_functions.length; j++) {
307  for (var i = 0; i < should_throw_on_null_and_undefined.length; i++) {
308    exception = false;
309    try {
310      reducing_functions[j].call(array, should_throw_on_null_and_undefined[i]);
311    } catch (e) {
312      exception = true;
313      checkExpectedMessage(e);
314    }
315    assertTrue(exception);
316
317    exception = false;
318    try {
319      reducing_functions[j].call(array, should_throw_on_null_and_undefined[i]);
320    } catch (e) {
321      exception = true;
322      checkExpectedMessage(e);
323    }
324    assertTrue(exception);
325  }
326}
327
328for (var j = 0; j < reducing_functions.length; j++) {
329  for (var i = 0; i < non_generic.length; i++) {
330    exception = false;
331    try {
332      reducing_functions[j].call(array, non_generic[i]);
333    } catch (e) {
334      exception = true;
335      assertTrue(e instanceof TypeError);
336    }
337    assertTrue(exception);
338
339    exception = false;
340    try {
341      reducing_functions[j].call(array, non_generic[i]);
342    } catch (e) {
343      exception = true;
344      assertTrue(e instanceof TypeError);
345    }
346    assertTrue(exception);
347  }
348}
349
350
351// Object.prototype.toString()
352assertEquals(Object.prototype.toString.call(null),
353             '[object Null]')
354
355assertEquals(Object.prototype.toString.call(undefined),
356             '[object Undefined]')
357