1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/js/src/tests/ecma_5/misc/builtin-methods-reject-null-undefined-this.js Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,153 @@ 1.4 +/* 1.5 + * Any copyright is dedicated to the Public Domain. 1.6 + * http://creativecommons.org/licenses/publicdomain/ 1.7 + */ 1.8 + 1.9 +//----------------------------------------------------------------------------- 1.10 +var BUGNUMBER = 619283; 1.11 +var summary = 1.12 + "ECMAScript built-in methods that immediately throw when |this| is " + 1.13 + "|undefined| or |null| (due to CheckObjectCoercible, ToObject, or ToString)"; 1.14 + 1.15 +print(BUGNUMBER + ": " + summary); 1.16 + 1.17 +/************** 1.18 + * BEGIN TEST * 1.19 + **************/ 1.20 + 1.21 +// We can't just exhaustively loop over everything because 1) method properties 1.22 +// might be extensions with special |this| handling, and 2) some methods don't 1.23 +// *quite* immediately throw a TypeError, first thing, if |this| is |undefined| 1.24 +// or |null|, or their algorithms are very slightly ambiguous about whether they 1.25 +// do. Why? Ipse-dixitism. *shrug* 1.26 + 1.27 +var ClassToMethodMap = 1.28 + { 1.29 + Object: [/* "toString" has special |this| handling */ 1.30 + "toLocaleString", "valueOf", "hasOwnProperty", 1.31 + /* 1.32 + * "isPrototypeOf" has special |this| handling already tested in 1.33 + * ecma_5/Object/isPrototypeOf.js. 1.34 + */ 1.35 + /* 1.36 + * "isPrototypeOf" has special |this| handling already tested in 1.37 + * ecma_5/Object/propertyIsEnumerable.js. 1.38 + */], 1.39 + // Function methods often don't ToObject(this) as their very first step, 1.40 + // and they're already stepwise well-tested such that manual tests here 1.41 + // would be redundant. 1.42 + Array: ["toString", "toLocaleString", "concat", "join", "pop", "push", 1.43 + "reverse", "shift", "slice", "sort", "splice", "unshift", 1.44 + "indexOf", "lastIndexOf", "every", "some", "forEach", "map", 1.45 + "filter", "reduce", "reduceRight"], 1.46 + String: ["toString", "valueOf", "charAt", "charCodeAt", "concat", 1.47 + "indexOf", "lastIndexOf", "localeCompare", "match", "replace", 1.48 + "search", "slice", "split", "substring", "toLowerCase", 1.49 + "toLocaleLowerCase", "toUpperCase", "toLocaleUpperCase", "trim", 1.50 + /* 1.51 + * "trimLeft" and "trimRight" are non-standard and thus are tested 1.52 + * in ecma_5/extensions/trim-extensions.js. 1.53 + */ 1.54 + ], 1.55 + Boolean: ["toString", "valueOf"], 1.56 + Number: ["toString", "toLocaleString", "valueOf", 1.57 + /* 1.58 + * toFixed doesn't *immediately* test |this| for number or 1.59 + * Number-ness, but because the ToInteger(void 0) which arguably 1.60 + * precedes it in the toFixed algorithm won't throw in this test, 1.61 + * we don't need to specially test it. 1.62 + */ 1.63 + "toFixed", 1.64 + "toExponential", "toPrecision"], 1.65 + Date: ["toString", "toDateString", "toTimeString", "toLocaleString", 1.66 + "toLocaleDateString", "toLocaleTimeString", "valueOf", "getTime", 1.67 + "getFullYear", "getUTCFullYear", "getMonth", "getUTCMonth", 1.68 + "getDate", "getUTCDate", "getDay", "getUTCDay", "getHours", 1.69 + "getUTCHours", "getMinutes", "getUTCMinutes", "getSeconds", 1.70 + "getUTCSeconds", "getMilliseconds", "getUTCMilliseconds", 1.71 + /* 1.72 + * toFixed doesn't *immediately* test |this| for number or 1.73 + * Number-ness, but because the TimeClip(ToNumber(void 0)) which 1.74 + * arguably precedes it in the setTime algorithm won't throw in 1.75 + * this test, we don't need to specially test it. 1.76 + */ 1.77 + "setTime", 1.78 + "getTimezoneOffset", "setMilliseconds", "setUTCMilliseconds", 1.79 + "setSeconds", "setUTCSeconds", "setMinutes", "setUTCMinutes", 1.80 + "setHours", "setUTCHours", "setDate", "setUTCDate", "setMonth", 1.81 + "setUTCMonth", "setFullYear", "setUTCFullYear", "toUTCString", 1.82 + "toISOString", "toJSON"], 1.83 + RegExp: ["exec", "test", "toString"], 1.84 + Error: ["toString"], 1.85 + }; 1.86 + 1.87 +var badThisValues = [null, undefined]; 1.88 + 1.89 +function testMethod(Class, className, method) 1.90 +{ 1.91 + var expr; 1.92 + 1.93 + // Try out explicit this values 1.94 + for (var i = 0, sz = badThisValues.length; i < sz; i++) 1.95 + { 1.96 + var badThis = badThisValues[i]; 1.97 + 1.98 + expr = className + ".prototype." + method + ".call(" + badThis + ")"; 1.99 + try 1.100 + { 1.101 + Class.prototype[method].call(badThis); 1.102 + throw new Error(expr + " didn't throw a TypeError"); 1.103 + } 1.104 + catch (e) 1.105 + { 1.106 + assertEq(e instanceof TypeError, true, 1.107 + "wrong error for " + expr + ", instead threw " + e); 1.108 + } 1.109 + 1.110 + expr = className + ".prototype." + method + ".apply(" + badThis + ")"; 1.111 + try 1.112 + { 1.113 + Class.prototype[method].apply(badThis); 1.114 + throw new Error(expr + " didn't throw a TypeError"); 1.115 + } 1.116 + catch (e) 1.117 + { 1.118 + assertEq(e instanceof TypeError, true, 1.119 + "wrong error for " + expr + ", instead threw " + e); 1.120 + } 1.121 + } 1.122 + 1.123 + // ..and for good measure.. 1.124 + 1.125 + expr = "(0, " + className + ".prototype." + method + ")()" 1.126 + try 1.127 + { 1.128 + // comma operator to call GetValue() on the method and de-Reference it 1.129 + (0, Class.prototype[method])(); 1.130 + throw new Error(expr + " didn't throw a TypeError"); 1.131 + } 1.132 + catch (e) 1.133 + { 1.134 + assertEq(e instanceof TypeError, true, 1.135 + "wrong error for " + expr + ", instead threw " + e); 1.136 + } 1.137 +} 1.138 + 1.139 +for (var className in ClassToMethodMap) 1.140 +{ 1.141 + var Class = this[className]; 1.142 + 1.143 + var methodNames = ClassToMethodMap[className]; 1.144 + for (var i = 0, sz = methodNames.length; i < sz; i++) 1.145 + { 1.146 + var method = methodNames[i]; 1.147 + testMethod(Class, className, method); 1.148 + } 1.149 +} 1.150 + 1.151 +/******************************************************************************/ 1.152 + 1.153 +if (typeof reportCompare === "function") 1.154 + reportCompare(true, true); 1.155 + 1.156 +print("All tests passed!");