blob: a2275c1b82011064103a1480731cada3fed2cfee [file] [log] [blame]
/*
* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/licenses/publicdomain/
*/
//-----------------------------------------------------------------------------
var BUGNUMBER = 619283;
var summary =
"ECMAScript built-in methods that immediately throw when |this| is " +
"|undefined| or |null| (due to CheckObjectCoercible, ToObject, or ToString)";
print(BUGNUMBER + ": " + summary);
/**************
* BEGIN TEST *
**************/
// We can't just exhaustively loop over everything because 1) method properties
// might be extensions with special |this| handling, and 2) some methods don't
// *quite* immediately throw a TypeError, first thing, if |this| is |undefined|
// or |null|, or their algorithms are very slightly ambiguous about whether they
// do. Why? Ipse-dixitism. *shrug*
var ClassToMethodMap =
{
Object: [/* "toString" has special |this| handling */
"toLocaleString", "valueOf", "hasOwnProperty",
/*
* "isPrototypeOf" has special |this| handling already tested in
* ecma_5/Object/isPrototypeOf.js.
*/
/*
* "isPrototypeOf" has special |this| handling already tested in
* ecma_5/Object/propertyIsEnumerable.js.
*/],
// Function methods often don't ToObject(this) as their very first step,
// and they're already stepwise well-tested such that manual tests here
// would be redundant.
Array: ["toString", "toLocaleString", "concat", "join", "pop", "push",
"reverse", "shift", "slice", "sort", "splice", "unshift",
"indexOf", "lastIndexOf", "every", "some", "forEach", "map",
"filter", "reduce", "reduceRight"],
String: ["toString", "valueOf", "charAt", "charCodeAt", "concat",
"indexOf", "lastIndexOf", "localeCompare", "match", "replace",
"search", "slice", "split", "substring", "toLowerCase",
"toLocaleLowerCase", "toUpperCase", "toLocaleUpperCase", "trim",
/*
* "trimLeft" and "trimRight" are non-standard and thus are tested
* in ecma_5/extensions/trim-extensions.js.
*/
],
Boolean: ["toString", "valueOf"],
Number: ["toString", "toLocaleString", "valueOf",
/*
* toFixed doesn't *immediately* test |this| for number or
* Number-ness, but because the ToInteger(void 0) which arguably
* precedes it in the toFixed algorithm won't throw in this test,
* we don't need to specially test it.
*/
"toFixed",
"toExponential", "toPrecision"],
Date: ["toDateString", "toTimeString", "toLocaleString",
"toLocaleDateString", "toLocaleTimeString", "valueOf", "getTime",
"getFullYear", "getUTCFullYear", "getMonth", "getUTCMonth",
"getDate", "getUTCDate", "getDay", "getUTCDay", "getHours",
"getUTCHours", "getMinutes", "getUTCMinutes", "getSeconds",
"getUTCSeconds", "getMilliseconds", "getUTCMilliseconds",
/*
* toFixed doesn't *immediately* test |this| for number or
* Number-ness, but because the TimeClip(ToNumber(void 0)) which
* arguably precedes it in the setTime algorithm won't throw in
* this test, we don't need to specially test it.
*/
"setTime",
"getTimezoneOffset", "setMilliseconds", "setUTCMilliseconds",
"setSeconds", "setUTCSeconds", "setMinutes", "setUTCMinutes",
"setHours", "setUTCHours", "setDate", "setUTCDate", "setMonth",
"setUTCMonth", "setFullYear", "setUTCFullYear", "toUTCString",
"toISOString", "toJSON"],
RegExp: ["exec", "test", "toString"],
Error: ["toString"],
};
var badThisValues = [null, undefined];
function testMethod(Class, className, method)
{
var expr;
// Try out explicit this values
for (var i = 0, sz = badThisValues.length; i < sz; i++)
{
var badThis = badThisValues[i];
expr = className + ".prototype." + method + ".call(" + badThis + ")";
try
{
Class.prototype[method].call(badThis);
throw new Error(expr + " didn't throw a TypeError");
}
catch (e)
{
assertEq(e instanceof TypeError, true,
"wrong error for " + expr + ", instead threw " + e);
}
expr = className + ".prototype." + method + ".apply(" + badThis + ")";
try
{
Class.prototype[method].apply(badThis);
throw new Error(expr + " didn't throw a TypeError");
}
catch (e)
{
assertEq(e instanceof TypeError, true,
"wrong error for " + expr + ", instead threw " + e);
}
}
// ..and for good measure..
expr = "(0, " + className + ".prototype." + method + ")()"
try
{
// comma operator to call GetValue() on the method and de-Reference it
(0, Class.prototype[method])();
throw new Error(expr + " didn't throw a TypeError");
}
catch (e)
{
assertEq(e instanceof TypeError, true,
"wrong error for " + expr + ", instead threw " + e);
}
}
for (var className in ClassToMethodMap)
{
var Class = this[className];
var methodNames = ClassToMethodMap[className];
for (var i = 0, sz = methodNames.length; i < sz; i++)
{
var method = methodNames[i];
testMethod(Class, className, method);
}
}
/******************************************************************************/
if (typeof reportCompare === "function")
reportCompare(true, true);
print("All tests passed!");