StepFlowTests.cs 9.9 KB

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