toPrimitive.js 57 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074
  1. //-------------------------------------------------------------------------------------------------------
  2. // Copyright (C) Microsoft. All rights reserved.
  3. // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
  4. //-------------------------------------------------------------------------------------------------------
  5. WScript.LoadScriptFile("..\\UnitTestFramework\\UnitTestFramework.js");
  6. function AddNumbers(first, second)
  7. {
  8. return first + second;
  9. }
  10. var tests = [
  11. {
  12. name: "Number Object Test",
  13. body: function ()
  14. {
  15. var a = new Number(1);
  16. a[Symbol.toPrimitive] = function(hint)
  17. {
  18. if(hint == "string")
  19. {
  20. return "a";
  21. }
  22. else
  23. {
  24. return 10;
  25. }
  26. }
  27. assert.isTrue(10 == a,"should now call @@toprimitive and return 10");
  28. assert.isTrue(11 == a+1,"should now call @@toprimitive with default hint and return 10 then add 1 = 11");
  29. assert.areEqual("a",String(a),"should now call @@toPrimitive and return a");
  30. }
  31. },
  32. {
  33. name: "Symbol Tests",
  34. body: function ()
  35. {
  36. var o = Object.getOwnPropertyDescriptor(Symbol,"toPrimitive");
  37. assert.isFalse(o.writable, "Symbol @@toPrimitive is not writable");
  38. assert.isFalse(o.enumerable, "Symbol @@toPrimitive is not enumerable");
  39. assert.isFalse(o.configurable, "Symbol @@toPrimitive is not configurable");
  40. assert.areEqual("[Symbol.toPrimitive]", Symbol.prototype[Symbol.toPrimitive].name, "string should be [Symbol.toPrimitive]");
  41. var o = Object.getOwnPropertyDescriptor(Symbol.prototype,Symbol.toPrimitive);
  42. assert.isFalse(o.writable, "Symbol @@toPrimitive is not writable");
  43. assert.isFalse(o.enumerable, "Symbol @@toPrimitive is not enumerable");
  44. assert.isTrue(o.configurable, "Symbol @@toPrimitive is configurable");
  45. assert.throws(function() { Symbol.prototype[Symbol.toPrimitive](); }, TypeError, "Symbol[@@toPrimitive] throws no matter the parameters", "Symbol[Symbol.toPrimitive]: 'this' is not a Symbol object");
  46. var s = Symbol();
  47. assert.areEqual(s, Object(s)[Symbol.toPrimitive](), ""); // true
  48. assert.areEqual(s, Symbol.prototype[Symbol.toPrimitive].call(s), ""); // true
  49. assert.areEqual(Symbol.toPrimitive, Symbol.toPrimitive[Symbol.toPrimitive](), "Symbol.toPrimitive");
  50. assert.areEqual(Symbol.iterator, Symbol.iterator[Symbol.toPrimitive](), "Symbol.iterator");
  51. assert.areEqual(Symbol.hasInstance, Symbol.hasInstance[Symbol.toPrimitive](), "Symbol.hasInstance");
  52. assert.areEqual(Symbol.isConcatSpreadable, Symbol.isConcatSpreadable[Symbol.toPrimitive](), "Symbol.isConcatSpreadable");
  53. assert.areEqual(Symbol.match, Symbol.match[Symbol.toPrimitive](), "Symbol.match");
  54. assert.areEqual(Symbol.replace, Symbol.replace[Symbol.toPrimitive](), "Symbol.replace");
  55. assert.areEqual(Symbol.search, Symbol.search[Symbol.toPrimitive](), "Symbol.search");
  56. assert.areEqual(Symbol.split, Symbol.split[Symbol.toPrimitive](), "Symbol.split");
  57. assert.areEqual(Symbol.toStringTag, Symbol.toStringTag[Symbol.toPrimitive](), "Symbol.toStringTag");
  58. assert.areEqual(Symbol.unscopables, Symbol.unscopables[Symbol.toPrimitive](), "Symbol.unscopables");
  59. }
  60. },
  61. {
  62. name: "Date Test",
  63. body: function ()
  64. {
  65. assert.areEqual("[Symbol.toPrimitive]", Date.prototype[Symbol.toPrimitive].name, "string should be [Symbol.toPrimitive]");
  66. var o = Object.getOwnPropertyDescriptor(Date.prototype,Symbol.toPrimitive);
  67. assert.isFalse(o.writable, "Date @@toPrimitive is not writable");
  68. assert.isFalse(o.enumerable, "Date @@toPrimitive is not enumerable");
  69. assert.isTrue(o.configurable, "Date @@toPrimitive is configurable");
  70. var d = new Date(2014,5,30,8, 30,45,2);
  71. assert.areEqual(d.toString(),d[Symbol.toPrimitive]("string"), "check that the string hint toPrimitive returns toString");
  72. assert.areEqual(d.toString(),d[Symbol.toPrimitive]("default"), "check that default has the same behaviour as string hint");
  73. assert.areEqual(d.valueOf(),d[Symbol.toPrimitive]("number"),"check that the number hint toPrimitive returns valueOf");
  74. assert.throws(function() {d[Symbol.toPrimitive]("boolean")}, TypeError, "boolean is an invalid hint");
  75. assert.throws(function() {d[Symbol.toPrimitive]({})}, TypeError, "provided hint must be strings or they results in a type error");
  76. assert.areEqual(d.toString()+10,d+10,"addition provides no hint resulting default hint which is string");
  77. assert.areEqual(d.valueOf(), (new Number(d)).valueOf(),"conversion toNumber calls toPrimitive with hint number");
  78. delete Date.prototype[Symbol.toPrimitive];
  79. assert.isFalse(Date.prototype.hasOwnProperty(Symbol.toPrimitive),"Property is configurable, should be able to delete");
  80. assert.areEqual(d.toString()+10,d+10,"(fall back to OriginalToPrimitive) addition provides no hint resulting default hint which is string");
  81. assert.areEqual(d.valueOf(), (new Number(d)).valueOf(),"(fall back to OriginalToPrimitive) conversion toNumber calls toPrimitive with hint number");
  82. Object.defineProperty(Date.prototype, Symbol.toPrimitive, o); // restore deleted [@@toPrimitive] property
  83. assert.throws(()=>(Date.prototype[Symbol.toPrimitive].call(undefined, "default")), TypeError, "this=undefined", "Date[Symbol.toPrimitive]: 'this' is not an Object");
  84. assert.throws(()=>(Date.prototype[Symbol.toPrimitive].call(null, "default")), TypeError, "this=null", "Date[Symbol.toPrimitive]: 'this' is not an Object");
  85. assert.throws(()=>(Date.prototype[Symbol.toPrimitive].call(true, "default")), TypeError, "this=true", "Date[Symbol.toPrimitive]: 'this' is not an Object");
  86. assert.throws(()=>(Date.prototype[Symbol.toPrimitive].call(false, "default")), TypeError, "this=false", "Date[Symbol.toPrimitive]: 'this' is not an Object");
  87. assert.throws(()=>(Date.prototype[Symbol.toPrimitive].call(0, "default")), TypeError, "this=0", "Date[Symbol.toPrimitive]: 'this' is not an Object");
  88. assert.throws(()=>(Date.prototype[Symbol.toPrimitive].call(NaN, "default")), TypeError, "this=NaN", "Date[Symbol.toPrimitive]: 'this' is not an Object");
  89. assert.throws(()=>(Date.prototype[Symbol.toPrimitive].call('', "default")), TypeError, "this=''", "Date[Symbol.toPrimitive]: 'this' is not an Object");
  90. assert.throws(()=>(Date.prototype[Symbol.toPrimitive].call('abc', "default")), TypeError, "this='abc'", "Date[Symbol.toPrimitive]: 'this' is not an Object");
  91. assert.throws(()=>(Date.prototype[Symbol.toPrimitive].call()), TypeError, "this=undefined no hint", "Date[Symbol.toPrimitive]: invalid hint");
  92. assert.throws(()=>(Date.prototype[Symbol.toPrimitive].call(undefined)), TypeError, "this=undefined hint=undefined", "Date[Symbol.toPrimitive]: invalid hint");
  93. assert.throws(()=>(Date.prototype[Symbol.toPrimitive].call(null)), TypeError, "this=null hint=undefined", "Date[Symbol.toPrimitive]: invalid hint");
  94. assert.throws(()=>(Date.prototype[Symbol.toPrimitive].call(true)), TypeError, "this=true hint=undefined", "Date[Symbol.toPrimitive]: invalid hint");
  95. assert.throws(()=>(Date.prototype[Symbol.toPrimitive].call(false)), TypeError, "this=false hint=undefined", "Date[Symbol.toPrimitive]: invalid hint");
  96. assert.throws(()=>(Date.prototype[Symbol.toPrimitive].call(0)), TypeError, "this=0 hint=undefined", "Date[Symbol.toPrimitive]: invalid hint");
  97. assert.throws(()=>(Date.prototype[Symbol.toPrimitive].call(NaN)), TypeError, "this=NaN hint=undefined", "Date[Symbol.toPrimitive]: invalid hint");
  98. assert.throws(()=>(Date.prototype[Symbol.toPrimitive].call('')), TypeError, "this='' hint=undefined", "Date[Symbol.toPrimitive]: invalid hint");
  99. assert.throws(()=>(Date.prototype[Symbol.toPrimitive].call('abc')), TypeError, "this='abc' hint=undefined", "Date[Symbol.toPrimitive]: invalid hint");
  100. assert.throws(()=>(Date.prototype[Symbol.toPrimitive].call(function(){})), TypeError, "this=function(){} hint=undefined", "Date[Symbol.toPrimitive]: invalid hint");
  101. assert.throws(()=>(d[Symbol.toPrimitive]()), TypeError, "no hint", "Date[Symbol.toPrimitive]: invalid hint");
  102. assert.throws(()=>(d[Symbol.toPrimitive](undefined)), TypeError, "hint=undefined", "Date[Symbol.toPrimitive]: invalid hint");
  103. assert.throws(()=>(d[Symbol.toPrimitive](null)), TypeError, "hint=null", "Date[Symbol.toPrimitive]: invalid hint");
  104. assert.throws(()=>(d[Symbol.toPrimitive](true)), TypeError, "hint=true", "Date[Symbol.toPrimitive]: invalid hint");
  105. assert.throws(()=>(d[Symbol.toPrimitive](false)), TypeError, "hint=false", "Date[Symbol.toPrimitive]: invalid hint");
  106. assert.throws(()=>(d[Symbol.toPrimitive](0)), TypeError, "hint=0", "Date[Symbol.toPrimitive]: invalid hint");
  107. assert.throws(()=>(d[Symbol.toPrimitive](NaN)), TypeError, "hint=NaN", "Date[Symbol.toPrimitive]: invalid hint");
  108. assert.throws(()=>(d[Symbol.toPrimitive]('')), TypeError, "hint=''", "Date[Symbol.toPrimitive]: invalid hint");
  109. assert.throws(()=>(d[Symbol.toPrimitive]('abc')), TypeError, "hint='abc'", "Date[Symbol.toPrimitive]: invalid hint");
  110. assert.throws(()=>(d[Symbol.toPrimitive](function(){})), TypeError, "hint=function(){}", "Date[Symbol.toPrimitive]: invalid hint");
  111. assert.throws(()=>(d[Symbol.toPrimitive]({})), TypeError, "hint=={}", "Date[Symbol.toPrimitive]: invalid hint");
  112. }
  113. },
  114. {
  115. name: "Object toPrimitive Test",
  116. body: function ()
  117. {
  118. var o = { toString : function () {return "o"}, valueOf : function() { return 0;}};
  119. o[Symbol.toPrimitive] = function(hint)
  120. {
  121. if("string" == hint)
  122. {
  123. return this.toString()+" (hint String)";
  124. }
  125. else if("number" == hint)
  126. {
  127. return this.valueOf()+2;
  128. }
  129. else
  130. {
  131. return " (hint default) ";
  132. }
  133. }
  134. assert.areEqual(" (hint default) ", o[Symbol.toPrimitive](), "Test to check the string is properly being returned");
  135. assert.areEqual("o (hint String)", o[Symbol.toPrimitive]("string"), "Test to check the string is properly being returned");
  136. assert.areEqual(2, o[Symbol.toPrimitive]("number"), "Test to check the integer is properly being returned");
  137. assert.areEqual(2,(new Number(o)).valueOf(),"toNumber should call toPrimitive which should invoke the user defined behaviour for @@toPrimitive with hint number"); // conversion toNumber -> toPrimitive(hint number)
  138. assert.areEqual("1 (hint default) 1",1+o+1,"add should call toPrimitive which should invoke the user defined behaviour for @@toPrimitive with no hint"); // add -> toPrimitive(hint none)
  139. assert.areEqual("o (hint String)",(new String(o)).toString(),"toString should call toPrimitive which should invoke the user defined behaviour for @@toPrimitive with hint string"); // conversion toString -> toPrimitive(hint string)
  140. }
  141. },
  142. {
  143. name: "Object toPrimitive must be Function or null else Throws typeError",
  144. body: function ()
  145. {
  146. var o = { toString : function () {return "o"}, valueOf : function() { return 0;}};
  147. o[Symbol.toPrimitive] = {}; // can only be a function else type error
  148. assert.throws(function() {var a = o+1;}, TypeError, "o[Symbol.toPrimitive] must be a function", "The value of the property 'Symbol.toPrimitive' is not a Function object");
  149. o[Symbol.toPrimitive] = null;
  150. assert.doesNotThrow(function() {var a = o+1;}, "If o[Symbol.toPrimitive] is null it is ignored");
  151. }
  152. },
  153. // In ScriptLanguageVersion6 the ActiveXObject constructor is removed and is unable to be used for this test. Disabling until different object type can be found
  154. // that can be used instead.
  155. // {
  156. // name: "Object toPrimitive must return ECMA Type else TypeError",
  157. // body: function ()
  158. // {
  159. // var o = { toString : function () {return "o"}, valueOf : function() { return 0;}};
  160. // var c = new ActiveXObject("Excel.Application");
  161. // o[Symbol.toPrimitive] = function(hint)
  162. // {
  163. // return c;
  164. // }
  165. // assert.throws(function() {var a = o+1;}, TypeError, "o[Symbol.toPrimitive] must return an ECMA language value");
  166. //
  167. // }
  168. // },
  169. {
  170. name: "String Object Test",
  171. body: function ()
  172. {
  173. var a = new String("a");
  174. a[Symbol.toPrimitive] = function(hint)
  175. {
  176. if(hint == "string")
  177. {
  178. return "var_a";
  179. }
  180. else
  181. {
  182. return -1;
  183. }
  184. }
  185. assert.isTrue(-1 == a,"should now call @@toprimitive and return -1");
  186. assert.isTrue("var_a" == String(a),"should now call @@toprimitive and return var_a");
  187. assert.isTrue(0 == a+1,"should now call @@toprimitive and return -1+1 = 0");
  188. assert.isTrue("var_a1" == String(a)+1,"should now call @@toprimitive and return var_a1");
  189. assert.areEqual(-1,Number(a),"should now call @@toPrimitive and return a");
  190. }
  191. },
  192. {
  193. name: "ToPrimitive calling user-defined [@@toPrimitive] method",
  194. body: function ()
  195. {
  196. var o = {}, o1 = {}, o2 = {};
  197. var retVal, hint;
  198. o[Symbol.toPrimitive] = function(h) { hint.push(h); return retVal; }
  199. o1[Symbol.toPrimitive] = function(h) { hint.push("o1:"+h); return retVal; }
  200. o2[Symbol.toPrimitive] = function(h) { hint.push("o2:"+h); return retVal; }
  201. // Ensuring OrdinaryToPrimitive is not called
  202. Object.defineProperty(o, "toString", { writable:true, configurable:true, enumerable:true, value: function() { throw Error("Unexpected toString() call on o"); } });
  203. Object.defineProperty(o1, "toString", { writable:true, configurable:true, enumerable:true, value: function() { throw Error("Unexpected toString() call on o1"); } });
  204. Object.defineProperty(o2, "toString", { writable:true, configurable:true, enumerable:true, value: function() { throw Error("Unexpected toString() call on o2"); } });
  205. Object.defineProperty(o, "valueOf", { writable:true, configurable:true, enumerable:true, value: function() { throw Error("Unexpected valueOf() call on o"); } });
  206. Object.defineProperty(o1, "valueOf", { writable:true, configurable:true, enumerable:true, value: function() { throw Error("Unexpected valueOf() call on o1"); } });
  207. Object.defineProperty(o2, "valueOf", { writable:true, configurable:true, enumerable:true, value: function() { throw Error("Unexpected valueOf() call on o2"); } });
  208. var verifyToPrimitive = function(func, expectedResult, expectedHint, description) {
  209. hint = [];
  210. assert.areEqual(expectedResult, func(), "result:" + description);
  211. assert.areEqual(expectedHint, hint, "hint:" + description);
  212. }
  213. //
  214. // ToNumber calls ToPrimitive(input, 'number')
  215. //
  216. retVal = NaN;
  217. verifyToPrimitive(()=>Number(o), NaN, ["number"], "Number()");
  218. verifyToPrimitive(()=>new Uint8Array([o]), new Uint8Array([NaN]), ["number"], "TypedArray constructor");
  219. verifyToPrimitive(()=>isFinite(o), false, ["number"], "isFinite()");
  220. verifyToPrimitive(()=>isNaN(o), true, ["number"], "isNaN()");
  221. retVal = 100;
  222. verifyToPrimitive(()=>(1-o), -99, ["number"], "1-o");
  223. verifyToPrimitive(()=>(o-2), 98, ["number"], "o-2");
  224. verifyToPrimitive(()=>(1*o), 100, ["number"], "1*o");
  225. verifyToPrimitive(()=>(o*2), 200, ["number"], "o*2");
  226. verifyToPrimitive(()=>Math.log10(o), 2, ["number"], "Math.log10()");
  227. verifyToPrimitive(()=>(o1-o2), 0, ["o1:number", "o2:number"], "o1-o2");
  228. verifyToPrimitive(()=>(o2/o1), 1, ["o2:number", "o1:number"], "o2/o1");
  229. retVal = 100;
  230. var n = o;
  231. verifyToPrimitive(()=>(++n), 101, ["number"], "++n");
  232. n = o;
  233. verifyToPrimitive(()=>(n++), 100, ["number"], "n++");
  234. n = o;
  235. verifyToPrimitive(()=>(--n), 99, ["number"], "--n");
  236. n = o;
  237. verifyToPrimitive(()=>(n--), 100, ["number"], "n--");
  238. retVal = "abc";
  239. verifyToPrimitive(()=>(1-o), NaN, ["number"], "1-o ([@@toPrimitive] returns string)");
  240. verifyToPrimitive(()=>(o-2), NaN, ["number"], "o-2 ([@@toPrimitive] returns string)");
  241. //
  242. // ToString calls ToPrimitive(input, 'string')
  243. //
  244. retVal = NaN;
  245. verifyToPrimitive(()=>String(o), "NaN", ["string"], "String()");
  246. verifyToPrimitive(()=>parseFloat(o), NaN, ["string"], "parseFloat()");
  247. verifyToPrimitive(()=>parseInt(o), NaN, ["string"], "parseInt()");
  248. verifyToPrimitive(()=>decodeURI(o), "NaN", ["string"], "decodeURI()");
  249. //
  250. // ToPropertyKey calls ToPrimitive(input, 'string')
  251. //
  252. retVal = NaN;
  253. var x = {};
  254. verifyToPrimitive(()=>Object.defineProperty(x, o, {writable:true, enumerable:true, configurable:true, value: 'abc123'}), x, ["string"], "Object.defineProperty()");
  255. verifyToPrimitive(()=>x[o], 'abc123', ["string"], "x[o]");
  256. verifyToPrimitive(()=>x.hasOwnProperty(o), true, ["string"], "Object.prototype.hasOwnProperty()");
  257. verifyToPrimitive(()=>x.propertyIsEnumerable(o), true, ["string"], "Object.prototype.propertyIsEnumerable()");
  258. verifyToPrimitive(()=>(o in x), true, ["string"], "o in x");
  259. //
  260. // + operator calls ToPrimitive(input, 'default')
  261. //
  262. retVal = 100;
  263. verifyToPrimitive(()=>(o+1), 101, ["default"], "o+1");
  264. verifyToPrimitive(()=>(2+o), 102, ["default"], "2+o");
  265. verifyToPrimitive(()=>(o+'abc'), '100abc', ["default"], "o+'abc'");
  266. verifyToPrimitive(()=>('abc'+o), 'abc100', ["default"], "'abc'+o");
  267. verifyToPrimitive(()=>(o1+o2), 200, ["o1:default", "o2:default"], "o1+o2");
  268. verifyToPrimitive(()=>(o2+o1), 200, ["o2:default", "o1:default"], "o2+o1");
  269. retVal = "abc";
  270. verifyToPrimitive(()=>(o+1), "abc1", ["default"], "o+1 ([@@toPrimitive] returns string)");
  271. verifyToPrimitive(()=>(2+o), "2abc", ["default"], "2+1 ([@@toPrimitive] returns string)");
  272. verifyToPrimitive(()=>(o+'def'), 'abcdef', ["default"], "o+'def'");
  273. verifyToPrimitive(()=>('def'+o), 'defabc', ["default"], "'def'+o");
  274. verifyToPrimitive(()=>(o1+o2), "abcabc", ["o1:default", "o2:default"], "o1+o2");
  275. verifyToPrimitive(()=>(o2+o1), "abcabc", ["o2:default", "o1:default"], "o2+o1");
  276. //
  277. // abstract relational comparison calls ToPrimitive(input, "number")
  278. //
  279. retVal = 100;
  280. verifyToPrimitive(()=>(o<1), false, ["number"], "o<1");
  281. verifyToPrimitive(()=>(1<o), true, ["number"], "1<o");
  282. verifyToPrimitive(()=>(o<=25), false, ["number"], "o<=25");
  283. verifyToPrimitive(()=>(-9<=o), true, ["number"], "-9<=o");
  284. verifyToPrimitive(()=>(o>1), true, ["number"], "o>1");
  285. verifyToPrimitive(()=>(1>o), false, ["number"], "1>o");
  286. verifyToPrimitive(()=>(o>=25), true, ["number"], "o>=25");
  287. verifyToPrimitive(()=>(-9>=o), false, ["number"], "-9>=o");
  288. verifyToPrimitive(()=>(o1<o2), false, ["o1:number", "o2:number"], "o1<o2");
  289. verifyToPrimitive(()=>(o2<=o1), true, ["o2:number", "o1:number"], "o2<=o1");
  290. verifyToPrimitive(()=>(o1>o2), false, ["o1:number", "o2:number"], "o1>o2");
  291. verifyToPrimitive(()=>(o2>=o1), true, ["o2:number", "o1:number"], "o2>=o1");
  292. //
  293. // abstract equality comparison calls ToPrimitive(input, "default")
  294. //
  295. verifyToPrimitive(()=>(o1==o2), false, [], ""); // 1. If Type(x) is the same of Type(y) return Strict Equality Comparison x === y
  296. retVal = 100;
  297. verifyToPrimitive(()=>(o==100), true, ["default"], "o==100");
  298. verifyToPrimitive(()=>(100==o), true, ["default"], "100==o");
  299. verifyToPrimitive(()=>(o==1), false, ["default"], "o==1");
  300. verifyToPrimitive(()=>(1==o), false, ["default"], "1==o");
  301. retVal = true;
  302. verifyToPrimitive(()=>(o==true), true, ["default"], "o==true");
  303. verifyToPrimitive(()=>(true==o), true, ["default"], "true==o");
  304. verifyToPrimitive(()=>(o==false), false, ["default"], "o==false");
  305. verifyToPrimitive(()=>(false==o), false, ["default"], "false==o");
  306. retVal = 'abc';
  307. verifyToPrimitive(()=>(o=='abc'), true, ["default"], "o=='abc'");
  308. verifyToPrimitive(()=>('abc'==o), true, ["default"], "'abc'==o");
  309. verifyToPrimitive(()=>(o=='abc1'), false, ["default"], "o=='abc1'");
  310. verifyToPrimitive(()=>('abc1'==o), false, ["default"], "'abc1'==o");
  311. retVal = Symbol();
  312. verifyToPrimitive(()=>(o==retVal), true, ["default"], "o==retVal (retVal=Symbol())");
  313. verifyToPrimitive(()=>(retVal==o), true, ["default"], "retVal==o (retVal=Symbol())");
  314. verifyToPrimitive(()=>(o==Symbol()), false, ["default"], "o==Symbol()");
  315. verifyToPrimitive(()=>(Symbol()==o), false, ["default"], "Symbol()==o");
  316. //
  317. // Date constructor calls ToPrimitive(input, "default")
  318. //
  319. retVal = 'Jan 1, 2016';
  320. verifyToPrimitive(()=>new Date(o).valueOf(), new Date(retVal).valueOf(), ["default"], "Date() constructor");
  321. //
  322. // Date.prototype.toJSON calls ToPrimitive(input, "number")
  323. //
  324. retVal = NaN;
  325. verifyToPrimitive(()=>Date.prototype.toJSON.call(o), null, ["number"], "Date.prototype.toJSON()");
  326. //
  327. // Date.prototype[@@toPrimitive] calls ToPrimitive
  328. //
  329. Object.defineProperty(o, 'toString', { writable:true, configurable:true, enumerable:true, value: function() { return 'abc'; } });
  330. Object.defineProperty(o, 'valueOf', { writable:true, configurable:true, enumerable:true, value: function() { return 123; } });
  331. assert.areEqual(123, Date.prototype[Symbol.toPrimitive].call(o, 'number'), "Date.prototype[@@toPrimitive].call(o, 'number')");
  332. assert.areEqual('abc', Date.prototype[Symbol.toPrimitive].call(o, 'string'), "Date.prototype[@@toPrimitive].call(o, 'string')");
  333. assert.areEqual('abc', Date.prototype[Symbol.toPrimitive].call(o, 'default'), "Date.prototype[@@toPrimitive].call(o, 'default')");
  334. }
  335. },
  336. {
  337. name: "ToPrimitive calling user-defined [@@toPrimitive] method that returns Object throws TypeError",
  338. body: function ()
  339. {
  340. var o = {};
  341. [{}, new Date(), Error(), new String(), new Boolean(), new Number()].forEach(function(retVal) {
  342. o[Symbol.toPrimitive] = function(h) { return retVal; }
  343. //
  344. // ToNumber
  345. //
  346. assert.throws(()=>(Number(o)), TypeError, "Number()", "[Symbol.toPrimitive]: invalid argument");
  347. assert.throws(()=>new Uint8Array([o]), TypeError, "TypedArray constructor", "[Symbol.toPrimitive]: invalid argument");
  348. assert.throws(()=>isFinite(o), TypeError, "isFinite()", "[Symbol.toPrimitive]: invalid argument");
  349. assert.throws(()=>isNaN(o), TypeError, "isNaN()", "[Symbol.toPrimitive]: invalid argument");
  350. assert.throws(()=>(1-o), TypeError, "1-o", "[Symbol.toPrimitive]: invalid argument");
  351. assert.throws(()=>(o-2), TypeError, "o-2", "[Symbol.toPrimitive]: invalid argument");
  352. assert.throws(()=>(1*o), TypeError, "1*o", "[Symbol.toPrimitive]: invalid argument");
  353. assert.throws(()=>(o*2), TypeError, "o*2", "[Symbol.toPrimitive]: invalid argument");
  354. assert.throws(()=>Math.log10(o), TypeError, "Math.log10()", "[Symbol.toPrimitive]: invalid argument");
  355. var n = o;
  356. assert.throws(()=>(++n), TypeError, "++n", "[Symbol.toPrimitive]: invalid argument");
  357. n = o;
  358. assert.throws(()=>(n++), TypeError, "n++", "[Symbol.toPrimitive]: invalid argument");
  359. n = o;
  360. assert.throws(()=>(--n), TypeError, "--n", "[Symbol.toPrimitive]: invalid argument");
  361. n = o;
  362. assert.throws(()=>(n--), TypeError, "n--", "[Symbol.toPrimitive]: invalid argument");
  363. //
  364. // ToString
  365. //
  366. assert.throws(()=>String(o), TypeError, "String()", "[Symbol.toPrimitive]: invalid argument");
  367. assert.throws(()=>parseFloat(o), TypeError, "parseFloat()", "[Symbol.toPrimitive]: invalid argument");
  368. assert.throws(()=>parseInt(o), TypeError, "parseInt()", "[Symbol.toPrimitive]: invalid argument");
  369. assert.throws(()=>decodeURI(o), TypeError, "decodeURI()", "[Symbol.toPrimitive]: invalid argument");
  370. //
  371. // ToPropertyKey
  372. //
  373. var x = {};
  374. assert.throws(()=>Object.defineProperty(x, o, {}), TypeError, "Object.defineProperty()", "[Symbol.toPrimitive]: invalid argument");
  375. assert.throws(()=>x[o], TypeError, "x[o]", "[Symbol.toPrimitive]: invalid argument");
  376. assert.throws(()=>x.hasOwnProperty(o), TypeError, "Object.prototype.hasOwnProperty()", "[Symbol.toPrimitive]: invalid argument");
  377. assert.throws(()=>x.propertyIsEnumerable(o), TypeError, "Object.prototype.propertyIsEnumerable()", "[Symbol.toPrimitive]: invalid argument");
  378. assert.throws(()=>(o in x), TypeError, "o in x", "[Symbol.toPrimitive]: invalid argument");
  379. //
  380. // + operator
  381. //
  382. assert.throws(()=>(o+1), TypeError, "o+1", "[Symbol.toPrimitive]: invalid argument");
  383. assert.throws(()=>(2+o), TypeError, "2+o", "[Symbol.toPrimitive]: invalid argument");
  384. assert.throws(()=>(o+'abc'), TypeError, "o+'abc'", "[Symbol.toPrimitive]: invalid argument");
  385. assert.throws(()=>('abc'+o), TypeError, "'abc'+o", "[Symbol.toPrimitive]: invalid argument");
  386. //
  387. // abstract relational comparison
  388. //
  389. assert.throws(()=>(o<1), TypeError, "o<1", "[Symbol.toPrimitive]: invalid argument");
  390. assert.throws(()=>(1<o), TypeError, "1<o", "[Symbol.toPrimitive]: invalid argument");
  391. assert.throws(()=>(o<=25), TypeError, "o<=25", "[Symbol.toPrimitive]: invalid argument");
  392. assert.throws(()=>(-9<=o), TypeError, "-9<=o", "[Symbol.toPrimitive]: invalid argument");
  393. assert.throws(()=>(o>1), TypeError, "o>1", "[Symbol.toPrimitive]: invalid argument");
  394. assert.throws(()=>(o>=25), TypeError, "o>=25", "[Symbol.toPrimitive]: invalid argument");
  395. assert.throws(()=>(-9>=o), TypeError, "-9>=o", "[Symbol.toPrimitive]: invalid argument");
  396. assert.throws(()=>(o<o), TypeError, "o<o", "[Symbol.toPrimitive]: invalid argument");
  397. assert.throws(()=>(o<=o), TypeError, "o<=o", "[Symbol.toPrimitive]: invalid argument");
  398. assert.throws(()=>(o>o), TypeError, "o>o", "[Symbol.toPrimitive]: invalid argument");
  399. assert.throws(()=>(o>=o), TypeError, "o>=o", "[Symbol.toPrimitive]: invalid argument");
  400. //
  401. // abstract equality comparison
  402. //
  403. assert.isTrue(o==o, "o==o should not call ToPrimitive");
  404. assert.throws(()=>('abc'==o), TypeError, "'abc'==o", "[Symbol.toPrimitive]: invalid argument");
  405. assert.throws(()=>(o=='abc'), TypeError, "o=='abc'", "[Symbol.toPrimitive]: invalid argument");
  406. assert.throws(()=>(100==o), TypeError, "100==o", "[Symbol.toPrimitive]: invalid argument");
  407. assert.throws(()=>(o==100), TypeError, "o==100", "[Symbol.toPrimitive]: invalid argument");
  408. assert.throws(()=>(Symbol()==o), TypeError, "Symbol()==o", "[Symbol.toPrimitive]: invalid argument");
  409. assert.throws(()=>(o==Symbol()), TypeError, "o==Symbol()", "[Symbol.toPrimitive]: invalid argument");
  410. });
  411. }
  412. },
  413. {
  414. name: "Array type conversion tests: lastIndexOf()",
  415. body: function ()
  416. {
  417. var p1 = {
  418. [Symbol.toPrimitive] (hint) {
  419. Object.defineProperty(a1, "0", {configurable : true, get: function(){ return 30;}});
  420. return a1.length;
  421. }
  422. };
  423. var a1 = [1, 2, 3, 4, 5];
  424. assert.areEqual(3, a1.lastIndexOf(4, p1), "ToPrimitive: lastIndexOf() method returned incorrect result as array type changed to ES5 array.");
  425. var a1_proto = {};
  426. Object.defineProperty(a1_proto, "1", {
  427. get: function(){
  428. Object.defineProperty(a1_prototest, "0", {configurable : true, get: function(){ return 30;}});
  429. return 2;
  430. }
  431. });
  432. var a1_prototest = [, , 3, 4, 5];
  433. a1_prototest.__proto__ = a1_proto;
  434. var c1_prototest = [].lastIndexOf.call(a1_prototest, 30);
  435. assert.areEqual(0, c1_prototest, "ToPrimitive: The lastIndexOf() method returned incorrect result as array type changed to ES5 array in the property getter of the prototype.");
  436. }
  437. },
  438. {
  439. name: "Array type conversion tests: indexOf()",
  440. body: function ()
  441. {
  442. var p2 = {
  443. [Symbol.toPrimitive] (hint) {
  444. Object.defineProperty(a2, "0", {configurable : true, get: function(){ return 30;}});
  445. return 0;
  446. }
  447. };
  448. var a2 = [1, 2, 3, 4, 5];
  449. assert.areEqual(3, a2.indexOf(4, p2), "ToPrimitive: indexOf() method returned incorrect result as array type changed to ES5 array.");
  450. var a2_proto = {};
  451. Object.defineProperty(a2_proto, "0", {
  452. get: function(){
  453. Object.defineProperty(a2_prototest, "1", {configurable : true, get: function(){ return 30;}});
  454. return 1;
  455. }
  456. });
  457. var a2_prototest = [, , 3, 4, 5];
  458. a2_prototest.__proto__ = a2_proto;
  459. var c2_prototest = [].indexOf.call(a2_prototest, 30);
  460. assert.areEqual(1, c2_prototest, "ToPrimitive: The indexOf() method returned incorrect result as array type changed to ES5 array in the property getter of the prototype.");
  461. }
  462. },
  463. {
  464. name: "Array type conversion tests: splice()",
  465. body: function ()
  466. {
  467. var p3 = {
  468. [Symbol.toPrimitive] (hint) {
  469. Object.defineProperty(a3, "0", {configurable : true, get: function(){ return 30;}});
  470. return 0;
  471. }
  472. };
  473. var a3 = [1, 2, 3, 4, 5];
  474. var b3 = a3.splice(p3);
  475. assert.areEqual([30,2,3,4,5], b3, "ToPrimitive: splice() method returned incorrect result as array type changed to ES5 array.");
  476. var a3_proto = {};
  477. Object.defineProperty(a3_proto, "0", {
  478. get: function(){
  479. Object.defineProperty(a3_prototest, "1", {configurable : true, get: function(){ return 30;}});
  480. return 1;
  481. }
  482. });
  483. var a3_prototest = [, , 3, 4, 5];
  484. a3_prototest.__proto__ = a3_proto;
  485. var c3_prototest = [].splice.call(a3_prototest, 0);
  486. assert.areEqual([1,30,3,4,5], c3_prototest, "ToPrimitive: The splice() method returned incorrect result as array type changed to ES5 array in the property getter of the prototype.");
  487. function a3_constructor(x) { };
  488. a3_constructor[Symbol.species] = function () {
  489. Object.defineProperty(a3_species, "0", { configurable: true, get: function () { return 30; } });
  490. return {};
  491. };
  492. var a3_species = [1, 2, 3, 4, 5];
  493. a3_species['constructor'] = a3_constructor;
  494. var c3_species = a3_species.splice(0);
  495. assert.areEqual(30, c3_species["0"], "The splice() method returned incorrect result as array was converted to an ES5Array.");
  496. assert.areEqual("30,2,3,4,5", [].join.call(c3_species, ","), "The splice() method returned incorrect result as array was converted to an ES5Array.");
  497. }
  498. },
  499. {
  500. name: "Array type conversion tests: slice()",
  501. body: function ()
  502. {
  503. var p4 = {
  504. [Symbol.toPrimitive] (hint) {
  505. Object.defineProperty(a4, "0", {configurable : true, get: function(){ return 30;}});
  506. return 0;
  507. }
  508. };
  509. var a4 = [1, 2, 3, 4, 5];
  510. var b4 = a4.slice(p4);
  511. assert.areEqual([30,2,3,4,5], b4, "ToPrimitive: slice() method returned incorrect result as array type changed to ES5 array.");
  512. var a4_proto = {};
  513. Object.defineProperty(a4_proto, "0", {
  514. get: function(){
  515. Object.defineProperty(a4_prototest, "1", {configurable : true, get: function(){ return 30;}});
  516. return 1;
  517. }
  518. });
  519. var a4_prototest = [, , 3, 4, 5];
  520. a4_prototest.__proto__ = a4_proto;
  521. var c4_prototest = [].slice.call(a4_prototest, 0);
  522. assert.areEqual([1,30,3,4,5], c4_prototest, "ToPrimitive: The slice() method returned incorrect result as array type changed to ES5 array in the property getter of the prototype.");
  523. function a4_constructor(x) { };
  524. a4_constructor[Symbol.species] = function () {
  525. Object.defineProperty(a4_species, "0", { configurable: true, get: function () { return 30; } });
  526. return {};
  527. };
  528. var a4_species = [1, 2, 3, 4, 5];
  529. a4_species['constructor'] = a4_constructor;
  530. var c4_species = a4_species.slice(0);
  531. assert.areEqual(30, c4_species["0"], "The slice() method returned incorrect result as array was converted to an ES5Array.");
  532. assert.areEqual("30,2,3,4,5", [].join.call(c4_species, ","), "The slice() method returned incorrect result as array was converted to an ES5Array.");
  533. }
  534. },
  535. {
  536. name: "Array type conversion tests: includes()",
  537. body: function ()
  538. {
  539. var p5 = {
  540. [Symbol.toPrimitive] (hint) {
  541. Object.defineProperty(a5, "0", {configurable : true, get: function(){ return 30;}});
  542. return 0;
  543. }
  544. };
  545. var a5 = [1, 2, 3, 4, 5];
  546. assert.isTrue(a5.includes(30, p5), "ToPrimitive: includes() method returned incorrect result as array type changed to ES5 array.");
  547. var a5_proto = {};
  548. Object.defineProperty(a5_proto, "0", {
  549. get: function(){
  550. Object.defineProperty(a5_prototest, "1", {configurable : true, get: function(){ return 30;}});
  551. return 1;
  552. }
  553. });
  554. var a5_prototest = [, , 3, 4, 5];
  555. a5_prototest.__proto__ = a5_proto;
  556. assert.isTrue([].includes.call(a5_prototest, 30), "The includes() method returned incorrect result as array type changed to ES5 array in the property getter of the prototype.");
  557. }
  558. },
  559. {
  560. name: "Array type conversion tests: find() and findIndex().",
  561. body: function ()
  562. {
  563. var p2 = {
  564. [Symbol.toPrimitive] (hint) {
  565. // The first element changes during the visit to the first element; so it's side-effect won't be seen by Find method.
  566. Object.defineProperty(a2, "0", {configurable : true, get: function(){ return 20;}});
  567. // The second element changes during the visit to the first element; so it's side-effect will be seen by Find method.
  568. Object.defineProperty(a2, "1", {configurable : true, get: function(){ return 30;}});
  569. return 10;
  570. }
  571. };
  572. var a2 = [1, 2, 3, 4, 5];
  573. var c2 = a2.find(function(x) { return x % p2 == 0; });
  574. assert.areEqual(30, c2, "The find() method returned incorrect result as array was converted to an ES5Array.");
  575. var a2_prototest = [,, 3, 4, 5];
  576. var a2_proto = {};
  577. Object.defineProperty(a2_proto, "0", {
  578. get: function(){
  579. Object.defineProperty(a2_prototest, "1", {configurable : true, get: function(){ return 30;}});
  580. return 7;
  581. }
  582. });
  583. a2_prototest.__proto__ = a2_proto;
  584. var c2_prototest = [].find.call(a2_prototest, function(x) { return x % 10 == 0; });
  585. assert.areEqual(30, c2_prototest, "The find() method returned incorrect result as array was converted to an ES5Array in the property getter of the prototype.");
  586. var p3 = {
  587. [Symbol.toPrimitive] (hint) {
  588. // The first element changes during the visit to the first element; so it's side-effect won't be seen by FindIndex method.
  589. Object.defineProperty(a3, "0", {configurable : true, get: function(){ return 30;}});
  590. // The second element changes during the visit to the first element; so it's side-effect will be seen by FindIndex method.
  591. Object.defineProperty(a3, "1", {configurable : true, get: function(){ return 30;}});
  592. return 30;
  593. }
  594. };
  595. var a3 = [1, 2, 3, 4, 5];
  596. var c3 = a3.findIndex(function(x) { return x == p3; });
  597. assert.areEqual(1, c3, "The findIndex() method returned incorrect result as array was converted to an ES5Array.");
  598. }
  599. },
  600. {
  601. name: "Array type conversion tests: map().",
  602. body: function ()
  603. {
  604. var p4 = function(x)
  605. {
  606. Object.defineProperty(a4, "1", {configurable : true, get: function(){ return 30;}});
  607. return x * x;
  608. };
  609. var a4 = [1, 2, 3, 4, 5];
  610. var c4 = a4.map(p4);
  611. assert.areEqual([1,900,9,16,25], c4, "The map() method returned incorrect result as array was converted to an ES5Array.");
  612. var p4_typedarray = function(x)
  613. {
  614. Object.defineProperty(a4_typedarray, "1", {configurable : false, value: 30});
  615. return x * x;
  616. };
  617. var a4_typedarray = new Int32Array([1, 2, 3, 4, 5]);
  618. var c4_typedarray = a4_typedarray.map(p4_typedarray);
  619. assert.areEqual([1,900,9,16,25], c4_typedarray, "The map() method returned incorrect result for TypedArray.");
  620. function a4_constructor(x) { };
  621. a4_constructor[Symbol.species] = function () {
  622. Object.defineProperty(a4_species, "1", { configurable: true, get: function () { return 30; } });
  623. return {};
  624. };
  625. var a4_species = [1, 2, 3, 4, 5];
  626. a4_species['constructor'] = a4_constructor;
  627. var c4_species = a4_species.map(function (x) { return x * x; });
  628. assert.areEqual([1, 900, 9, 16, 25], c4_species, "Map returned incorrect result as array was converted to an ES5Array.");
  629. var a4_proto = {};
  630. Object.defineProperty(a4_proto, "0", {
  631. get: function(){
  632. Object.defineProperty(a4_prototest, "1", {configurable : true, get: function(){ return 30;}});
  633. return 7;
  634. }
  635. });
  636. var SquareNumber = function(x)
  637. {
  638. return x * x;
  639. };
  640. var a4_prototest = [, , 3, 4, 5];
  641. a4_prototest.__proto__ = a4_proto;
  642. var c4_prototest = [].map.call(a4_prototest, SquareNumber);
  643. assert.areEqual([49,900,9,16,25], c4_prototest, "The map() method returned incorrect result as array was converted to an ES5Array in the property getter of the prototype.");
  644. }
  645. },
  646. {
  647. name: "Array type conversion tests: reduce().",
  648. body: function ()
  649. {
  650. var p6 = {
  651. [Symbol.toPrimitive] (hint) {
  652. // The first element changes during the visit to the first element; so it's side-effect won't be seen by Reduce method.
  653. Object.defineProperty(a6, "0", {configurable : true, get: function(){ return 30;}});
  654. // The second element changes during the visit to the first element; so it's side-effect will be seen by Reduce method.
  655. Object.defineProperty(a6, "1", {configurable : true, get: function(){ return 30;}});
  656. return 0;
  657. }
  658. };
  659. var a6 = [1, 2, 3, 4, 5];
  660. var c6 = a6.reduce(AddNumbers, p6);
  661. assert.areEqual(43, c6, "The reduce() method returned incorrect result as array was converted to an ES5Array.");
  662. var a6_proto = {};
  663. Object.defineProperty(a6_proto, "0", {
  664. get: function(){
  665. Object.defineProperty(a6_prototest, "1", {configurable : true, get: function(){ return 30;}});
  666. return 1;
  667. }
  668. });
  669. var a6_prototest = [, , 3, 4, 5];
  670. a6_prototest.__proto__ = a6_proto;
  671. var c6_prototest = [].reduce.call(a6_prototest, AddNumbers);
  672. assert.areEqual(43, c6_prototest, "The reduce() method returned incorrect result as array was converted to an ES5Array in the property getter of the prototype.");
  673. // Regression tests
  674. var a6_es5 = [1, 2, 3, 4, 5];
  675. Object.defineProperty(a6_es5, "0", {configurable : true, get: function(){ return 30;}});
  676. var c6_es5 = a6_es5.reduce(AddNumbers);
  677. assert.areEqual(44, c6_es5, "The reduce() method returned incorrect result for an ES5Array.");
  678. }
  679. },
  680. {
  681. name: "Array type conversion tests: reduceRight().",
  682. body: function ()
  683. {
  684. var p7 = {
  685. [Symbol.toPrimitive] (hint) {
  686. // The last element changes during the visit to the last element; so it's side-effect won't be seen by ReduceRight method.
  687. Object.defineProperty(a7, "4", {configurable : true, get: function(){ return 30;}});
  688. // The second element changes during the visit to the first element; so it's side-effect will be seen by ReduceRight method.
  689. Object.defineProperty(a7, "1", {configurable : true, get: function(){ return 30;}});
  690. return 0;
  691. }
  692. };
  693. var a7 = [1, 2, 3, 4, 5];
  694. var c7 = a7.reduceRight(AddNumbers, p7);
  695. assert.areEqual(43, c7, "The reduceRight() method returned incorrect result as array was converted to an ES5Array.");
  696. var a7_proto = {};
  697. Object.defineProperty(a7_proto, "4", {
  698. get: function(){
  699. Object.defineProperty(a7_prototest, "1", {configurable : true, get: function(){ return 30;}});
  700. return 5;
  701. }
  702. });
  703. var a7_prototest = [1, , 3, 4, ,];
  704. a7_prototest.__proto__ = a7_proto;
  705. var c7_prototest = [].reduceRight.call(a7_prototest, AddNumbers);
  706. assert.areEqual(43, c7_prototest, "The reduceRight() method returned incorrect result as array was converted to an ES5Array in the property getter of the prototype.");
  707. // Regression test
  708. var a7_es5 = [1, 2, 3, 4, 5];
  709. Object.defineProperty(a7_es5, "0", {configurable : true, get: function(){ return 30;}});
  710. var c7_es5 = a7_es5.reduceRight(AddNumbers);
  711. assert.areEqual(44, c7_es5, "The reduceRight() method returned incorrect result for an ES5Array.");
  712. }
  713. },
  714. {
  715. name: "Array type conversion tests: some().",
  716. body: function ()
  717. {
  718. var p8 = {
  719. [Symbol.toPrimitive] (hint) {
  720. Object.defineProperty(a8, "1", {configurable : true, get: function(){ return 30;}});
  721. return 30;
  722. }
  723. };
  724. function MatchNumber(numberToMatch)
  725. {
  726. return numberToMatch == p8;
  727. }
  728. var a8 = [1, 2, 3, 4, 5];
  729. var c8 = a8.some(MatchNumber);
  730. assert.isTrue(c8, "The some() method returned incorrect result as array was converted to an ES5Array.");
  731. var a8_proto = {};
  732. Object.defineProperty(a8_proto, "0", {
  733. get: function(){
  734. Object.defineProperty(a8_prototest, "1", {configurable : true, get: function(){ return 30;}});
  735. return 5;
  736. }
  737. });
  738. var a8_prototest = [, , 3, 4, 5];
  739. a8_prototest.__proto__ = a8_proto;
  740. var c8_prototest = [].some.call(a8_prototest, function(elem){ return elem == 30; });
  741. assert.isTrue(c8_prototest, "The some() method returned incorrect result as array was converted to an ES5Array in the property getter of the prototype.");
  742. }
  743. },
  744. {
  745. name: "Array type conversion tests: every().",
  746. body: function ()
  747. {
  748. var p9 = {
  749. [Symbol.toPrimitive] (hint) {
  750. Object.defineProperty(a9, "1", {configurable : true, get: function(){ return 30;}});
  751. return 30;
  752. }
  753. };
  754. function CompareNumber(numberToMatch)
  755. {
  756. return numberToMatch < p9;
  757. }
  758. var a9 = [1, 2, 3, 4, 5];
  759. var c9 = a9.every(CompareNumber);
  760. assert.isFalse(c9, "The every() method returned incorrect result as array was converted to an ES5Array.");
  761. var a9_proto = {};
  762. Object.defineProperty(a9_proto, "0", {
  763. get: function(){
  764. Object.defineProperty(a9_prototest, "1", {configurable : true, get: function(){ return 30;}});
  765. return 1;
  766. }
  767. });
  768. var a9_prototest = [, , 3, 4, 5];
  769. a9_prototest.__proto__ = a9_proto;
  770. var c9_prototest = [].every.call(a9_prototest, function(elem){ return elem < 30;});
  771. assert.isFalse(c9_prototest, "The every() method returned incorrect result as array was converted to an ES5Array in the property getter of the prototype.");
  772. }
  773. },
  774. {
  775. name: "Array type conversion tests: fill().",
  776. body: function ()
  777. {
  778. var temp = 30;
  779. var p10 = {
  780. [Symbol.toPrimitive] (hint) {
  781. Object.defineProperty(a10, 1, {configurable : true, get: function(){ return temp;}, set: function(value){ temp = value;}});
  782. return 0;
  783. }
  784. };
  785. var a10 = [1, 2, 3, 4, 5];
  786. var c10 = a10.fill(0, p10);
  787. assert.areEqual([0,0,0,0,0], c10, "ToPrimitive: The fill() method returned incorrect result as array type changed to ES5 array.");
  788. }
  789. },
  790. {
  791. name: "Array type conversion tests: filter().",
  792. body: function ()
  793. {
  794. var p11 = {
  795. [Symbol.toPrimitive] (hint) {
  796. // The first element changes during the visit to the first element; so it's side-effect won't be seen by filter method.
  797. Object.defineProperty(a11, "0", {configurable : true, get: function(){ return 30;}});
  798. // The last element changes during the visit to the first element; so it's side-effect will be seen by filter method.
  799. Object.defineProperty(a11, "4", {configurable : true, get: function(){ return 30;}});
  800. return 0;
  801. }
  802. };
  803. var a11 = [1, 2, 3, 4, 5];
  804. var c11 = a11.filter(function(elem){ return elem %2 == p11; });
  805. assert.areEqual([2,4,30], c11, "ToPrimitive: The filter() method returned incorrect result as array type changed to ES5 array.");
  806. var a11_proto = {};
  807. Object.defineProperty(a11_proto, "0", {
  808. get: function(){
  809. Object.defineProperty(a11_prototest, "1", {configurable : true, get: function(){ return 30;}});
  810. return 1;
  811. }
  812. });
  813. var a11_prototest = [, , 3, 4, 5];
  814. a11_prototest.__proto__ = a11_proto;
  815. var c11_prototest = [].filter.call(a11_prototest, function(elem){ return elem %2 == 0; });
  816. assert.areEqual([30,4], c11_prototest, "ToPrimitive: The filter() method returned incorrect result as array type changed to ES5 array in the property getter of the prototype.");
  817. var p11_typedarray = {
  818. [Symbol.toPrimitive] (hint) {
  819. // The first element changes during the visit to the first element; so it's side-effect won't be seen by filter method.
  820. Object.defineProperty(a11_typedarray, "0", {configurable : false, value:30 });
  821. // The last element changes during the visit to the first element; so it's side-effect will be seen by filter method.
  822. Object.defineProperty(a11_typedarray, "4", {configurable : false, value:30 });
  823. return 0;
  824. }
  825. };
  826. var a11_typedarray = new Int16Array([1,2,3,4,5]);
  827. var c11_typedarray = a11_typedarray.filter(function(elem){ return elem %2 == p11_typedarray; });
  828. assert.areEqual([2,4,30], c11_typedarray, "ToPrimitive: The filter() method returned incorrect result for TypedArray.");
  829. function a11_constructor(x) { };
  830. a11_constructor[Symbol.species] = function () {
  831. Object.defineProperty(a11_species, "0", { configurable: true, get: function () { return 30; } });
  832. return {};
  833. };
  834. var a11_species = [1, 2, 3, 4, 5];
  835. a11_species['constructor'] = a11_constructor;
  836. var c11_species = a11_species.filter(function (elem) { return elem % 2 == 0; });
  837. assert.areEqual([30, 2, 4], c11_species, "The filter() returned incorrect result as array was converted to an ES5Array.");
  838. }
  839. },
  840. {
  841. name: "Array type conversion tests: foreach().",
  842. body: function ()
  843. {
  844. var a18 = [1,2,3,4,5];
  845. var c18 = "";
  846. a18.forEach( function (item, index)
  847. {
  848. if(index==0)
  849. {
  850. // The first element changes during the visit to the first element; so it's side-effect won't be seen by forEach method.
  851. Object.defineProperty(a18, "0", {configurable : true, get: function(){ return 30;}});
  852. // The last element changes during the visit to the first element; so it's side-effect will be seen by forEach method.
  853. Object.defineProperty(a18, "1", {configurable : true, get: function(){ return 30;}});
  854. }
  855. else
  856. {
  857. c18 = c18 + ","
  858. }
  859. c18 = c18 + item*item;
  860. });
  861. assert.areEqual("1,900,9,16,25", c18, "ToPrimitive: The forEach() method returned incorrect result for as array type changed to ES5 array.");
  862. var a18_proto = {};
  863. Object.defineProperty(a18_proto, "0", {
  864. get: function(){
  865. Object.defineProperty(a18_prototest, "1", {configurable : true, get: function(){ return 30;}});
  866. return 1;
  867. }
  868. });
  869. var a18_prototest = [,,3,4,5];
  870. a18_prototest.__proto__ = a18_proto;
  871. var c18_prototest = "";
  872. [].forEach.call(a18_prototest, function (item, index)
  873. {
  874. if(index>0)
  875. {
  876. c18_prototest += ","
  877. }
  878. c18_prototest += item*item;
  879. });
  880. assert.areEqual("1,900,9,16,25", c18_prototest, "ToPrimitive: The forEach() method returned incorrect result for as array type changed to ES5 array.");
  881. var a18_typedarray = new Int16Array([1,2,3,4,5]);
  882. var c18_typedarray = "";
  883. a18_typedarray.forEach( function (item, index)
  884. {
  885. if(index==0)
  886. {
  887. // The first element changes during the visit to the first element; so it's side-effect won't be seen by forEach method.
  888. Object.defineProperty(a18_typedarray, "0", {configurable : false, value:30 });
  889. // The last element changes during the visit to the first element; so it's side-effect will be seen by forEach method.
  890. Object.defineProperty(a18_typedarray, "1", {configurable : false, value:30 });
  891. }
  892. else
  893. {
  894. c18_typedarray = c18_typedarray + ","
  895. }
  896. c18_typedarray = c18_typedarray + item*item;
  897. });
  898. assert.areEqual("1,900,9,16,25", c18_typedarray, "ToPrimitive: The forEach() returned incorrect result for TypedArray.");
  899. }
  900. },
  901. {
  902. name: "Array type conversion tests: copyWithin().",
  903. body: function ()
  904. {
  905. var p21 = {
  906. [Symbol.toPrimitive] (hint) {
  907. Object.defineProperty(a21, "0", {configurable : true, get: function(){ return 30;}});
  908. return -2;
  909. }
  910. };
  911. var a21 = [1,2,3,4,5];
  912. var c21 = a21.copyWithin(p21);
  913. assert.areEqual([30,2,3,30,2], c21, "ToPrimitive: The copyWithin() method returned incorrect result as array type changed to ES5 array.");
  914. //This test is failing due to following bug.
  915. // 10747539: The CopyWithin array method implementation needs to do prototype lookup for property lookup (HasItem).
  916. // var a21_proto = {};
  917. // Object.defineProperty(a21_proto, "0", {
  918. // get: function(){
  919. // Object.defineProperty(a21_prototest, "1", {configurable : true, get: function(){ return 2;}});
  920. // return 30;
  921. // }
  922. // });
  923. // var a21_prototest = [,,3,4,5];
  924. // a21_prototest.__proto__ = a21_proto;
  925. // var c21_prototest = [].copyWithin.call(a21_prototest, -2);
  926. // assert.areEqual("30,2,3,30,2", [].join.call(c21_prototest, ","), "ToPrimitive: The copyWithin() method returned incorrect result as array type changed to ES5Array in the property getter of the prototype.");
  927. var p21_typedarray = {
  928. [Symbol.toPrimitive] (hint) {
  929. Object.defineProperty(a21_typedarray, "0", {configurable : false, value:30 });
  930. return -2;
  931. }
  932. };
  933. var a21_typedarray = new Int16Array([1,2,3,4,5]);
  934. var c21_typedarray = a21_typedarray.copyWithin(p21_typedarray);
  935. assert.areEqual([30,2,3,30,2], c21_typedarray, "ToPrimitive: The copyWithin() method returned incorrect result for TypedArray.");
  936. }
  937. },
  938. ];
  939. testRunner.runTests(tests, { verbose: WScript.Arguments[0] != "summary" });