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 need to pass a dummy object argument ({}) to these functions because
166    // of Object.prototype.isPrototypeOf's special behavior, see issue 3483
167    // for more details.
168    should_throw_on_null_and_undefined[i].call(null, {});
169  } catch (e) {
170    exception = true;
171    checkExpectedMessage(e);
172  }
173  assertTrue(exception);
174
175  exception = false;
176  try {
177    should_throw_on_null_and_undefined[i].call(undefined, {});
178  } catch (e) {
179    exception = true;
180    checkExpectedMessage(e);
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    checkExpectedMessage(e);
190  }
191  assertTrue(exception);
192
193  exception = false;
194  try {
195    should_throw_on_null_and_undefined[i].apply(undefined, [{}]);
196  } catch (e) {
197    exception = true;
198    checkExpectedMessage(e);
199  }
200  assertTrue(exception);
201}
202
203// Test that all natives that are non generic throw on null and undefined.
204for (var i = 0; i < non_generic.length; i++) {
205  // Sanity check that all functions are correct
206  assertEquals(typeof(non_generic[i]), "function");
207
208  exception = false;
209  try {
210    non_generic[i].call(null);
211  } catch (e) {
212    exception = true;
213    assertTrue(e instanceof TypeError);
214  }
215  assertTrue(exception);
216
217  exception = false;
218  try {
219    non_generic[i].call(null);
220  } catch (e) {
221    exception = true;
222    assertTrue(e instanceof TypeError);
223  }
224  assertTrue(exception);
225
226  exception = false;
227  try {
228    non_generic[i].apply(null);
229  } catch (e) {
230    exception = true;
231    assertTrue(e instanceof TypeError);
232  }
233  assertTrue(exception);
234
235  exception = false;
236  try {
237    non_generic[i].apply(null);
238  } catch (e) {
239    exception = true;
240    assertTrue(e instanceof TypeError);
241  }
242  assertTrue(exception);
243}
244
245
246// Test that we still throw when calling with thisArg null or undefined
247// through an array mapping function.
248// We need to make sure that the elements of `array` are all object values,
249// see issue 3483 for more details.
250var array = [{}, [], new Number, new Map, new WeakSet];
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      checkExpectedMessage(e);
261    }
262    assertTrue(exception);
263
264    exception = false;
265    try {
266      mapping_functions[j].call(array,
267                                should_throw_on_null_and_undefined[i],
268                                undefined);
269    } catch (e) {
270      exception = true;
271      checkExpectedMessage(e);
272    }
273    assertTrue(exception);
274  }
275}
276
277for (var j = 0; j < mapping_functions.length; j++) {
278  for (var i = 0; i < non_generic.length; i++) {
279    exception = false;
280    try {
281      mapping_functions[j].call(array,
282                                non_generic[i],
283                                null);
284    } catch (e) {
285      exception = true;
286      assertTrue(e instanceof TypeError);
287    }
288    assertTrue(exception);
289
290    exception = false;
291    try {
292      mapping_functions[j].call(array,
293                                non_generic[i],
294                                undefined);
295    } catch (e) {
296      exception = true;
297      assertTrue(e instanceof TypeError);
298    }
299    assertTrue(exception);
300  }
301}
302
303
304// Reduce functions do a call with null as this argument.
305for (var j = 0; j < reducing_functions.length; j++) {
306  for (var i = 0; i < should_throw_on_null_and_undefined.length; i++) {
307    exception = false;
308    try {
309      reducing_functions[j].call(array, should_throw_on_null_and_undefined[i]);
310    } catch (e) {
311      exception = true;
312      checkExpectedMessage(e);
313    }
314    assertTrue(exception);
315
316    exception = false;
317    try {
318      reducing_functions[j].call(array, should_throw_on_null_and_undefined[i]);
319    } catch (e) {
320      exception = true;
321      checkExpectedMessage(e);
322    }
323    assertTrue(exception);
324  }
325}
326
327for (var j = 0; j < reducing_functions.length; j++) {
328  for (var i = 0; i < non_generic.length; i++) {
329    exception = false;
330    try {
331      reducing_functions[j].call(array, non_generic[i]);
332    } catch (e) {
333      exception = true;
334      assertTrue(e instanceof TypeError);
335    }
336    assertTrue(exception);
337
338    exception = false;
339    try {
340      reducing_functions[j].call(array, non_generic[i]);
341    } catch (e) {
342      exception = true;
343      assertTrue(e instanceof TypeError);
344    }
345    assertTrue(exception);
346  }
347}
348
349
350// Object.prototype.toString()
351assertEquals(Object.prototype.toString.call(null),
352             '[object Null]')
353
354assertEquals(Object.prototype.toString.call(undefined),
355             '[object Undefined]')
356