CallStackTests.cs 7.8 KB

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