ES6SubclassableBuiltins.js 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247
  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 Subclassable tests -- verifies subclass construction behavior
  6. WScript.LoadScriptFile("..\\UnitTestFramework\\UnitTestFramework.js");
  7. var tests = [
  8. {
  9. name: "Subclass of Boolean",
  10. body: function () {
  11. class MyBoolean extends Boolean {
  12. constructor(...val) {
  13. super(...val);
  14. this.prop = 'mybool';
  15. }
  16. method() {
  17. return this.prop;
  18. }
  19. }
  20. assert.areEqual('mybool', new MyBoolean(true).method(), "Subclass of Boolean has correct methods and properties");
  21. assert.isTrue(new MyBoolean(true) == true, "Subclass of Boolean object has correct boolean value");
  22. assert.isTrue(new MyBoolean(false) == false, "Subclass of Boolean object has correct boolean value");
  23. }
  24. },
  25. {
  26. name: "Subclass of Error",
  27. body: function () {
  28. function verifySubclassError(constructor, constructorName) {
  29. class MyError extends constructor {
  30. constructor(...val) {
  31. super(...val);
  32. this.prop = 'myerrorsubclass of ' + constructorName;
  33. }
  34. method() {
  35. return this.prop;
  36. }
  37. }
  38. assert.areEqual('myerrorsubclass of ' + constructorName, new MyError('message').method(), "Subclass of " + constructorName + " has correct methods and properties");
  39. assert.areEqual(constructorName + ": message", new MyError('message').toString(), "Subclass of " + constructorName + " has correct message value");
  40. }
  41. verifySubclassError(Error, 'Error');
  42. verifySubclassError(EvalError, 'EvalError');
  43. verifySubclassError(RangeError, 'RangeError');
  44. verifySubclassError(ReferenceError, 'ReferenceError');
  45. verifySubclassError(SyntaxError, 'SyntaxError');
  46. verifySubclassError(TypeError, 'TypeError');
  47. verifySubclassError(URIError, 'URIError');
  48. }
  49. },
  50. {
  51. name: "Subclass of Number",
  52. body: function () {
  53. class MyNumber extends Number {
  54. constructor(...val) {
  55. super(...val);
  56. this.prop = 'mynumber';
  57. }
  58. method() {
  59. return this.prop;
  60. }
  61. }
  62. assert.areEqual('mynumber', new MyNumber(0).method(), "Subclass of Number has correct methods and properties");
  63. assert.isTrue(new MyNumber(123) == 123, "Subclass of Number object has correct value");
  64. assert.isTrue(new MyNumber() == 0, "MyNumber constructor calls super with no argument should behave the same way as Number constructor and return NaN!");
  65. }
  66. },
  67. {
  68. name: "Subclass of Array",
  69. body: function () {
  70. class MyArray extends Array {
  71. constructor(...val) {
  72. super(...val);
  73. this.prop = 'myarray';
  74. }
  75. method() {
  76. return this.prop;
  77. }
  78. }
  79. assert.areEqual('myarray', new MyArray().method(), "Subclass of Array has correct methods and properties");
  80. assert.areEqual(0, new MyArray().length, "Subclass of Array object has correct length when constructor called with no arguments");
  81. assert.areEqual(100, new MyArray(100).length, "Subclass of Array object has correct length when constructor called with single numeric argument");
  82. assert.areEqual(50, new MyArray(50.0).length, "Subclass of Array object has correct length when constructor called with single float argument");
  83. assert.areEqual(1, new MyArray('something').length, "Subclass of Array object has correct length when constructor called with single non-numeric argument");
  84. assert.areEqual('something', new MyArray('something')[0], "Subclass of Array object has correct length when constructor called with single non-numeric argument");
  85. var a = new MyArray(1,2,3);
  86. assert.areEqual(3, a.length, "Subclass of Array object has correct length when constructor called with multiple arguments");
  87. assert.areEqual(1, a[0], "Subclass of Array object has correct values when constructor called with multiple arguments");
  88. assert.areEqual(2, a[1], "Subclass of Array object has correct values when constructor called with multiple arguments");
  89. assert.areEqual(3, a[2], "Subclass of Array object has correct values when constructor called with multiple arguments");
  90. assert.isTrue(Array.isArray(a), "Subclass of Array is an array as tested via Array.isArray");
  91. }
  92. },
  93. {
  94. name: "Subclass of Array - proto chain",
  95. body: function () {
  96. class MyArray extends Array
  97. {
  98. constructor(...args) { super(...args); }
  99. getFirstElement() { return this.length > 0 ? this[0] : undefined; }
  100. getLastElement() { return this.length > 0 ? this[this.length-1] : undefined; }
  101. }
  102. class OurArray extends MyArray
  103. {
  104. constructor(...args) { super(...args); }
  105. getLength() { return this.length; }
  106. }
  107. function verifyProtoChain(obj, length, newElement, firstElement)
  108. {
  109. assert.areEqual(false, obj instanceof Function, "Subclass of Array is not a function object");
  110. assert.areEqual(true, obj instanceof Array, "Subclass of Array is an Array");
  111. assert.areEqual(true, obj instanceof MyArray, "Subclass of Array is a 'MyArray' instance");
  112. assert.areEqual(true, obj instanceof OurArray, "Subclass of Array is a 'OurArray' instance");
  113. assert.areEqual(OurArray.prototype, obj.__proto__, "obj's [[Prototype]] slot points to OurArray.prototype");
  114. assert.areEqual(MyArray.prototype, obj.__proto__.__proto__, "obj's 2nd-order [[Prototype]] points to MyArray.prototype");
  115. assert.areEqual(Array.prototype, obj.__proto__.__proto__.__proto__, "obj's 3rd-order [[Prototype]] chain points to Array.prototype");
  116. assert.areEqual(length, obj.length, "Subclass of Array is a 'OurArray' instance");
  117. obj[length] = newElement;
  118. assert.areEqual(length + 1, obj.length, "Subclass of Array is a 'OurArray' instance");
  119. assert.areEqual(length + 1, obj.getLength(), "obj.getLength() returns "+ (length + 1));
  120. assert.areEqual(firstElement, obj.getFirstElement(), "obj.getFirstElement() returns "+ firstElement);
  121. assert.areEqual(newElement, obj.getLastElement(), "obj.getLastElement() returns "+ newElement);
  122. }
  123. assert.areEqual(MyArray, OurArray.__proto__, "OurArray's [[Prototype]] slot points to MyArray");
  124. assert.areEqual(Array, MyArray.__proto__, "MyArray's [[Prototype]] slot points to Array");
  125. verifyProtoChain(new OurArray(), 0, 1, 1);
  126. verifyProtoChain(new OurArray('e'), 1, 'element', 'e');
  127. verifyProtoChain(new OurArray('xyz',2), 2, function(){}, 'xyz');
  128. verifyProtoChain(new OurArray(1,2,3), 3, 4, 1);
  129. verifyProtoChain(new OurArray('a','b','c','d'), 4, 'e', 'a');
  130. verifyProtoChain(new OurArray(100), 100, 'element', undefined);
  131. }
  132. },
  133. {
  134. name: "Subclass of built-in constructors - verify proto chain",
  135. body: function () {
  136. function testProtoChain (Type, isFunction, ctorArgs)
  137. {
  138. class MyType extends Type
  139. {
  140. constructor(...args) { super(...args); this.prop1="method1"; }
  141. method1() { return ">"+this.prop1; }
  142. }
  143. class OurType extends MyType
  144. {
  145. constructor(...args) { super(...args); this.prop0="method0"; }
  146. method0() { return ">"+this.prop0; }
  147. }
  148. function verifyProtoChain(obj)
  149. {
  150. assert.areEqual(isFunction, obj instanceof Function, "Subclass of "+ Type.name +" is" + (isFunction ? "" : " not") + " a function object");
  151. assert.areEqual(true, obj instanceof Type, "Subclass of " + Type.name + " is an instance of " + Type.name);
  152. assert.areEqual(true, obj instanceof MyType, "Subclass of " + Type.name + " is an instance of 'MyType'");
  153. assert.areEqual(true, obj instanceof OurType, "Subclass of " + Type.name + " is an instance of 'OurType'");
  154. assert.areEqual(OurType.prototype, obj.__proto__, "obj's [[Prototype]] slot points to OurType.prototype");
  155. assert.areEqual(MyType.prototype, obj.__proto__.__proto__, "obj's 2nd-order [[Prototype]] points to MyType.prototype");
  156. assert.areEqual(Type.prototype, obj.__proto__.__proto__.__proto__, "obj's 3rd-order [[Prototype]] chain points to Type.prototype");
  157. assert.areEqual(">method0", obj.method0(), "obj");
  158. assert.areEqual(">method1", obj.method1(), "obj");
  159. }
  160. assert.areEqual(MyType, OurType.__proto__, "OurType's [[Prototype]] slot points to MyType");
  161. assert.areEqual(Type, MyType.__proto__, "MyType's [[Prototype]] slot points to Type");
  162. verifyProtoChain(eval("new OurType("+ctorArgs+")"));
  163. }
  164. function testReflectConstructNewTarget (Type, isFunction, ctorArgs)
  165. {
  166. class MyType extends Type {}
  167. let obj = Reflect.construct(Type, eval("["+ctorArgs+"]"), MyType);
  168. assert.areEqual(true, obj instanceof MyType, "new.target should be available in built-in subclassable constructor " + Type.name);
  169. }
  170. function forEachBuiltinSubclassable(test)
  171. {
  172. let GeneratorFunction = (function* g() {}).constructor;
  173. let TypedArray = Int8Array.__proto__;
  174. test(Array, false, "");
  175. test(ArrayBuffer, false, "");
  176. test(SharedArrayBuffer, false, "");
  177. test(Boolean, false, "");
  178. test(DataView, false, "new ArrayBuffer()");
  179. test(Date, false, "");
  180. test(Error, false, "");
  181. test( EvalError, false, "");
  182. test( RangeError, false, "");
  183. test( ReferenceError, false, "");
  184. test( SyntaxError, false, "");
  185. test( TypeError, false, "");
  186. test( URIError, false, "");
  187. test(Function, true, "");
  188. test(GeneratorFunction, true, "");
  189. test(Map, false, "");
  190. test(Number, false, "");
  191. test(Object, false, "");
  192. test(Promise, false, "function() {}");
  193. test(RegExp, false, "");
  194. test(Set, false, "");
  195. test(String, false, "");
  196. assert.throws( function() { test(Symbol, false, ""); }, TypeError,
  197. "Subclasses of Symbol cannot be instantiated", "Function is not a constructor");
  198. assert.throws( function() { test(TypedArray, false, ""); }, TypeError,
  199. "Subclasses of typed array constructor cannot be instantiated", "Typed array constructor argument is invalid");
  200. test( Int8Array, false, "");
  201. test( Int16Array, false, "");
  202. test( Int32Array, false, "");
  203. test( Uint8Array, false, "");
  204. test( Uint8ClampedArray, false, "");
  205. test( Uint16Array, false, "");
  206. test( Uint32Array, false, "");
  207. test( Float32Array, false, "");
  208. test( Float64Array, false, "");
  209. test(WeakMap, false, "");
  210. test(WeakSet, false, "");
  211. }
  212. forEachBuiltinSubclassable(testProtoChain);
  213. forEachBuiltinSubclassable(testReflectConstructNewTarget);
  214. }
  215. },
  216. ];
  217. testRunner.runTests(tests, { verbose: WScript.Arguments[0] != "summary" });