NodeAppender.spec.ts 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510
  1. import * as chai from 'chai';
  2. import * as ESTree from 'estree';
  3. import { TStatement } from '../../../src/types/TStatement';
  4. import { IStackTraceData } from '../../../src/interfaces/stack-trace-analyzer/IStackTraceData';
  5. import { NodeAppender } from '../../../src/NodeAppender';
  6. import { NodeMocks } from '../../mocks/NodeMocks';
  7. import { NodeUtils } from '../../../src/NodeUtils';
  8. import { StackTraceAnalyzer } from '../../../src/stack-trace-analyzer/StackTraceAnalyzer';
  9. const assert: any = chai.assert;
  10. describe('NodeAppender', () => {
  11. describe('appendNode (blockScopeNode: TNodeWithBlockStatement[], nodeBodyStatements: TStatement[]): void', () => {
  12. let blockStatementNode: ESTree.BlockStatement,
  13. expectedBlockStatementNode: ESTree.BlockStatement,
  14. expectedExpressionStatementNode: ESTree.ExpressionStatement,
  15. expressionStatementNode: ESTree.ExpressionStatement;
  16. beforeEach(() => {
  17. expressionStatementNode = NodeMocks.getExpressionStatementNode();
  18. expectedExpressionStatementNode = NodeMocks.getExpressionStatementNode();
  19. blockStatementNode = NodeMocks.getBlockStatementNode();
  20. expectedExpressionStatementNode['parentNode'] = blockStatementNode;
  21. expectedBlockStatementNode = NodeMocks.getBlockStatementNode([
  22. expectedExpressionStatementNode
  23. ]);
  24. NodeAppender.appendNode(
  25. blockStatementNode,
  26. [expressionStatementNode]
  27. );
  28. NodeAppender.appendNode(
  29. blockStatementNode,
  30. <TStatement[]>[{}]
  31. );
  32. });
  33. it('should append given node to a `BlockStatement` node body', () => {
  34. assert.deepEqual(blockStatementNode, expectedBlockStatementNode);
  35. });
  36. it('should does not change `BlockStatement` node body if given node is not a valid Node', () => {
  37. assert.deepEqual(blockStatementNode, expectedBlockStatementNode);
  38. });
  39. });
  40. describe('appendNodeToOptimalBlockScope (blockScopeStackTraceData: IStackTraceData[], blockScopeNode: TNodeWithBlockStatement, nodeBodyStatements: TStatement[], index: number = 0): void', () => {
  41. let astTree: ESTree.Program,
  42. expectedAstTree: ESTree.Program,
  43. node: TStatement[],
  44. stackTraceData: IStackTraceData[];
  45. beforeEach(() => {
  46. node = NodeUtils.convertCodeToStructure(`
  47. var test = 1;
  48. `);
  49. });
  50. it('should append node into first and deepest function call in calls trace - variant #1', () => {
  51. astTree = NodeMocks.getProgramNode(
  52. <ESTree.Statement[]>NodeUtils.convertCodeToStructure(`
  53. function foo () {
  54. }
  55. function bar () {
  56. function inner1 () {
  57. }
  58. function inner2 () {
  59. var inner3 = function () {
  60. }
  61. inner3();
  62. }
  63. inner2();
  64. inner1();
  65. }
  66. function baz () {
  67. }
  68. baz();
  69. foo();
  70. bar();
  71. `)
  72. );
  73. expectedAstTree = NodeMocks.getProgramNode(
  74. <ESTree.Statement[]>NodeUtils.convertCodeToStructure(`
  75. function foo () {
  76. }
  77. function bar () {
  78. function inner1 () {
  79. }
  80. function inner2 () {
  81. var inner3 = function () {
  82. }
  83. inner3();
  84. }
  85. inner2();
  86. inner1();
  87. }
  88. function baz () {
  89. var test = 1;
  90. }
  91. baz();
  92. foo();
  93. bar();
  94. `)
  95. );
  96. stackTraceData = new StackTraceAnalyzer(astTree.body).analyze();
  97. NodeAppender.appendNodeToOptimalBlockScope(stackTraceData, astTree, node);
  98. assert.deepEqual(astTree, expectedAstTree);
  99. });
  100. it('should append node into first and deepest function call in calls trace - variant #2', () => {
  101. astTree = NodeMocks.getProgramNode(
  102. <ESTree.Statement[]>NodeUtils.convertCodeToStructure(`
  103. function foo () {
  104. }
  105. function bar () {
  106. function inner1 () {
  107. }
  108. function inner2 () {
  109. var inner3 = function () {
  110. }
  111. inner3();
  112. }
  113. inner2();
  114. inner1();
  115. }
  116. function baz () {
  117. }
  118. bar();
  119. baz();
  120. foo();
  121. `)
  122. );
  123. expectedAstTree = NodeMocks.getProgramNode(
  124. <ESTree.Statement[]>NodeUtils.convertCodeToStructure(`
  125. function foo () {
  126. }
  127. function bar () {
  128. function inner1 () {
  129. }
  130. function inner2 () {
  131. var inner3 = function () {
  132. var test = 1;
  133. }
  134. inner3();
  135. }
  136. inner2();
  137. inner1();
  138. }
  139. function baz () {
  140. }
  141. bar();
  142. baz();
  143. foo();
  144. `)
  145. );
  146. stackTraceData = new StackTraceAnalyzer(astTree.body).analyze();
  147. NodeAppender.appendNodeToOptimalBlockScope(stackTraceData, astTree, node);
  148. assert.deepEqual(astTree, expectedAstTree);
  149. });
  150. describe('append by specific index', () => {
  151. let astTree: ESTree.Program;
  152. beforeEach(() => {
  153. astTree = NodeMocks.getProgramNode(
  154. <ESTree.Statement[]>NodeUtils.convertCodeToStructure(`
  155. function foo () {
  156. }
  157. function bar () {
  158. function inner1 () {
  159. }
  160. function inner2 () {
  161. var inner3 = function () {
  162. }
  163. inner3();
  164. }
  165. inner2();
  166. inner1();
  167. }
  168. function baz () {
  169. }
  170. bar();
  171. baz();
  172. foo();
  173. `)
  174. );
  175. });
  176. it('should append node into deepest function call by specified index in calls trace - variant #1', () => {
  177. expectedAstTree = NodeMocks.getProgramNode(
  178. <ESTree.Statement[]>NodeUtils.convertCodeToStructure(`
  179. function foo () {
  180. var test = 1;
  181. }
  182. function bar () {
  183. function inner1 () {
  184. }
  185. function inner2 () {
  186. var inner3 = function () {
  187. }
  188. inner3();
  189. }
  190. inner2();
  191. inner1();
  192. }
  193. function baz () {
  194. }
  195. bar();
  196. baz();
  197. foo();
  198. `)
  199. );
  200. stackTraceData = new StackTraceAnalyzer(astTree.body).analyze();
  201. NodeAppender.appendNodeToOptimalBlockScope(stackTraceData, astTree, node, 2);
  202. assert.deepEqual(astTree, expectedAstTree);
  203. });
  204. it('should append node into deepest function call by specified index in calls trace - variant #2', () => {
  205. expectedAstTree = NodeMocks.getProgramNode(
  206. <ESTree.Statement[]>NodeUtils.convertCodeToStructure(`
  207. function foo () {
  208. }
  209. function bar () {
  210. function inner1 () {
  211. }
  212. function inner2 () {
  213. var inner3 = function () {
  214. }
  215. inner3();
  216. }
  217. inner2();
  218. inner1();
  219. }
  220. function baz () {
  221. var test = 1;
  222. }
  223. bar();
  224. baz();
  225. foo();
  226. `)
  227. );
  228. stackTraceData = new StackTraceAnalyzer(astTree.body).analyze();
  229. NodeAppender.appendNodeToOptimalBlockScope(stackTraceData, astTree, node, 1);
  230. assert.deepEqual(astTree, expectedAstTree);
  231. });
  232. it('should append node into deepest function call by specified index in calls trace - variant #3', () => {
  233. astTree = NodeMocks.getProgramNode(
  234. <ESTree.Statement[]>NodeUtils.convertCodeToStructure(`
  235. var start = new Date();
  236. var log = console.log;
  237. console.log = function () {};
  238. (function () {
  239. function bar () {
  240. function inner1 () {
  241. }
  242. function inner2 () {
  243. var inner3 = function () {
  244. }
  245. inner3();
  246. }
  247. inner2();
  248. inner1();
  249. }
  250. bar();
  251. })();
  252. console.log = log;
  253. console.log(new Date() - start);
  254. `)
  255. );
  256. expectedAstTree = NodeMocks.getProgramNode(
  257. <ESTree.Statement[]>NodeUtils.convertCodeToStructure(`
  258. var start = new Date();
  259. var log = console.log;
  260. console.log = function () {};
  261. (function () {
  262. function bar () {
  263. function inner1 () {
  264. }
  265. function inner2 () {
  266. var inner3 = function () {
  267. var test = 1;
  268. }
  269. inner3();
  270. }
  271. inner2();
  272. inner1();
  273. }
  274. bar();
  275. })();
  276. console.log = log;
  277. console.log(new Date() - start);
  278. `)
  279. );
  280. stackTraceData = new StackTraceAnalyzer(astTree.body).analyze();
  281. NodeAppender.appendNodeToOptimalBlockScope(
  282. stackTraceData,
  283. astTree,
  284. node,
  285. NodeAppender.getRandomStackTraceIndex(stackTraceData.length)
  286. );
  287. assert.deepEqual(astTree, expectedAstTree);
  288. });
  289. });
  290. });
  291. describe('getRandomStackTraceIndex (stackTraceRootLength: number): number', () => {
  292. it('should returns random index between 0 and stack trace data root length', () => {
  293. let index: number;
  294. for (let i: number = 0; i < 100; i++) {
  295. index = NodeAppender.getRandomStackTraceIndex(100);
  296. assert.isAtLeast(index, 0);
  297. assert.isAtMost(index, 100);
  298. }
  299. });
  300. });
  301. describe('insertNodeAtIndex (blockScopeNode: TNodeWithBlockStatement[], nodeBodyStatements: TStatement[], index: number): void', () => {
  302. let blockStatementNode: ESTree.BlockStatement,
  303. expectedBlockStatementNode: ESTree.BlockStatement,
  304. expressionStatementNode1: ESTree.ExpressionStatement,
  305. expressionStatementNode2: ESTree.ExpressionStatement,
  306. expressionStatementNode3: ESTree.ExpressionStatement,
  307. expressionStatementNode4: ESTree.ExpressionStatement;
  308. beforeEach(() => {
  309. expressionStatementNode1 = NodeMocks.getExpressionStatementNode(NodeMocks.getLiteralNode(1));
  310. expressionStatementNode2 = NodeMocks.getExpressionStatementNode(NodeMocks.getLiteralNode(2));
  311. expressionStatementNode3 = NodeMocks.getExpressionStatementNode(NodeMocks.getLiteralNode(3));
  312. expressionStatementNode4 = NodeMocks.getExpressionStatementNode(NodeMocks.getLiteralNode(2));
  313. blockStatementNode = NodeMocks.getBlockStatementNode([
  314. expressionStatementNode1,
  315. expressionStatementNode3
  316. ]);
  317. expressionStatementNode1['parentNode'] = blockStatementNode;
  318. expressionStatementNode2['parentNode'] = blockStatementNode;
  319. expressionStatementNode3['parentNode'] = blockStatementNode;
  320. expectedBlockStatementNode = NodeMocks.getBlockStatementNode([
  321. expressionStatementNode1,
  322. expressionStatementNode2,
  323. expressionStatementNode3
  324. ]);
  325. NodeAppender.insertNodeAtIndex(
  326. blockStatementNode,
  327. [expressionStatementNode4],
  328. 1
  329. );
  330. NodeAppender.insertNodeAtIndex(
  331. blockStatementNode,
  332. <TStatement[]>[{}],
  333. 1
  334. );
  335. });
  336. it('should insert given node in `BlockStatement` node body at index', () => {
  337. assert.deepEqual(blockStatementNode, expectedBlockStatementNode);
  338. });
  339. it('should does not change `BlockStatement` node body if given node is not a valid Node', () => {
  340. assert.deepEqual(blockStatementNode, expectedBlockStatementNode);
  341. });
  342. });
  343. describe('prependNode (blockScopeNode: TNodeWithBlockStatement[], nodeBodyStatements: TStatement[]): void', () => {
  344. let blockStatementNode: ESTree.BlockStatement,
  345. expectedBlockStatementNode: ESTree.BlockStatement,
  346. expressionStatementNode1: ESTree.ExpressionStatement,
  347. expressionStatementNode2: ESTree.ExpressionStatement,
  348. expressionStatementNode3: ESTree.ExpressionStatement;
  349. beforeEach(() => {
  350. expressionStatementNode1 = NodeMocks.getExpressionStatementNode(NodeMocks.getLiteralNode(1));
  351. expressionStatementNode2 = NodeMocks.getExpressionStatementNode(NodeMocks.getLiteralNode(2));
  352. expressionStatementNode3 = NodeMocks.getExpressionStatementNode(NodeMocks.getLiteralNode(2));
  353. blockStatementNode = NodeMocks.getBlockStatementNode([
  354. expressionStatementNode1
  355. ]);
  356. expressionStatementNode1['parentNode'] = blockStatementNode;
  357. expressionStatementNode2['parentNode'] = blockStatementNode;
  358. expectedBlockStatementNode = NodeMocks.getBlockStatementNode([
  359. expressionStatementNode2,
  360. expressionStatementNode1
  361. ]);
  362. NodeAppender.prependNode(
  363. blockStatementNode,
  364. [Object.assign({}, expressionStatementNode3)]
  365. );
  366. NodeAppender.prependNode(
  367. blockStatementNode,
  368. <TStatement[]>[{}]
  369. )
  370. });
  371. it('should prepend given node to a `BlockStatement` node body', () => {
  372. assert.deepEqual(blockStatementNode, expectedBlockStatementNode);
  373. });
  374. it('should does not change `BlockStatement` node body if given node is not a valid Node', () => {
  375. assert.deepEqual(blockStatementNode, expectedBlockStatementNode);
  376. });
  377. });
  378. });