CallStackTests.cs 7.8 KB

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