ES6NewTarget.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280
  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 new.target tests
  6. WScript.LoadScriptFile("..\\UnitTestFramework\\UnitTestFramework.js");
  7. var tests = [
  8. {
  9. name: "Test new.target parsing path doesn't confuse 'new target'",
  10. body: function() {
  11. function target() { return { name: 'something' }; }
  12. var t = new target; // implicitly 'new target()'
  13. assert.areEqual('something', t.name, "new target() returned our new object instead of new.target");
  14. }
  15. },
  16. {
  17. name: "Test new.target in various block scopes'",
  18. body: function() {
  19. assert.doesNotThrow(function(){{new.target;}}, "new.target one level block do not throw in a function");
  20. assert.doesNotThrow(function(){{{new.target;}}}, "new.target two level block do not throw in a function");
  21. assert.doesNotThrow(function(){with({}) {new.target;}}, "new.target with scope body call does not throw");
  22. assert.doesNotThrow(function() { function parent(x) { new x();}; function child(){ with(new.target) {toString();}}; parent(child); }, "new.target with scope parameter does not throw");
  23. assert.doesNotThrow(function(){{if(true){new.target;}}}, "new.target condition block in nested block do not throw in a function");
  24. assert.doesNotThrow(function(){try { throw Error;} catch(e){new.target;}}, "new.target catch block do not throw in a function");
  25. assert.doesNotThrow(function(){ var a = b = c = 1; try {} catch([a,b,c]) { new.target;}}, "new.target in CatchParamPattern block do not throw in a function");
  26. assert.doesNotThrow(function(){ var x = function() {new.target;}; x();}, "new.target in function expression do not throw in a function");
  27. assert.doesNotThrow(function(){ var o = { "foo" : function () { new.target}}; o.foo();}, "new.target in named function expression do not throw in a function");
  28. }
  29. },
  30. {
  31. name: "Test new.target parsing path with badly-formed meta-property references",
  32. body: function() {
  33. assert.throws(function() { return new['target']; }, TypeError, "Meta-property new.target is not a real property lookup", "Object doesn't support this action");
  34. assert.throws(function() { return eval('new.'); }, SyntaxError, "Something like 'new.' should fall out of the meta-property parser path", "Syntax error");
  35. assert.throws(function() { return eval('new.target2'); }, SyntaxError, "No other keywords should produce meta-properties", "Syntax error");
  36. assert.throws(function() { return eval('new.something'); }, SyntaxError, "No other keywords should produce meta-properties", "Syntax error");
  37. assert.throws(function() { return eval('new.eval'); }, SyntaxError, "No other keywords should produce meta-properties", "Syntax error");
  38. }
  39. },
  40. {
  41. name: "There is now a well-known PID for 'target' - ensure it doesn't break",
  42. body: function() {
  43. var obj = { target: 'something' };
  44. assert.areEqual('something', obj.target, "The name 'target' can be used as an identifier");
  45. }
  46. },
  47. /*
  48. // Blocked by 'ReferenceError: '<_lexicalNewTargetSymbol>' is undefined' bug
  49. {
  50. name: "new.target is not valid for assignment",
  51. body: function() {
  52. assert.throws(function() { eval("new.target = 'something';"); }, ReferenceError, "new.target cannot be a lhs in an assignment expression - this is an early reference error", "Invalid left-hand side in assignment");
  53. assert.throws(function() { eval("((new.target)) = 'something';"); }, ReferenceError, "new.target cannot be a lhs in an assignment expression - this is an early reference error", "Invalid left-hand side in assignment");
  54. }
  55. },
  56. */
  57. {
  58. name: "Simple base class gets new.target correctly",
  59. body: function() {
  60. var called = false;
  61. class SimpleBaseClass {
  62. constructor() {
  63. assert.isTrue(new.target === SimpleBaseClass, "new.target === SimpleBaseClass");
  64. called = true;
  65. }
  66. }
  67. var myObj = new SimpleBaseClass();
  68. assert.isTrue(called, "The constructor was called.");
  69. }
  70. },
  71. {
  72. name: "Simple derived and base class passes new.target correctly",
  73. body: function() {
  74. var called = false;
  75. class BaseClassForB {
  76. constructor() {
  77. assert.isTrue(new.target === DerivedClassForB, "new.target === DerivedClassForB");
  78. called = true;
  79. }
  80. }
  81. class DerivedClassForB extends BaseClassForB {
  82. constructor() {
  83. assert.isTrue(new.target === DerivedClassForB, "new.target === DerivedClassForB");
  84. super();
  85. }
  86. }
  87. var myB = new DerivedClassForB();
  88. assert.isTrue(called, "The super-chain was called.");
  89. }
  90. },
  91. {
  92. name: "Simple base class with arrow function using new.target correctly",
  93. body: function() {
  94. var called = false;
  95. class SimpleBaseClass {
  96. constructor() {
  97. var arrow = () => {
  98. assert.isTrue(new.target === SimpleBaseClass, "new.target === SimpleBaseClass");
  99. called = true;
  100. }
  101. arrow();
  102. }
  103. }
  104. var myObj = new SimpleBaseClass();
  105. assert.isTrue(called, "The constructor was called.");
  106. }
  107. },
  108. {
  109. name: "new.target behavior in arrow function inside derived class",
  110. body: function() {
  111. let constructed = false;
  112. class C {
  113. constructor() {
  114. let arrow = () => {
  115. assert.isTrue(D === new.target, "Class constructor implicitly invoked via super call has new.target set to derived constructor (also in arrow)");
  116. constructed = true;
  117. };
  118. arrow();
  119. }
  120. }
  121. class D extends C {
  122. constructor() {
  123. let arrow = () => {
  124. assert.isTrue(D === new.target, "Class constructor explicitly invoked via new keyword has new.target set to that constructor (also in arrow)");
  125. };
  126. arrow();
  127. super();
  128. }
  129. }
  130. let myD = new D();
  131. assert.isTrue(constructed, "We actually ran the constructor code");
  132. }
  133. },
  134. {
  135. name: "new.target behavior in a normal function",
  136. body: function() {
  137. function foo() {
  138. assert.isTrue(undefined === new.target, "Normal function call has new.target set to undefined in the function body");
  139. return new.target;
  140. }
  141. assert.isTrue(undefined === foo(), "Normal function returning new.target returns undefined");
  142. }
  143. },
  144. {
  145. name: "new.target behavior in a normal function in a new expression",
  146. body: function() {
  147. function foo() {
  148. assert.isTrue(foo === new.target, "Function called as new expression has new.target set to the function in the function body");
  149. return new.target;
  150. }
  151. assert.isTrue(foo === new foo(), "Function called-as-constructor has new.target set to that function");
  152. }
  153. },
  154. {
  155. name: "new.target behavior in an arrow in a normal function",
  156. body: function() {
  157. function foo() {
  158. let arrow = () => {
  159. assert.isTrue(undefined === new.target, "Normal function call has new.target set to undefined in the function body");
  160. return new.target;
  161. };
  162. return arrow();
  163. }
  164. assert.isTrue(undefined === foo(), "Normal function returning new.target returns undefined");
  165. }
  166. },
  167. {
  168. name: "new.target behaviour in an arrow in a normal function in a new expression",
  169. body: function() {
  170. function foo() {
  171. let arrow = () => {
  172. assert.isTrue(foo === new.target, "Function called as new expression has new.target set to the function in the function body");
  173. return new.target;
  174. };
  175. return arrow();
  176. }
  177. assert.isTrue(foo === new foo(), "Function called-as-constructor has new.target set to that function");
  178. }
  179. },
  180. {
  181. name: "new.target captured from class constructor via arrow",
  182. body: function() {
  183. class base {
  184. constructor() {
  185. let arrow = () => {
  186. assert.isTrue(derived === new.target, "Function called as new expression has new.target set to the function in the function body");
  187. return new.target;
  188. };
  189. return arrow;
  190. }
  191. }
  192. class derived extends base {
  193. constructor() {
  194. return super();
  195. }
  196. }
  197. let arrow = new derived();
  198. assert.isTrue(derived === arrow(), "Arrow capturing new.target returns correct value");
  199. }
  200. },
  201. {
  202. name: "new.target inline constructor case",
  203. body: function() {
  204. function foo()
  205. {
  206. return new.target;
  207. }
  208. function bar()
  209. {
  210. return new foo(); //foo will be inlined here
  211. }
  212. assert.isTrue(bar() == foo, "Function called as new expression has new.target set to the function in the function body when the constructor is inlined");
  213. }
  214. },
  215. {
  216. name: "new.target inline case",
  217. body: function() {
  218. function foo()
  219. {
  220. return new.target;
  221. }
  222. function bar()
  223. {
  224. return foo(); //foo will be inlined here
  225. }
  226. assert.isTrue(bar() == undefined, "Normal inlined function has new.target set to undefined in the function body");
  227. }
  228. },
  229. {
  230. name: "new.target generator case",
  231. body: function() {
  232. function *foo()
  233. {
  234. yield new.target;
  235. }
  236. assert.isTrue((foo()).next().value == undefined, "Generator function has new.target set to undefined in the function body");
  237. }
  238. },
  239. ];
  240. testRunner.runTests(tests, { verbose: WScript.Arguments[0] != "summary" });