CallStackTests.cs 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292
  1. using Jint.Runtime.Debugger;
  2. namespace Jint.Tests.Runtime.Debugger;
  3. public class CallStackTests
  4. {
  5. [Fact]
  6. public void IncludesFunctionNames()
  7. {
  8. var script = @"
  9. function foo()
  10. {
  11. debugger;
  12. }
  13. function bar()
  14. {
  15. foo();
  16. }
  17. bar()";
  18. TestHelpers.TestAtBreak(script, info =>
  19. {
  20. Assert.Collection(info.CallStack,
  21. frame => Assert.Equal("foo", frame.FunctionName),
  22. frame => Assert.Equal("bar", frame.FunctionName),
  23. frame => Assert.Equal("(anonymous)", frame.FunctionName)
  24. );
  25. });
  26. }
  27. [Fact]
  28. public void IncludesLocations()
  29. {
  30. var script = @"
  31. function foo()
  32. {
  33. debugger;
  34. }
  35. function bar()
  36. {
  37. foo();
  38. }
  39. bar()";
  40. TestHelpers.TestAtBreak(script, info =>
  41. {
  42. // The line numbers here may mislead - the positions are, as would be expected,
  43. // at the position before the currently executing line, not the line after.
  44. // Remember that Esprima (and hence Jint) line numbers are 1-based, not 0-based.
  45. Assert.Collection(info.CallStack,
  46. // "debugger;"
  47. frame => Assert.Equal(Position.From(4, 0), frame.Location.Start),
  48. // "foo();"
  49. frame => Assert.Equal(Position.From(9, 0), frame.Location.Start),
  50. // "bar();"
  51. frame => Assert.Equal(Position.From(12, 0), frame.Location.Start)
  52. );
  53. });
  54. }
  55. [Fact]
  56. public void IncludesFunctionLocations()
  57. {
  58. var script = @"
  59. function foo()
  60. {
  61. debugger;
  62. }
  63. function bar()
  64. {
  65. foo();
  66. }
  67. bar()";
  68. TestHelpers.TestAtBreak(script, info =>
  69. {
  70. // Remember that Esprima (and hence Jint) line numbers are 1-based, not 0-based.
  71. Assert.Collection(info.CallStack,
  72. // function foo()
  73. frame => Assert.Equal(Position.From(2, 0), frame.FunctionLocation?.Start),
  74. // function bar()
  75. frame => Assert.Equal(Position.From(7, 0), frame.FunctionLocation?.Start),
  76. // global - no function location
  77. frame => Assert.Equal(null, frame.FunctionLocation?.Start)
  78. );
  79. });
  80. }
  81. [Fact]
  82. public void HasReturnValue()
  83. {
  84. string script = @"
  85. function foo()
  86. {
  87. return 'result';
  88. }
  89. foo();";
  90. var engine = new Engine(options => options.DebugMode().InitialStepMode(StepMode.Into));
  91. bool atReturn = false;
  92. bool didCheckReturn = false;
  93. engine.Debugger.Step += (sender, info) =>
  94. {
  95. if (atReturn)
  96. {
  97. Assert.NotNull(info.CurrentCallFrame.ReturnValue);
  98. Assert.Equal("result", info.CurrentCallFrame.ReturnValue.AsString());
  99. didCheckReturn = true;
  100. atReturn = false;
  101. }
  102. if (info.CurrentNode is ReturnStatement)
  103. {
  104. // Step one further, and we should have the return value
  105. atReturn = true;
  106. }
  107. return StepMode.Into;
  108. };
  109. engine.Execute(script);
  110. Assert.True(didCheckReturn);
  111. }
  112. [Fact]
  113. public void HasThis()
  114. {
  115. string script = @"
  116. function Thing(name)
  117. {
  118. this.name = name;
  119. }
  120. Thing.prototype.test = function()
  121. {
  122. debugger;
  123. }
  124. var car = new Thing('car');
  125. car.test();
  126. ";
  127. TestHelpers.TestAtBreak(script, (engine, info) =>
  128. {
  129. Assert.Collection(info.CallStack,
  130. frame => Assert.Equal(engine.Realm.GlobalObject.Get("car"), frame.This),
  131. frame => Assert.Equal(engine.Realm.GlobalObject, frame.This)
  132. );
  133. });
  134. }
  135. [Fact]
  136. public void NamesRegularFunction()
  137. {
  138. string script = @"
  139. function regularFunction() { debugger; }
  140. regularFunction();";
  141. TestHelpers.TestAtBreak(script, info =>
  142. {
  143. Assert.Equal("regularFunction", info.CurrentCallFrame.FunctionName);
  144. });
  145. }
  146. [Fact]
  147. public void NamesFunctionExpression()
  148. {
  149. string script = @"
  150. const functionExpression = function() { debugger; }
  151. functionExpression()";
  152. TestHelpers.TestAtBreak(script, info =>
  153. {
  154. Assert.Equal("functionExpression", info.CurrentCallFrame.FunctionName);
  155. });
  156. }
  157. [Fact]
  158. public void NamesNamedFunctionExpression()
  159. {
  160. string script = @"
  161. const functionExpression = function namedFunction() { debugger; }
  162. functionExpression()";
  163. TestHelpers.TestAtBreak(script, info =>
  164. {
  165. Assert.Equal("namedFunction", info.CurrentCallFrame.FunctionName);
  166. });
  167. }
  168. [Fact]
  169. public void NamesArrowFunction()
  170. {
  171. string script = @"
  172. const arrowFunction = () => { debugger; }
  173. arrowFunction()";
  174. TestHelpers.TestAtBreak(script, info =>
  175. {
  176. Assert.Equal("arrowFunction", info.CurrentCallFrame.FunctionName);
  177. });
  178. }
  179. [Fact]
  180. public void NamesNewFunction()
  181. {
  182. string script = @"
  183. const newFunction = new Function('debugger;');
  184. newFunction()";
  185. TestHelpers.TestAtBreak(script, info =>
  186. {
  187. // Ideally, this should be "(anonymous)", but FunctionConstructor sets the "anonymous" name.
  188. Assert.Equal("anonymous", info.CurrentCallFrame.FunctionName);
  189. });
  190. }
  191. [Fact]
  192. public void NamesMemberFunction()
  193. {
  194. string script = @"
  195. const obj = { memberFunction() { debugger; } };
  196. obj.memberFunction()";
  197. TestHelpers.TestAtBreak(script, info =>
  198. {
  199. Assert.Equal("memberFunction", info.CurrentCallFrame.FunctionName);
  200. });
  201. }
  202. [Fact]
  203. public void NamesAnonymousFunction()
  204. {
  205. string script = @"
  206. (function()
  207. {
  208. debugger;
  209. }());";
  210. TestHelpers.TestAtBreak(script, info =>
  211. {
  212. Assert.Equal("(anonymous)", info.CurrentCallFrame.FunctionName);
  213. });
  214. }
  215. [Fact]
  216. public void NamesGetAccessor()
  217. {
  218. string script = @"
  219. const obj = {
  220. get accessor()
  221. {
  222. debugger;
  223. return 'test';
  224. }
  225. };
  226. const x = obj.accessor;";
  227. TestHelpers.TestAtBreak(script, info =>
  228. {
  229. Assert.Equal("get accessor", info.CurrentCallFrame.FunctionName);
  230. });
  231. }
  232. [Fact]
  233. public void NamesSetAccessor()
  234. {
  235. string script = @"
  236. const obj = {
  237. set accessor(value)
  238. {
  239. debugger;
  240. this.value = value;
  241. }
  242. };
  243. obj.accessor = 42;";
  244. TestHelpers.TestAtBreak(script, info =>
  245. {
  246. Assert.Equal("set accessor", info.CurrentCallFrame.FunctionName);
  247. });
  248. }
  249. }