StepFlowTests.cs 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282
  1. using Esprima;
  2. using Esprima.Ast;
  3. using Jint.Runtime.Debugger;
  4. namespace Jint.Tests.Runtime.Debugger
  5. {
  6. public class StepFlowTests
  7. {
  8. private List<Node> CollectStepNodes(string script)
  9. {
  10. var engine = new Engine(options => options
  11. .DebugMode()
  12. .InitialStepMode(StepMode.Into));
  13. var nodes = new List<Node>();
  14. engine.Debugger.Step += (sender, info) =>
  15. {
  16. nodes.Add(info.CurrentNode);
  17. return StepMode.Into;
  18. };
  19. engine.Execute(script);
  20. return nodes;
  21. }
  22. [Fact]
  23. public void StepsThroughWhileLoop()
  24. {
  25. var script = @"
  26. let x = 0;
  27. while (x < 2)
  28. {
  29. x++;
  30. }
  31. ";
  32. var nodes = CollectStepNodes(script);
  33. Assert.Collection(nodes,
  34. node => Assert.IsType<VariableDeclaration>(node), // let x = 0;
  35. node => Assert.IsType<WhileStatement>(node), // while ...
  36. node => Assert.IsType<BinaryExpression>(node), // x < 2
  37. node => Assert.IsType<ExpressionStatement>(node), // x++;
  38. node => Assert.IsType<BinaryExpression>(node), // x < 2
  39. node => Assert.IsType<ExpressionStatement>(node), // x++;
  40. node => Assert.IsType<BinaryExpression>(node) // x < 2 (false)
  41. );
  42. }
  43. [Fact]
  44. public void StepsThroughDoWhileLoop()
  45. {
  46. var script = @"
  47. let x = 0;
  48. do
  49. {
  50. x++;
  51. }
  52. while (x < 2)
  53. ";
  54. var nodes = CollectStepNodes(script);
  55. Assert.Collection(nodes,
  56. node => Assert.IsType<VariableDeclaration>(node), // let x = 0;
  57. node => Assert.IsType<DoWhileStatement>(node), // do ...
  58. node => Assert.IsType<ExpressionStatement>(node), // x++;
  59. node => Assert.IsType<BinaryExpression>(node), // x < 2
  60. node => Assert.IsType<ExpressionStatement>(node), // x++;
  61. node => Assert.IsType<BinaryExpression>(node) // x < 2 (false)
  62. );
  63. }
  64. [Fact]
  65. public void StepsThroughForLoop()
  66. {
  67. var script = @"
  68. for (let x = 0; x < 2; x++)
  69. {
  70. 'dummy';
  71. }
  72. ";
  73. var nodes = CollectStepNodes(script);
  74. Assert.Collection(nodes,
  75. node => Assert.IsType<ForStatement>(node), // for ...
  76. node => Assert.IsType<VariableDeclaration>(node), // let x = 0
  77. node => Assert.IsType<BinaryExpression>(node), // x < 2
  78. node => Assert.True(node.IsLiteral("dummy")), // 'dummy';
  79. node => Assert.IsType<UpdateExpression>(node), // x++;
  80. node => Assert.IsType<BinaryExpression>(node), // x < 2
  81. node => Assert.True(node.IsLiteral("dummy")), // 'dummy';
  82. node => Assert.IsType<UpdateExpression>(node), // x++;
  83. node => Assert.IsType<BinaryExpression>(node) // x < 2 (false)
  84. );
  85. }
  86. [Fact]
  87. public void StepsThroughForOfLoop()
  88. {
  89. var script = @"
  90. const arr = [1, 2];
  91. for (const item of arr)
  92. {
  93. 'dummy';
  94. }
  95. ";
  96. var nodes = CollectStepNodes(script);
  97. Assert.Collection(nodes,
  98. node => Assert.IsType<VariableDeclaration>(node), // let arr = [1, 2];
  99. node => Assert.IsType<ForOfStatement>(node), // for ...
  100. node => Assert.IsType<VariableDeclaration>(node), // item
  101. node => Assert.True(node.IsLiteral("dummy")), // 'dummy';
  102. node => Assert.IsType<VariableDeclaration>(node), // item
  103. node => Assert.True(node.IsLiteral("dummy")) // 'dummy';
  104. );
  105. }
  106. [Fact]
  107. public void StepsThroughForInLoop()
  108. {
  109. var script = @"
  110. const obj = { x: 1, y: 2 };
  111. for (const key in obj)
  112. {
  113. 'dummy';
  114. }
  115. ";
  116. var nodes = CollectStepNodes(script);
  117. Assert.Collection(nodes,
  118. node => Assert.IsType<VariableDeclaration>(node), // let obj = { x: 1, y: 2 };
  119. node => Assert.IsType<ForInStatement>(node), // for ...
  120. node => Assert.IsType<VariableDeclaration>(node), // key
  121. node => Assert.IsType<ExpressionStatement>(node), // 'dummy';
  122. node => Assert.IsType<VariableDeclaration>(node), // key
  123. node => Assert.IsType<ExpressionStatement>(node) // 'dummy';
  124. );
  125. }
  126. [Fact]
  127. public void StepsThroughConstructor()
  128. {
  129. var script = @"
  130. class Test
  131. {
  132. constructor()
  133. {
  134. 'in constructor';
  135. }
  136. }
  137. new Test();
  138. 'after construction';
  139. ";
  140. var nodes = CollectStepNodes(script);
  141. Assert.Collection(nodes,
  142. node => Assert.IsType<ClassDeclaration>(node), // class Test
  143. node => Assert.IsType<ExpressionStatement>(node), // new Test();
  144. node => Assert.True(node.IsLiteral("in constructor")), // 'in constructor()'
  145. node => Assert.Null(node), // return point
  146. node => Assert.True(node.IsLiteral("after construction"))
  147. );
  148. }
  149. [Fact]
  150. public void SkipsFunctionBody()
  151. {
  152. var script = @"
  153. function test()
  154. {
  155. 'dummy';
  156. }
  157. test();
  158. ";
  159. var nodes = CollectStepNodes(script);
  160. Assert.Collection(nodes,
  161. node => Assert.IsType<FunctionDeclaration>(node), // function(test) ...;
  162. node => Assert.IsType<ExpressionStatement>(node), // test();
  163. node => Assert.True(node.IsLiteral("dummy")), // 'dummy';
  164. node => Assert.Null(node) // return point
  165. );
  166. }
  167. [Fact]
  168. public void SkipsReturnPointOfImplicitConstructor()
  169. {
  170. var script = @"
  171. class Test
  172. {
  173. }
  174. new Test();
  175. 'dummy';
  176. ";
  177. var nodes = CollectStepNodes(script);
  178. Assert.Collection(nodes,
  179. node => Assert.IsType<ClassDeclaration>(node), // class Test
  180. node => Assert.IsType<ExpressionStatement>(node), // new Test();
  181. node => Assert.True(node.IsLiteral("dummy")) // 'dummy';
  182. );
  183. }
  184. [Fact]
  185. public void StepIntoNamedFunctionCalls()
  186. {
  187. var script = @"
  188. function a( ) { return 2; }
  189. function b(l) { return l + a(); }
  190. function c( ) { return b(3) + a(); }
  191. let res = c();
  192. ";
  193. var steps = StepIntoScript(script);
  194. Assert.Collection(steps,
  195. step => Assert.Equal("function c( ) { »return b(3) + a(); }", step),
  196. step => Assert.Equal("function b(l) { »return l + a(); }", step),
  197. step => Assert.Equal("function a( ) { »return 2; }", step),
  198. step => Assert.Equal("function a( ) { return 2; }»", step),
  199. step => Assert.Equal("function b(l) { return l + a(); }»", step),
  200. step => Assert.Equal("function a( ) { »return 2; }", step),
  201. step => Assert.Equal("function a( ) { return 2; }»", step),
  202. step => Assert.Equal("function c( ) { return b(3) + a(); }»", step));
  203. }
  204. [Fact]
  205. public void StepIntoArrowFunctionCalls()
  206. {
  207. var script = @"
  208. const a = ( ) => 2;
  209. const b = (l) => l + a();
  210. const c = ( ) => b(3) + a();
  211. let res = c();
  212. ";
  213. var steps = StepIntoScript(script);
  214. Assert.Collection(steps,
  215. step => Assert.Equal("const c = ( ) => »b(3) + a();", step),
  216. step => Assert.Equal("const b = (l) => »l + a();", step),
  217. step => Assert.Equal("const a = ( ) => »2;", step),
  218. step => Assert.Equal("const a = ( ) => 2»;", step),
  219. step => Assert.Equal("const b = (l) => l + a()»;", step),
  220. step => Assert.Equal("const a = ( ) => »2;", step),
  221. step => Assert.Equal("const a = ( ) => 2»;", step),
  222. step => Assert.Equal("const c = ( ) => b(3) + a()»;", step));
  223. }
  224. private List<string> StepIntoScript(string script)
  225. {
  226. var engine = new Engine(options => options
  227. .DebugMode()
  228. .InitialStepMode(StepMode.Into));
  229. var stepStatements = new List<string>();
  230. var scriptLines = script.Replace("\r\n", "\n").Replace("\r", "\n").Split('\n');
  231. engine.Debugger.Step += (sender, information) =>
  232. {
  233. if (information.CurrentNode is not VariableDeclaration && information.CurrentNode is not FunctionDeclaration)
  234. OutputPosition(information.Location);
  235. return StepMode.Into;
  236. };
  237. engine.Execute(script);
  238. return stepStatements;
  239. void OutputPosition(Location location)
  240. {
  241. var line = scriptLines[location.Start.Line - 1];
  242. var withPositionIndicator = string.Concat(line.Substring(0, location.Start.Column), "»", line.Substring(location.Start.Column));
  243. stepStatements.Add(withPositionIndicator.TrimEnd());
  244. }
  245. }
  246. }
  247. }