import * as ESTree from 'estree'; import { assert } from 'chai'; import { Nodes } from '../../../../src/node/Nodes'; import { NodeGuards } from '../../../../src/node/NodeGuards'; import { NodeUtils } from '../../../../src/node/NodeUtils'; describe('NodeGuards', () => { describe('isNodeHasBlockScope (node: ESTree.Node): node is TNodeWithBlockScope', () => { describe('truthful checks', () => { describe('Variant #1: block statement of function declaration', () => { const expectedResult: boolean = true; const node: ESTree.Node = Nodes.getBlockStatementNode(); const parentNode: ESTree.FunctionDeclaration = Nodes.getFunctionDeclarationNode( 'foo', [], node ); let result: boolean; before(() => { NodeUtils.parentize(parentNode); result = NodeGuards.isNodeHasBlockScope(node, parentNode); }); it('should check if node has block scope', () => { assert.equal(result, expectedResult); }); }); describe('Variant #2: block statement of function expression', () => { const expectedResult: boolean = true; const node: ESTree.Node = Nodes.getBlockStatementNode(); const parentNode: ESTree.FunctionExpression = Nodes.getFunctionExpressionNode( [], node ); let result: boolean; before(() => { NodeUtils.parentize(parentNode); result = NodeGuards.isNodeHasBlockScope(node, parentNode); }); it('should check if node has block scope', () => { assert.equal(result, expectedResult); }); }); }); describe('false checks', () => { describe('Variant #1: switch-case node', () => { const expectedResult: boolean = false; const node: ESTree.Node = Nodes.getSwitchCaseNode( Nodes.getLiteralNode(1), [] ); const parentNode: ESTree.FunctionDeclaration = Nodes.getFunctionDeclarationNode( 'foo', [], Nodes.getBlockStatementNode([ Nodes.getSwitchStatementNode( Nodes.getMemberExpressionNode( Nodes.getIdentifierNode('bar'), Nodes.getUpdateExpressionNode( '++', Nodes.getIdentifierNode('baz') ), true ), [node] ) ]) ); let result: boolean; before(() => { NodeUtils.parentize(parentNode); result = NodeGuards.isNodeHasBlockScope(node, parentNode); }); it('should check if node has block scope', () => { assert.equal(result, expectedResult); }); }); describe('Variant #2: literal node', () => { const expectedResult: boolean = false; const node: ESTree.Node = Nodes.getLiteralNode(1); const parentNode: ESTree.FunctionDeclaration = Nodes.getFunctionDeclarationNode( 'foo', [], Nodes.getBlockStatementNode([ Nodes.getExpressionStatementNode( Nodes.getCallExpressionNode( Nodes.getIdentifierNode('bar'), [node] ) ) ]) ); let result: boolean; before(() => { NodeUtils.parentize(parentNode); result = NodeGuards.isNodeHasBlockScope(node, parentNode); }); it('should check if node has block scope', () => { assert.equal(result, expectedResult); }); }); describe('Variant #3: block statement of if statement', () => { const expectedResult: boolean = false; const node: ESTree.Node = Nodes.getBlockStatementNode(); const parentNode: ESTree.IfStatement = Nodes.getIfStatementNode( Nodes.getIdentifierNode('foo'), node ); let result: boolean; before(() => { NodeUtils.parentize(parentNode); result = NodeGuards.isNodeHasBlockScope(node, parentNode); }); it('should check if node has block scope', () => { assert.equal(result, expectedResult); }); }); }); }); describe('isNodeHasScope (node: ESTree.Node): node is TNodeWithScope', () => { describe('truthful checks', () => { describe('Variant #1: program node', () => { const expectedResult: boolean = true; const node: ESTree.Node = Nodes.getProgramNode(); let result: boolean; before(() => { result = NodeGuards.isNodeHasScope(node); }); it('should check if node has scope', () => { assert.equal(result, expectedResult); }); }); describe('Variant #2: block statement node', () => { const expectedResult: boolean = true; const node: ESTree.Node = Nodes.getBlockStatementNode(); let result: boolean; before(() => { result = NodeGuards.isNodeHasScope(node); }); it('should check if node has scope', () => { assert.equal(result, expectedResult); }); }); describe('Variant #3: switch case node', () => { const expectedResult: boolean = true; const node: ESTree.Node = Nodes.getSwitchCaseNode( Nodes.getLiteralNode(1), [] ); let result: boolean; before(() => { result = NodeGuards.isNodeHasScope(node); }); it('should check if node has scope', () => { assert.equal(result, expectedResult); }); }); }); describe('false checks', () => { describe('Variant #1: literal node', () => { const expectedResult: boolean = false; const node: ESTree.Node = Nodes.getLiteralNode(1); let result: boolean; before(() => { result = NodeGuards.isNodeHasScope(node); }); it('should check if node has scope', () => { assert.equal(result, expectedResult); }); }); describe('Variant #2: identifier node', () => { const expectedResult: boolean = false; const node: ESTree.Node = Nodes.getIdentifierNode('foo'); let result: boolean; before(() => { result = NodeGuards.isNodeHasScope(node); }); it('should check if node has scope', () => { assert.equal(result, expectedResult); }); }); describe('Variant #3: if-statement node', () => { const expectedResult: boolean = false; const node: ESTree.Node = Nodes.getIfStatementNode( Nodes.getIdentifierNode('foo'), Nodes.getBlockStatementNode() ); let result: boolean; before(() => { result = NodeGuards.isNodeHasScope(node); }); it('should check if node has scope', () => { assert.equal(result, expectedResult); }); }); describe('Variant #4: switch-statement node', () => { const expectedResult: boolean = false; const node: ESTree.Node = Nodes.getSwitchStatementNode( Nodes.getIdentifierNode('foo'), [] ); let result: boolean; before(() => { result = NodeGuards.isNodeHasScope(node); }); it('should check if node has scope', () => { assert.equal(result, expectedResult); }); }); }); }); describe('isReplaceableIdentifierNode (node: ESTree.Node, parentNode: ESTree.Node): node is ESTree.Identifier', () => { describe('truthful checks', () => { describe('Variant #1: parent node is function declaration node', () => { const expectedResult: boolean = true; const identifier: ESTree.Identifier = Nodes.getIdentifierNode('foo'); const parentNode: ESTree.Node = Nodes.getFunctionDeclarationNode( 'bar', [identifier], Nodes.getBlockStatementNode() ); let result: boolean; before(() => { NodeUtils.parentize(parentNode); result = NodeGuards.isReplaceableIdentifierNode(identifier, parentNode); }); it('should check if input identifier can be replaced by obfuscated one', () => { assert.equal(result, expectedResult); }); }); describe('Variant #2: parent node is computed property node', () => { const expectedResult: boolean = true; const identifier: ESTree.Identifier = Nodes.getIdentifierNode('foo'); const parentNode: ESTree.Node = Nodes.getPropertyNode( identifier, Nodes.getLiteralNode('bar'), true ); let result: boolean; before(() => { NodeUtils.parentize(parentNode); result = NodeGuards.isReplaceableIdentifierNode(identifier, parentNode); }); it('should check if input identifier can be replaced by obfuscated one', () => { assert.equal(result, expectedResult); }); }); describe('Variant #4: parent node is computed member expression node', () => { const expectedResult: boolean = true; const identifier: ESTree.Identifier = Nodes.getIdentifierNode('foo'); const parentNode: ESTree.Node = Nodes.getMemberExpressionNode( Nodes.getIdentifierNode('bar'), identifier, true ); let result: boolean; before(() => { NodeUtils.parentize(parentNode); result = NodeGuards.isReplaceableIdentifierNode(identifier, parentNode); }); it('should check if input identifier can be replaced by obfuscated one', () => { assert.equal(result, expectedResult); }); }); describe('Variant #4: parent node is computed method definition node', () => { const expectedResult: boolean = true; const identifier: ESTree.Identifier = Nodes.getIdentifierNode('foo'); const parentNode: ESTree.Node = Nodes.getMethodDefinitionNode( identifier, Nodes.getFunctionExpressionNode([], Nodes.getBlockStatementNode()), 'method', true ); let result: boolean; before(() => { NodeUtils.parentize(parentNode); result = NodeGuards.isReplaceableIdentifierNode(identifier, parentNode); }); it('should check if input identifier can be replaced by obfuscated one', () => { assert.equal(result, expectedResult); }); }); }); describe('false checks', () => { describe('Variant #1: node isn\'t an identifier', () => { const expectedResult: boolean = false; const literal: ESTree.Literal = Nodes.getLiteralNode(1); const parentNode: ESTree.Node = Nodes.getExpressionStatementNode( Nodes.getCallExpressionNode( Nodes.getIdentifierNode('foo'), [literal] ) ); let result: boolean; before(() => { NodeUtils.parentize(parentNode); result = NodeGuards.isReplaceableIdentifierNode(literal, parentNode); }); it('should check if input identifier can be replaced by obfuscated one', () => { assert.equal(result, expectedResult); }); }); describe('Variant #2: parent node isn\'t computed property node', () => { const expectedResult: boolean = false; const identifier: ESTree.Identifier = Nodes.getIdentifierNode('foo'); const parentNode: ESTree.Node = Nodes.getPropertyNode( identifier, Nodes.getLiteralNode('bar'), false ); let result: boolean; before(() => { NodeUtils.parentize(parentNode); result = NodeGuards.isReplaceableIdentifierNode(identifier, parentNode); }); it('should check if input identifier can be replaced by obfuscated one', () => { assert.equal(result, expectedResult); }); }); describe('Variant #3: parent node isn\'t computed member expression node', () => { const expectedResult: boolean = false; const identifier: ESTree.Identifier = Nodes.getIdentifierNode('foo'); const parentNode: ESTree.Node = Nodes.getMemberExpressionNode( Nodes.getIdentifierNode('bar'), identifier, false ); let result: boolean; before(() => { NodeUtils.parentize(parentNode); result = NodeGuards.isReplaceableIdentifierNode(identifier, parentNode); }); it('should check if input identifier can be replaced by obfuscated one', () => { assert.equal(result, expectedResult); }); }); describe('Variant #4: parent node isn\'t computed method definition node', () => { const expectedResult: boolean = false; const identifier: ESTree.Identifier = Nodes.getIdentifierNode('foo'); const parentNode: ESTree.Node = Nodes.getMethodDefinitionNode( identifier, Nodes.getFunctionExpressionNode([], Nodes.getBlockStatementNode()), 'method', false ); let result: boolean; before(() => { NodeUtils.parentize(parentNode); result = NodeGuards.isReplaceableIdentifierNode(identifier, parentNode); }); it('should check if input identifier can be replaced by obfuscated one', () => { assert.equal(result, expectedResult); }); }); }); }); });