StepModeTests.cs 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482
  1. using Jint.Runtime.Debugger;
  2. namespace Jint.Tests.Runtime.Debugger;
  3. public class StepModeTests
  4. {
  5. /// <summary>
  6. /// Helper method to keep tests independent of line numbers, columns or other arbitrary assertions on
  7. /// the current statement. Steps through script with StepMode.Into until it reaches literal statement
  8. /// (or directive) 'source'. Then counts the steps needed to reach 'target' using the indicated StepMode.
  9. /// </summary>
  10. /// <param name="script">Script used as basis for test</param>
  11. /// <param name="stepMode">StepMode to use from source to target</param>
  12. /// <returns>Number of steps from source to target</returns>
  13. private static int StepsFromSourceToTarget(string script, StepMode stepMode)
  14. {
  15. var engine = new Engine(options => options
  16. .DebugMode()
  17. .InitialStepMode(StepMode.Into)
  18. .DebuggerStatementHandling(DebuggerStatementHandling.Script));
  19. int steps = 0;
  20. bool sourceReached = false;
  21. bool targetReached = false;
  22. engine.Debugger.Step += (sender, info) =>
  23. {
  24. if (sourceReached)
  25. {
  26. steps++;
  27. if (info.ReachedLiteral("target"))
  28. {
  29. // Stop stepping
  30. targetReached = true;
  31. return StepMode.None;
  32. }
  33. return stepMode;
  34. }
  35. else if (info.ReachedLiteral("source"))
  36. {
  37. sourceReached = true;
  38. return stepMode;
  39. }
  40. return StepMode.Into;
  41. };
  42. engine.Execute(script);
  43. // Make sure we actually reached the target
  44. Assert.True(targetReached);
  45. return steps;
  46. }
  47. [Fact]
  48. public void StepsIntoRegularFunctionCall()
  49. {
  50. var script = @"
  51. 'source';
  52. test(); // first step
  53. function test()
  54. {
  55. 'target'; // second step
  56. }";
  57. Assert.Equal(2, StepsFromSourceToTarget(script, StepMode.Into));
  58. }
  59. [Fact]
  60. public void StepsOverRegularFunctionCall()
  61. {
  62. var script = @"
  63. 'source';
  64. test();
  65. 'target';
  66. function test()
  67. {
  68. 'dummy';
  69. }";
  70. Assert.Equal(2, StepsFromSourceToTarget(script, StepMode.Over));
  71. }
  72. [Fact]
  73. public void StepsOutOfRegularFunctionCall()
  74. {
  75. var script = @"
  76. test();
  77. 'target';
  78. function test()
  79. {
  80. 'source';
  81. 'dummy';
  82. }";
  83. Assert.Equal(1, StepsFromSourceToTarget(script, StepMode.Out));
  84. }
  85. [Fact]
  86. public void StepsIntoMemberFunctionCall()
  87. {
  88. var script = @"
  89. const obj = {
  90. test()
  91. {
  92. 'target'; // second step
  93. }
  94. };
  95. 'source';
  96. obj.test(); // first step";
  97. Assert.Equal(2, StepsFromSourceToTarget(script, StepMode.Into));
  98. }
  99. [Fact]
  100. public void StepsOverMemberFunctionCall()
  101. {
  102. var script = @"
  103. const obj = {
  104. test()
  105. {
  106. 'dummy';
  107. }
  108. };
  109. 'source';
  110. obj.test();
  111. 'target';";
  112. Assert.Equal(2, StepsFromSourceToTarget(script, StepMode.Over));
  113. }
  114. [Fact]
  115. public void StepsOutOfMemberFunctionCall()
  116. {
  117. var script = @"
  118. const obj = {
  119. test()
  120. {
  121. 'source';
  122. 'dummy';
  123. }
  124. };
  125. obj.test();
  126. 'target';";
  127. Assert.Equal(1, StepsFromSourceToTarget(script, StepMode.Out));
  128. }
  129. [Fact]
  130. public void StepsIntoCallExpression()
  131. {
  132. var script = @"
  133. function test()
  134. {
  135. 'target'; // second step
  136. return 42;
  137. }
  138. 'source';
  139. const x = test(); // first step";
  140. Assert.Equal(2, StepsFromSourceToTarget(script, StepMode.Into));
  141. }
  142. [Fact]
  143. public void StepsOverCallExpression()
  144. {
  145. var script = @"
  146. function test()
  147. {
  148. 'dummy';
  149. return 42;
  150. }
  151. 'source';
  152. const x = test();
  153. 'target';";
  154. Assert.Equal(2, StepsFromSourceToTarget(script, StepMode.Over));
  155. }
  156. [Fact]
  157. public void StepsOutOfCallExpression()
  158. {
  159. var script = @"
  160. function test()
  161. {
  162. 'source';
  163. 'dummy';
  164. return 42;
  165. }
  166. const x = test();
  167. 'target';";
  168. Assert.Equal(1, StepsFromSourceToTarget(script, StepMode.Out));
  169. }
  170. [Fact]
  171. public void StepsIntoGetAccessor()
  172. {
  173. var script = @"
  174. const obj = {
  175. get test()
  176. {
  177. 'target'; // second step
  178. return 144;
  179. }
  180. };
  181. 'source';
  182. const x = obj.test; // first step";
  183. Assert.Equal(2, StepsFromSourceToTarget(script, StepMode.Into));
  184. }
  185. [Fact]
  186. public void StepsOverGetAccessor()
  187. {
  188. var script = @"
  189. const obj = {
  190. get test()
  191. {
  192. return 144;
  193. }
  194. };
  195. 'source';
  196. const x = obj.test;
  197. 'target';";
  198. Assert.Equal(2, StepsFromSourceToTarget(script, StepMode.Over));
  199. }
  200. [Fact]
  201. public void StepsOutOfGetAccessor()
  202. {
  203. var script = @"
  204. const obj = {
  205. get test()
  206. {
  207. 'source';
  208. 'dummy';
  209. return 144;
  210. }
  211. };
  212. const x = obj.test;
  213. 'target';";
  214. Assert.Equal(1, StepsFromSourceToTarget(script, StepMode.Out));
  215. }
  216. [Fact]
  217. public void StepsIntoSetAccessor()
  218. {
  219. var script = @"
  220. const obj = {
  221. set test(value)
  222. {
  223. 'target'; // second step
  224. this.value = value;
  225. }
  226. };
  227. 'source';
  228. obj.test = 37; // first step";
  229. Assert.Equal(2, StepsFromSourceToTarget(script, StepMode.Into));
  230. }
  231. [Fact]
  232. public void StepsOverSetAccessor()
  233. {
  234. var script = @"
  235. const obj = {
  236. set test(value)
  237. {
  238. this.value = value;
  239. }
  240. };
  241. 'source';
  242. obj.test = 37;
  243. 'target';";
  244. Assert.Equal(2, StepsFromSourceToTarget(script, StepMode.Over));
  245. }
  246. [Fact]
  247. public void StepsOutOfSetAccessor()
  248. {
  249. var script = @"
  250. const obj = {
  251. set test(value)
  252. {
  253. 'source';
  254. 'dummy';
  255. this.value = value;
  256. }
  257. };
  258. obj.test = 37;
  259. 'target';";
  260. Assert.Equal(1, StepsFromSourceToTarget(script, StepMode.Out));
  261. }
  262. [Fact]
  263. public void ReturnPointIsAStep()
  264. {
  265. var script = @"
  266. function test()
  267. {
  268. 'source';
  269. }
  270. test();
  271. 'target';";
  272. Assert.Equal(2, StepsFromSourceToTarget(script, StepMode.Over));
  273. }
  274. [Fact]
  275. public void ReturnStatementIsAStep()
  276. {
  277. var script = @"
  278. function test()
  279. {
  280. 'source';
  281. return 'result';
  282. }
  283. test();
  284. 'target';";
  285. Assert.Equal(3, StepsFromSourceToTarget(script, StepMode.Over));
  286. }
  287. [Fact]
  288. public void StepOutOnlyStepsOutOneStackLevel()
  289. {
  290. var script = @"
  291. function test()
  292. {
  293. 'dummy';
  294. test2();
  295. 'target';
  296. }
  297. function test2()
  298. {
  299. 'source';
  300. 'dummy';
  301. 'dummy';
  302. }
  303. test();";
  304. var engine = new Engine(options => options.DebugMode());
  305. int step = 0;
  306. engine.Debugger.Step += (sender, info) =>
  307. {
  308. switch (step)
  309. {
  310. case 0:
  311. if (info.ReachedLiteral("source"))
  312. {
  313. step++;
  314. return StepMode.Out;
  315. }
  316. break;
  317. case 1:
  318. Assert.True(info.ReachedLiteral("target"));
  319. step++;
  320. break;
  321. }
  322. return StepMode.Into;
  323. };
  324. engine.Execute(script);
  325. }
  326. [Fact]
  327. public void StepOverDoesSinglestepAfterBreakpoint()
  328. {
  329. string script = @"
  330. test();
  331. function test()
  332. {
  333. 'dummy';
  334. debugger;
  335. 'target';
  336. }";
  337. var engine = new Engine(options => options
  338. .DebugMode()
  339. .DebuggerStatementHandling(DebuggerStatementHandling.Script));
  340. bool stepping = false;
  341. engine.Debugger.Break += (sender, info) =>
  342. {
  343. stepping = true;
  344. return StepMode.Over;
  345. };
  346. engine.Debugger.Step += (sender, info) =>
  347. {
  348. if (stepping)
  349. {
  350. Assert.True(info.ReachedLiteral("target"));
  351. }
  352. return StepMode.None;
  353. };
  354. engine.Execute(script);
  355. }
  356. [Fact]
  357. public void StepNotTriggeredWhenRunning()
  358. {
  359. string script = @"
  360. test();
  361. function test()
  362. {
  363. 'dummy';
  364. 'dummy';
  365. }";
  366. var engine = new Engine(options => options
  367. .DebugMode()
  368. .InitialStepMode(StepMode.Into));
  369. int stepCount = 0;
  370. engine.Debugger.Step += (sender, info) =>
  371. {
  372. stepCount++;
  373. // Start running after first step
  374. return StepMode.None;
  375. };
  376. engine.Execute(script);
  377. Assert.Equal(1, stepCount);
  378. }
  379. [Fact]
  380. public void SkipIsTriggeredWhenRunning()
  381. {
  382. string script = @"
  383. 'step';
  384. 'skip';
  385. 'skip';
  386. debugger;
  387. 'step';
  388. 'step';
  389. ";
  390. var engine = new Engine(options => options
  391. .DebugMode()
  392. .DebuggerStatementHandling(DebuggerStatementHandling.Script)
  393. .InitialStepMode(StepMode.Into));
  394. int stepCount = 0;
  395. int skipCount = 0;
  396. engine.Debugger.Step += (sender, info) =>
  397. {
  398. Assert.True(TestHelpers.IsLiteral(info.CurrentNode, "step"));
  399. stepCount++;
  400. // Start running after first step
  401. return stepCount == 1 ? StepMode.None : StepMode.Into;
  402. };
  403. engine.Debugger.Skip += (sender, info) =>
  404. {
  405. Assert.True(TestHelpers.IsLiteral(info.CurrentNode, "skip"));
  406. skipCount++;
  407. return StepMode.None;
  408. };
  409. engine.Debugger.Break += (sender, info) =>
  410. {
  411. // Back to stepping after debugger statement
  412. return StepMode.Into;
  413. };
  414. engine.Execute(script);
  415. Assert.Equal(2, skipCount);
  416. Assert.Equal(3, stepCount);
  417. }
  418. }