ES6ArrayUseConstructor.js 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358
  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. // ES6 Array builtins using this['constructor'] property to construct their return values
  6. WScript.LoadScriptFile("..\\UnitTestFramework\\UnitTestFramework.js");
  7. var tests = [
  8. {
  9. name: "Array.prototype.concat",
  10. body: function () {
  11. var arr = ['a','b','c'];
  12. arr['constructor'] = Number;
  13. var out = Array.prototype.concat.call(arr, [1,2,3]);
  14. assert.isTrue(Array.isArray(out), "Return from Array.prototype.concat should be an Array object");
  15. assert.isFalse(out instanceof Number, "Return from Array.prototype.concat should not have been constructed from Number");
  16. assert.areEqual(['a','b','c',1,2,3], out, "Array.prototype.concat output should show correct Array behavior");
  17. assert.areEqual(6, out.length, "Array.prototype.concat sets the length property of returned object");
  18. }
  19. },
  20. {
  21. name: "Array.prototype.filter",
  22. body: function () {
  23. var arr = ['a','b','c'];
  24. arr['constructor'] = Number;
  25. var out = Array.prototype.filter.call(arr, function() { return true; });
  26. assert.isTrue(Array.isArray(out), "Return from Array.prototype.filter should be an Array object");
  27. assert.isFalse(out instanceof Number, "Return from Array.prototype.filter should not have been constructed from Number");
  28. assert.areEqual(['a','b','c'], out, "Array.prototype.filter output should show correct Array behavior");
  29. assert.areEqual(3, out.length, "Array.prototype.filter does not set the length property of returned object");
  30. }
  31. },
  32. {
  33. name: "Array.prototype.map",
  34. body: function () {
  35. var arr = ['a','b','c'];
  36. arr['constructor'] = Number;
  37. var out = Array.prototype.map.call(arr, function(val) { return val; });
  38. assert.isTrue(Array.isArray(out), "Return from Array.prototype.map should be an Array object");
  39. assert.isFalse(out instanceof Number, "Return from Array.prototype.map should not have been constructed from Number");
  40. assert.areEqual(['a','b','c'], out, "Array.prototype.map output should show correct Array behavior");
  41. assert.areEqual(3, out.length, "Array.prototype.map does not set the length property of returned object");
  42. }
  43. },
  44. {
  45. name: "Array.prototype.slice",
  46. body: function () {
  47. var arr = ['a','b','c'];
  48. arr['constructor'] = Number;
  49. var out = Array.prototype.slice.call(arr);
  50. assert.isTrue(Array.isArray(out), "Return from Array.prototype.slice should be an Array object");
  51. assert.isFalse(out instanceof Number, "Return from Array.prototype.slice should not have been constructed from Number");
  52. assert.areEqual(['a','b','c'], out, "Array.prototype.slice output should show correct Array behavior");
  53. assert.areEqual(3, out.length, "Array.prototype.slice sets the length property of returned object");
  54. }
  55. },
  56. {
  57. name: "Array.prototype.splice - array source with constructor property set to Number",
  58. body: function () {
  59. var arr = ['a','b','c','d','e','f'];
  60. arr['constructor'] = Number;
  61. var out = Array.prototype.splice.call(arr, 0, 3);
  62. assert.isTrue(Array.isArray(out), "Return from Array.prototype.splice should be an Array object");
  63. assert.isFalse(out instanceof Number, "Return from Array.prototype.splice should not have been constructed from Number");
  64. assert.areEqual(['a','b','c'], out, "Array.prototype.splice output should show correct Array behavior");
  65. assert.areEqual(3, out.length, "Array.prototype.splice sets the length property of returned object");
  66. }
  67. },
  68. {
  69. name: "Array.prototype.splice - array source with constructor property set to Array",
  70. body: function () {
  71. var arr = [1,2,3,4,5,6];
  72. arr['constructor'] = Array;
  73. var out = Array.prototype.splice.call(arr, 0, 3);
  74. assert.isTrue(Array.isArray(out), "Return from Array.prototype.splice should be an Array object");
  75. assert.isTrue(out instanceof Array, "Return from Array.prototype.splice should have been constructed from Array");
  76. assert.areEqual([1,2,3], out, "Array.prototype.splice output is correct");
  77. assert.areEqual(3, out.length, "Array.prototype.splice sets the length property of returned object");
  78. }
  79. },
  80. {
  81. name: "Array.prototype.splice - array source with no constructor property",
  82. body: function () {
  83. var arr = [1,2,3,4,5,6];
  84. var out = Array.prototype.splice.call(arr, 0, 3);
  85. assert.isTrue(Array.isArray(out), "Return from Array.prototype.splice should be an Array object");
  86. assert.isTrue(out instanceof Array, "Return from Array.prototype.splice should have been constructed from Array");
  87. assert.areEqual([1,2,3], out, "Array.prototype.splice output is correct");
  88. assert.areEqual(3, out.length, "Array.prototype.splice sets the length property of returned object");
  89. }
  90. },
  91. {
  92. name: "Array.prototype.splice - object source with no constructor property",
  93. body: function () {
  94. var arr = {0:1,1:2,2:3,3:4,4:5,5:6,'length':6};
  95. var out = Array.prototype.splice.call(arr, 0, 3);
  96. assert.isTrue(Array.isArray(out), "Return from Array.prototype.splice should be an Array object");
  97. assert.isTrue(out instanceof Array, "Return from Array.prototype.splice should have been constructed from Array");
  98. assert.areEqual([1,2,3], out, "Array.prototype.splice output is correct");
  99. assert.areEqual(3, out.length, "Array.prototype.splice sets the length property of returned object");
  100. }
  101. },
  102. {
  103. name: "Array.prototype.splice - object source with constructor property set to Number",
  104. body: function () {
  105. var arr = {0:1,1:2,2:3,3:4,4:5,5:6,'length':6};
  106. arr['constructor'] = Number;
  107. var out = Array.prototype.splice.call(arr, 0, 3);
  108. assert.isTrue(Array.isArray(out), "Return from Array.prototype.splice should be an Array object");
  109. assert.isTrue(out instanceof Array, "Return from Array.prototype.splice should have been constructed from Array");
  110. assert.areEqual([1,2,3], out, "Array.prototype.splice output is correct");
  111. assert.areEqual(3, out.length, "Array.prototype.splice sets the length property of returned object");
  112. }
  113. },
  114. {
  115. name: "ArraySpeciesCreate test through Array.prototype.splice",
  116. body: function () {
  117. var arr = ['a','b','c','d','e','f'];
  118. arr['constructor'] = null;
  119. assert.throws(function() { Array.prototype.splice.call(arr, 0, 3); }, TypeError, "TypeError when constructor[Symbol.species] is not constructor", "Function 'constructor[Symbol.species]' is not a constructor");
  120. var arr = ['a','b','c','d','e','f'];
  121. Object.defineProperty(arr, 'constructor', {enumerable: false, configurable: true, writable: true, value: null});
  122. assert.throws(function() { Array.prototype.splice.call(arr, 0, 3); }, TypeError, "TypeError when constructor[Symbol.species] is not constructor", "Function 'constructor[Symbol.species]' is not a constructor");
  123. var arr = ['a','b','c','d','e','f'];
  124. arr['constructor'] = undefined;
  125. var out = Array.prototype.splice.call(arr, 0, 3);
  126. assert.isTrue(Array.isArray(out), "Return from Array.prototype.splice should be an Array object when constructor == undefined");
  127. assert.areEqual(['a','b','c'], out, "Array.prototype.splice output should show correct Array behavior when constructor == undefined");
  128. assert.areEqual(3, out.length, "Array.prototype.splice sets the length property of returned object when constructor == undefined");
  129. var arr = ['a','b','c','d','e','f'];
  130. arr['constructor'] = function() {};
  131. var out = Array.prototype.splice.call(arr, 0, 3);
  132. assert.isTrue(Array.isArray(out), "Return from Array.prototype.splice should be an Array object when constructor has no [@@species] property");
  133. assert.areEqual(['a','b','c'], out, "Array.prototype.splice output should show correct Array behavior when constructor has no [@@species] property");
  134. assert.areEqual(3, out.length, "Array.prototype.splice sets the length property of returned object when constructor has no [@@species] property");
  135. var builtinArraySpeciesDesc = Object.getOwnPropertyDescriptor(Array, Symbol.species);
  136. var arr = ['a','b','c','d','e','f'];
  137. Object.defineProperty(Array, Symbol.species, {enumerable: false, configurable: true, writable: true, value: Object});
  138. var out = Array.prototype.splice.call(arr, 0, 3);
  139. assert.isFalse(Array.isArray(out), "Return from Array.prototype.splice should be an object when constructor has [@@species] == Object");
  140. assert.areEqual({'0':'a','1':'b','2':'c',"length":3}, out, "Array.prototype.splice output should show correct Array behavior when constructor has [@@species] == Object");
  141. var arr = ['a','b','c','d','e','f'];
  142. Object.defineProperty(Array, Symbol.species, {enumerable: false, configurable: true, writable: true, value: null});
  143. var out = Array.prototype.splice.call(arr, 0, 3);
  144. assert.isTrue(Array.isArray(out), "Return from Array.prototype.splice should be an Array object when constructor has [@@species] == null");
  145. assert.areEqual(['a','b','c'], out, "Array.prototype.splice output should show correct Array behavior when constructor has [@@species] == null");
  146. assert.areEqual(3, out.length, "Array.prototype.splice sets the length property of returned object when constructor has [@@species] == null");
  147. Object.defineProperty(Array, Symbol.species, builtinArraySpeciesDesc);
  148. var external = WScript.LoadScriptFile("ES6ArrayUseConstructor_helper.js","samethread");
  149. var arr = ['a','b','c','d','e','f'];
  150. arr['constructor'] = external.CrossContextArrayConstructor;
  151. var out = Array.prototype.splice.call(arr, 0, 3);
  152. assert.isTrue(Array.isArray(out), "Return from Array.prototype.splice should be an Array object when constructor is %Array% of a different script context");
  153. assert.areEqual(['a','b','c'], out, "Array.prototype.splice output should show correct Array behavior when constructor is %Array% of a different script context");
  154. assert.areEqual(3, out.length, "Array.prototype.splice sets the length property of returned object when constructor is %Array% of a different script context");
  155. }
  156. },
  157. {
  158. name: "ArraySpeciesCreate test through Array.prototype.splice - native arrays",
  159. body: function () {
  160. var arr = [1,2,3,4,5,6];
  161. arr['constructor'] = null;
  162. assert.throws(function() { Array.prototype.splice.call(arr, 0, 3); }, TypeError, "TypeError when constructor[Symbol.species] is not constructor", "Function 'constructor[Symbol.species]' is not a constructor");
  163. var arr = [1,2,3,4,5,6];
  164. Object.defineProperty(arr, 'constructor', {enumerable: false, configurable: true, writable: true, value: null});
  165. assert.throws(function() { Array.prototype.splice.call(arr, 0, 3); }, TypeError, "TypeError when constructor[Symbol.species] is not constructor", "Function 'constructor[Symbol.species]' is not a constructor");
  166. var arr = [1,2,3,4,5,6];
  167. arr['constructor'] = undefined;
  168. var out = Array.prototype.splice.call(arr, 0, 3);
  169. assert.isTrue(Array.isArray(out), "Return from Array.prototype.splice should be an Array object when constructor == undefined");
  170. assert.areEqual([1,2,3], out, "Array.prototype.splice output should show correct Array behavior when constructor == undefined");
  171. assert.areEqual(3, out.length, "Array.prototype.splice sets the length property of returned object when constructor == undefined");
  172. var arr = [1,2,3,4,5,6];
  173. arr['constructor'] = function() {};
  174. var out = Array.prototype.splice.call(arr, 0, 3);
  175. assert.isTrue(Array.isArray(out), "Return from Array.prototype.splice should be an Array object when constructor has no [@@species] property");
  176. assert.areEqual([1,2,3], out, "Array.prototype.splice output should show correct Array behavior when constructor has no [@@species] property");
  177. assert.areEqual(3, out.length, "Array.prototype.splice sets the length property of returned object when constructor has no [@@species] property");
  178. var builtinArraySpeciesDesc = Object.getOwnPropertyDescriptor(Array, Symbol.species);
  179. var arr = [1,2,3,4,5,6];
  180. Object.defineProperty(Array, Symbol.species, {enumerable: false, configurable: true, writable: true, value: Object});
  181. var out = Array.prototype.splice.call(arr, 0, 3);
  182. assert.isFalse(Array.isArray(out), "Return from Array.prototype.splice should be an object when constructor has [@@species] == Object");
  183. assert.areEqual({'0':1,'1':2,'2':3,"length":3}, out, "Array.prototype.splice output should show correct Array behavior when constructor has [@@species] == Object");
  184. var arr = [1,2,3,4,5,6];
  185. Object.defineProperty(Array, Symbol.species, {enumerable: false, configurable: true, writable: true, value: null});
  186. var out = Array.prototype.splice.call(arr, 0, 3);
  187. assert.isTrue(Array.isArray(out), "Return from Array.prototype.splice should be an Array object when constructor has [@@species] == null");
  188. assert.areEqual([1,2,3], out, "Array.prototype.splice output should show correct Array behavior when constructor has [@@species] == null");
  189. assert.areEqual(3, out.length, "Array.prototype.splice sets the length property of returned object when constructor has [@@species] == null");
  190. Object.defineProperty(Array, Symbol.species, builtinArraySpeciesDesc);
  191. var external = WScript.LoadScriptFile("ES6ArrayUseConstructor_helper.js","samethread");
  192. var arr = [1,2,3,4,5,6];
  193. arr['constructor'] = external.CrossContextArrayConstructor;
  194. var out = Array.prototype.splice.call(arr, 0, 3);
  195. assert.isTrue(Array.isArray(out), "Return from Array.prototype.splice should be an Array object when constructor is %Array% of a different script context");
  196. assert.areEqual([1,2,3], out, "Array.prototype.splice output should show correct Array behavior when constructor is %Array% of a different script context");
  197. assert.areEqual(3, out.length, "Array.prototype.splice sets the length property of returned object when constructor is %Array% of a different script context");
  198. }
  199. },
  200. {
  201. name: "ArraySpeciesCreate test through Array.prototype.map",
  202. body: function () {
  203. var f = function(val) { return val; }
  204. var arr = ['a','b','c'];
  205. arr['constructor'] = null;
  206. assert.throws(function() { Array.prototype.map.call(arr, f); }, TypeError, "TypeError when constructor[Symbol.species] is not constructor", "Function 'constructor[Symbol.species]' is not a constructor");
  207. var arr = ['a','b','c'];
  208. Object.defineProperty(arr, 'constructor', {enumerable: false, configurable: true, writable: true, value: null});
  209. assert.throws(function() { Array.prototype.map.call(arr, f); }, TypeError, "TypeError when constructor[Symbol.species] is not constructor", "Function 'constructor[Symbol.species]' is not a constructor");
  210. var arr = ['a','b','c'];
  211. arr['constructor'] = undefined;
  212. var out = Array.prototype.map.call(arr, f);
  213. assert.isTrue(Array.isArray(out), "Return from Array.prototype.map should be an Array object when constructor == undefined");
  214. assert.areEqual(['a','b','c'], out, "Array.prototype.map output should show correct Array behavior when constructor == undefined");
  215. assert.areEqual(3, out.length, "Array.prototype.map sets the length property of returned object when constructor == undefined");
  216. var arr = ['a','b','c'];
  217. arr['constructor'] = function() {};
  218. var out = Array.prototype.map.call(arr, f);
  219. assert.isTrue(Array.isArray(out), "Return from Array.prototype.map should be an Array object when constructor has no [@@species] property");
  220. assert.areEqual(['a','b','c'], out, "Array.prototype.map output should show correct Array behavior when constructor has no [@@species] property");
  221. assert.areEqual(3, out.length, "Array.prototype.map sets the length property of returned object when constructor has no [@@species] property");
  222. var builtinArraySpeciesDesc = Object.getOwnPropertyDescriptor(Array, Symbol.species);
  223. var arr = ['a','b','c'];
  224. Object.defineProperty(Array, Symbol.species, {enumerable: false, configurable: true, writable: true, value: Object});
  225. var out = Array.prototype.map.call(arr, f);
  226. assert.isFalse(Array.isArray(out), "Return from Array.prototype.map should be an object when constructor has [@@species] == Object");
  227. assert.areEqual({'0':'a','1':'b','2':'c'}, out, "Array.prototype.map output should show correct Array behavior when constructor has [@@species] == Object");
  228. var arr = ['a','b','c'];
  229. Object.defineProperty(Array, Symbol.species, {enumerable: false, configurable: true, writable: true, value: null});
  230. var out = Array.prototype.map.call(arr, f);
  231. assert.isTrue(Array.isArray(out), "Return from Array.prototype.map should be an Array object when constructor has [@@species] == null");
  232. assert.areEqual(['a','b','c'], out, "Array.prototype.map output should show correct Array behavior when constructor has [@@species] == null");
  233. assert.areEqual(3, out.length, "Array.prototype.map sets the length property of returned object when constructor has [@@species] == null");
  234. Object.defineProperty(Array, Symbol.species, builtinArraySpeciesDesc);
  235. var external = WScript.LoadScriptFile("ES6ArrayUseConstructor_helper.js","samethread");
  236. var arr = ['a','b','c'];
  237. arr['constructor'] = external.CrossContextArrayConstructor;
  238. var out = Array.prototype.map.call(arr, f);
  239. assert.isTrue(Array.isArray(out), "Return from Array.prototype.map should be an Array object when constructor is %Array% of a different script context");
  240. assert.areEqual(['a','b','c'], out, "Array.prototype.map output should show correct Array behavior when constructor is %Array% of a different script context");
  241. assert.areEqual(3, out.length, "Array.prototype.map sets the length property of returned object when constructor is %Array% of a different script context");
  242. }
  243. },
  244. {
  245. name: "ArraySpeciesCreate test through Array.prototype.map - native arrays",
  246. body: function () {
  247. var f = function(val) { return val; }
  248. var arr = [1,2,3];
  249. arr['constructor'] = null;
  250. assert.throws(function() { Array.prototype.map.call(arr, f); }, TypeError, "TypeError when constructor[Symbol.species] is not constructor", "Function 'constructor[Symbol.species]' is not a constructor");
  251. var arr = [1,2,3];
  252. Object.defineProperty(arr, 'constructor', {enumerable: false, configurable: true, writable: true, value: null});
  253. assert.throws(function() { Array.prototype.map.call(arr, f); }, TypeError, "TypeError when constructor[Symbol.species] is not constructor", "Function 'constructor[Symbol.species]' is not a constructor");
  254. var arr = [1,2,3];
  255. arr['constructor'] = undefined;
  256. var out = Array.prototype.map.call(arr, f);
  257. assert.isTrue(Array.isArray(out), "Return from Array.prototype.splice should be an Array object when constructor == undefined");
  258. assert.areEqual([1,2,3], out, "Array.prototype.splice output should show correct Array behavior when constructor == undefined");
  259. assert.areEqual(3, out.length, "Array.prototype.splice sets the length property of returned object when constructor == undefined");
  260. var arr = [1,2,3];
  261. arr['constructor'] = function() {};
  262. var out = Array.prototype.map.call(arr, f);
  263. assert.isTrue(Array.isArray(out), "Return from Array.prototype.splice should be an Array object when constructor has no [@@species] property");
  264. assert.areEqual([1,2,3], out, "Array.prototype.splice output should show correct Array behavior when constructor has no [@@species] property");
  265. assert.areEqual(3, out.length, "Array.prototype.splice sets the length property of returned object when constructor has no [@@species] property");
  266. var builtinArraySpeciesDesc = Object.getOwnPropertyDescriptor(Array, Symbol.species);
  267. var arr = [1,2,3];
  268. Object.defineProperty(Array, Symbol.species, {enumerable: false, configurable: true, writable: true, value: Object});
  269. var out = Array.prototype.map.call(arr, f);
  270. assert.isFalse(Array.isArray(out), "Return from Array.prototype.splice should be an object when constructor has [@@species] == Object");
  271. assert.areEqual({'0':1,'1':2,'2':3}, out, "Array.prototype.splice output should show correct Array behavior when constructor has [@@species] == Object");
  272. var arr = [1,2,3];
  273. Object.defineProperty(Array, Symbol.species, {enumerable: false, configurable: true, writable: true, value: null});
  274. var out = Array.prototype.map.call(arr, f);
  275. assert.isTrue(Array.isArray(out), "Return from Array.prototype.splice should be an Array object when constructor has [@@species] == null");
  276. assert.areEqual([1,2,3], out, "Array.prototype.splice output should show correct Array behavior when constructor has [@@species] == null");
  277. assert.areEqual(3, out.length, "Array.prototype.splice sets the length property of returned object when constructor has [@@species] == null");
  278. Object.defineProperty(Array, Symbol.species, builtinArraySpeciesDesc);
  279. var external = WScript.LoadScriptFile("ES6ArrayUseConstructor_helper.js","samethread");
  280. var arr = [1,2,3];
  281. arr['constructor'] = external.CrossContextArrayConstructor;
  282. var out = Array.prototype.map.call(arr, f);
  283. assert.isTrue(Array.isArray(out), "Return from Array.prototype.splice should be an Array object when constructor is %Array% of a different script context");
  284. assert.areEqual([1,2,3], out, "Array.prototype.splice output should show correct Array behavior when constructor is %Array% of a different script context");
  285. assert.areEqual(3, out.length, "Array.prototype.splice sets the length property of returned object when constructor is %Array% of a different script context");
  286. }
  287. },
  288. {
  289. name: "ArraySpeciesCreate test through Array.prototype.filter - ES5 arrays",
  290. body: function () {
  291. var arr = ['a','b','c'];
  292. Object.defineProperty(arr, "3", { get : function () { return 0xff;}, set: function() { }}); //Create an ES5 array
  293. Object.defineProperty(Array, Symbol.species, {enumerable: false, configurable: true, writable: true, value: Object});
  294. var out = Array.prototype.filter.call(arr, function() { return true; });
  295. assert.isFalse(Array.isArray(out), "Return from Array.prototype.filter should be an object when constructor has [@@species] == Object on an ES5 array");
  296. assert.areEqual('a', out[0], "Array.prototype.filter output Object should have correct first index value when constructor has [@@species] == Object on an ES5 array");
  297. assert.areEqual(255, out[3], "Array.prototype.fitler output Object should have correct last index value when constructor has [@@species] == Object on an ES5 array");
  298. }
  299. },
  300. ];
  301. testRunner.runTests(tests, { verbose: WScript.Arguments[0] != "summary" });