2
0

StepFlowTests.cs 9.4 KB

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