NodeGuards.spec.ts 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453
  1. import * as ESTree from 'estree';
  2. import { assert } from 'chai';
  3. import { Nodes } from '../../../../src/node/Nodes';
  4. import { NodeGuards } from '../../../../src/node/NodeGuards';
  5. import { NodeUtils } from '../../../../src/node/NodeUtils';
  6. describe('NodeGuards', () => {
  7. describe('isNodeHasBlockScope (node: ESTree.Node): node is TNodeWithBlockScope', () => {
  8. describe('truthful checks', () => {
  9. describe('variant #1: block statement of function declaration', () => {
  10. const expectedResult: boolean = true;
  11. const node: ESTree.Node = Nodes.getBlockStatementNode();
  12. const parentNode: ESTree.FunctionDeclaration = Nodes.getFunctionDeclarationNode(
  13. 'foo',
  14. [],
  15. node
  16. );
  17. let result: boolean;
  18. before(() => {
  19. NodeUtils.parentize(parentNode);
  20. result = NodeGuards.isNodeHasBlockScope(node);
  21. });
  22. it('should check if node has block scope', () => {
  23. assert.equal(result, expectedResult);
  24. });
  25. });
  26. describe('variant #2: block statement of function expression', () => {
  27. const expectedResult: boolean = true;
  28. const node: ESTree.Node = Nodes.getBlockStatementNode();
  29. const parentNode: ESTree.FunctionExpression = Nodes.getFunctionExpressionNode(
  30. [],
  31. node
  32. );
  33. let result: boolean;
  34. before(() => {
  35. NodeUtils.parentize(parentNode);
  36. result = NodeGuards.isNodeHasBlockScope(node);
  37. });
  38. it('should check if node has block scope', () => {
  39. assert.equal(result, expectedResult);
  40. });
  41. });
  42. });
  43. describe('false checks', () => {
  44. describe('variant #1: switch-case node', () => {
  45. const expectedResult: boolean = false;
  46. const node: ESTree.Node = Nodes.getSwitchCaseNode(
  47. Nodes.getLiteralNode(1),
  48. []
  49. );
  50. const parentNode: ESTree.FunctionDeclaration = Nodes.getFunctionDeclarationNode(
  51. 'foo',
  52. [],
  53. Nodes.getBlockStatementNode([
  54. Nodes.getSwitchStatementNode(
  55. Nodes.getMemberExpressionNode(
  56. Nodes.getIdentifierNode('bar'),
  57. Nodes.getUpdateExpressionNode(
  58. '++',
  59. Nodes.getIdentifierNode('baz')
  60. ),
  61. true
  62. ),
  63. [node]
  64. )
  65. ])
  66. );
  67. let result: boolean;
  68. before(() => {
  69. NodeUtils.parentize(parentNode);
  70. result = NodeGuards.isNodeHasBlockScope(node);
  71. });
  72. it('should check if node has block scope', () => {
  73. assert.equal(result, expectedResult);
  74. });
  75. });
  76. describe('variant #2: literal node', () => {
  77. const expectedResult: boolean = false;
  78. const node: ESTree.Node = Nodes.getLiteralNode(1);
  79. const parentNode: ESTree.FunctionDeclaration = Nodes.getFunctionDeclarationNode(
  80. 'foo',
  81. [],
  82. Nodes.getBlockStatementNode([
  83. Nodes.getExpressionStatementNode(
  84. Nodes.getCallExpressionNode(
  85. Nodes.getIdentifierNode('bar'),
  86. [node]
  87. )
  88. )
  89. ])
  90. );
  91. let result: boolean;
  92. before(() => {
  93. NodeUtils.parentize(parentNode);
  94. result = NodeGuards.isNodeHasBlockScope(node);
  95. });
  96. it('should check if node has block scope', () => {
  97. assert.equal(result, expectedResult);
  98. });
  99. });
  100. describe('variant #3: block statement of if statement', () => {
  101. const expectedResult: boolean = false;
  102. const node: ESTree.Node = Nodes.getBlockStatementNode();
  103. const parentNode: ESTree.IfStatement = Nodes.getIfStatementNode(
  104. Nodes.getIdentifierNode('foo'),
  105. node
  106. );
  107. let result: boolean;
  108. before(() => {
  109. NodeUtils.parentize(parentNode);
  110. result = NodeGuards.isNodeHasBlockScope(node);
  111. });
  112. it('should check if node has block scope', () => {
  113. assert.equal(result, expectedResult);
  114. });
  115. });
  116. });
  117. describe('exception checks', () => {
  118. describe('no `parentNode` property', () => {
  119. const node: ESTree.Node = Nodes.getBlockStatementNode();
  120. let testFunc: Function;
  121. before(() => {
  122. testFunc = () => NodeGuards.isNodeHasBlockScope(node);
  123. });
  124. it('should check if node has block scope', () => {
  125. assert.throw(testFunc, Error);
  126. });
  127. });
  128. });
  129. });
  130. describe('isNodeHasScope (node: ESTree.Node): node is TNodeWithScope', () => {
  131. describe('truthful checks', () => {
  132. describe('variant #1: program node', () => {
  133. const expectedResult: boolean = true;
  134. const node: ESTree.Node = Nodes.getProgramNode();
  135. let result: boolean;
  136. before(() => {
  137. result = NodeGuards.isNodeHasScope(node);
  138. });
  139. it('should check if node has scope', () => {
  140. assert.equal(result, expectedResult);
  141. });
  142. });
  143. describe('variant #2: block statement node', () => {
  144. const expectedResult: boolean = true;
  145. const node: ESTree.Node = Nodes.getBlockStatementNode();
  146. let result: boolean;
  147. before(() => {
  148. result = NodeGuards.isNodeHasScope(node);
  149. });
  150. it('should check if node has scope', () => {
  151. assert.equal(result, expectedResult);
  152. });
  153. });
  154. describe('variant #3: switch case node', () => {
  155. const expectedResult: boolean = true;
  156. const node: ESTree.Node = Nodes.getSwitchCaseNode(
  157. Nodes.getLiteralNode(1),
  158. []
  159. );
  160. let result: boolean;
  161. before(() => {
  162. result = NodeGuards.isNodeHasScope(node);
  163. });
  164. it('should check if node has scope', () => {
  165. assert.equal(result, expectedResult);
  166. });
  167. });
  168. });
  169. describe('false checks', () => {
  170. describe('variant #1: literal node', () => {
  171. const expectedResult: boolean = false;
  172. const node: ESTree.Node = Nodes.getLiteralNode(1);
  173. let result: boolean;
  174. before(() => {
  175. result = NodeGuards.isNodeHasScope(node);
  176. });
  177. it('should check if node has scope', () => {
  178. assert.equal(result, expectedResult);
  179. });
  180. });
  181. describe('variant #2: identifier node', () => {
  182. const expectedResult: boolean = false;
  183. const node: ESTree.Node = Nodes.getIdentifierNode('foo');
  184. let result: boolean;
  185. before(() => {
  186. result = NodeGuards.isNodeHasScope(node);
  187. });
  188. it('should check if node has scope', () => {
  189. assert.equal(result, expectedResult);
  190. });
  191. });
  192. describe('variant #3: if-statement node', () => {
  193. const expectedResult: boolean = false;
  194. const node: ESTree.Node = Nodes.getIfStatementNode(
  195. Nodes.getIdentifierNode('foo'),
  196. Nodes.getBlockStatementNode()
  197. );
  198. let result: boolean;
  199. before(() => {
  200. result = NodeGuards.isNodeHasScope(node);
  201. });
  202. it('should check if node has scope', () => {
  203. assert.equal(result, expectedResult);
  204. });
  205. });
  206. describe('variant #4: switch-statement node', () => {
  207. const expectedResult: boolean = false;
  208. const node: ESTree.Node = Nodes.getSwitchStatementNode(
  209. Nodes.getIdentifierNode('foo'),
  210. []
  211. );
  212. let result: boolean;
  213. before(() => {
  214. result = NodeGuards.isNodeHasScope(node);
  215. });
  216. it('should check if node has scope', () => {
  217. assert.equal(result, expectedResult);
  218. });
  219. });
  220. });
  221. });
  222. describe('isReplaceableIdentifierNode (node: ESTree.Node, parentNode: ESTree.Node): node is ESTree.Identifier', () => {
  223. describe('truthful checks', () => {
  224. describe('variant #1: parent node is function declaration node', () => {
  225. const expectedResult: boolean = true;
  226. const identifier: ESTree.Identifier = Nodes.getIdentifierNode('foo');
  227. const parentNode: ESTree.Node = Nodes.getFunctionDeclarationNode(
  228. 'bar',
  229. [identifier],
  230. Nodes.getBlockStatementNode()
  231. );
  232. let result: boolean;
  233. before(() => {
  234. NodeUtils.parentize(parentNode);
  235. result = NodeGuards.isReplaceableIdentifierNode(identifier, parentNode);
  236. });
  237. it('should check if input identifier can be replaced by obfuscated one', () => {
  238. assert.equal(result, expectedResult);
  239. });
  240. });
  241. describe('variant #2: parent node is computed property node', () => {
  242. const expectedResult: boolean = true;
  243. const identifier: ESTree.Identifier = Nodes.getIdentifierNode('foo');
  244. const parentNode: ESTree.Node = Nodes.getPropertyNode(
  245. identifier,
  246. Nodes.getLiteralNode('bar'),
  247. true
  248. );
  249. let result: boolean;
  250. before(() => {
  251. NodeUtils.parentize(parentNode);
  252. result = NodeGuards.isReplaceableIdentifierNode(identifier, parentNode);
  253. });
  254. it('should check if input identifier can be replaced by obfuscated one', () => {
  255. assert.equal(result, expectedResult);
  256. });
  257. });
  258. describe('variant #4: parent node is computed member expression node', () => {
  259. const expectedResult: boolean = true;
  260. const identifier: ESTree.Identifier = Nodes.getIdentifierNode('foo');
  261. const parentNode: ESTree.Node = Nodes.getMemberExpressionNode(
  262. Nodes.getIdentifierNode('bar'),
  263. identifier,
  264. true
  265. );
  266. let result: boolean;
  267. before(() => {
  268. NodeUtils.parentize(parentNode);
  269. result = NodeGuards.isReplaceableIdentifierNode(identifier, parentNode);
  270. });
  271. it('should check if input identifier can be replaced by obfuscated one', () => {
  272. assert.equal(result, expectedResult);
  273. });
  274. });
  275. describe('variant #4: parent node is computed method definition node', () => {
  276. const expectedResult: boolean = true;
  277. const identifier: ESTree.Identifier = Nodes.getIdentifierNode('foo');
  278. const parentNode: ESTree.Node = Nodes.getMethodDefinitionNode(
  279. identifier,
  280. Nodes.getFunctionExpressionNode([], Nodes.getBlockStatementNode()),
  281. 'method',
  282. true
  283. );
  284. let result: boolean;
  285. before(() => {
  286. NodeUtils.parentize(parentNode);
  287. result = NodeGuards.isReplaceableIdentifierNode(identifier, parentNode);
  288. });
  289. it('should check if input identifier can be replaced by obfuscated one', () => {
  290. assert.equal(result, expectedResult);
  291. });
  292. });
  293. });
  294. describe('false checks', () => {
  295. describe('variant #1: node isn\'t an identifier', () => {
  296. const expectedResult: boolean = false;
  297. const literal: ESTree.Literal = Nodes.getLiteralNode(1);
  298. const parentNode: ESTree.Node = Nodes.getExpressionStatementNode(
  299. Nodes.getCallExpressionNode(
  300. Nodes.getIdentifierNode('foo'),
  301. [literal]
  302. )
  303. );
  304. let result: boolean;
  305. before(() => {
  306. NodeUtils.parentize(parentNode);
  307. result = NodeGuards.isReplaceableIdentifierNode(literal, parentNode);
  308. });
  309. it('should check if input identifier can be replaced by obfuscated one', () => {
  310. assert.equal(result, expectedResult);
  311. });
  312. });
  313. describe('variant #2: parent node isn\'t computed property node', () => {
  314. const expectedResult: boolean = false;
  315. const identifier: ESTree.Identifier = Nodes.getIdentifierNode('foo');
  316. const parentNode: ESTree.Node = Nodes.getPropertyNode(
  317. identifier,
  318. Nodes.getLiteralNode('bar'),
  319. false
  320. );
  321. let result: boolean;
  322. before(() => {
  323. NodeUtils.parentize(parentNode);
  324. result = NodeGuards.isReplaceableIdentifierNode(identifier, parentNode);
  325. });
  326. it('should check if input identifier can be replaced by obfuscated one', () => {
  327. assert.equal(result, expectedResult);
  328. });
  329. });
  330. describe('variant #3: parent node isn\'t computed member expression node', () => {
  331. const expectedResult: boolean = false;
  332. const identifier: ESTree.Identifier = Nodes.getIdentifierNode('foo');
  333. const parentNode: ESTree.Node = Nodes.getMemberExpressionNode(
  334. Nodes.getIdentifierNode('bar'),
  335. identifier,
  336. false
  337. );
  338. let result: boolean;
  339. before(() => {
  340. NodeUtils.parentize(parentNode);
  341. result = NodeGuards.isReplaceableIdentifierNode(identifier, parentNode);
  342. });
  343. it('should check if input identifier can be replaced by obfuscated one', () => {
  344. assert.equal(result, expectedResult);
  345. });
  346. });
  347. describe('variant #4: parent node isn\'t computed method definition node', () => {
  348. const expectedResult: boolean = false;
  349. const identifier: ESTree.Identifier = Nodes.getIdentifierNode('foo');
  350. const parentNode: ESTree.Node = Nodes.getMethodDefinitionNode(
  351. identifier,
  352. Nodes.getFunctionExpressionNode([], Nodes.getBlockStatementNode()),
  353. 'method',
  354. false
  355. );
  356. let result: boolean;
  357. before(() => {
  358. NodeUtils.parentize(parentNode);
  359. result = NodeGuards.isReplaceableIdentifierNode(identifier, parentNode);
  360. });
  361. it('should check if input identifier can be replaced by obfuscated one', () => {
  362. assert.equal(result, expectedResult);
  363. });
  364. });
  365. });
  366. });
  367. });