@Test public void test_lines_of_code_number_on_tree() throws Exception { CompilationUnitTree cut = parse("metrics/lines_of_code.php"); Optional<ClassDeclarationTree> firstClassTree = cut.script().statements().stream() .filter(statement -> statement.is(Tree.Kind.CLASS_DECLARATION)) .map(ClassDeclarationTree.class::cast) .findFirst(); assertThat(firstClassTree).isPresent(); assertThat(LineVisitor.linesOfCode(firstClassTree.get())).isEqualTo(4); }
@Test public void without_statement() throws Exception { CompilationUnitTree tree = parse("<?php", PHPLexicalGrammar.COMPILATION_UNIT); assertThat(tree.is(Kind.COMPILATION_UNIT)).isTrue(); assertThat(tree.script().fileOpeningTagToken().text()).isEqualTo("<?php"); assertThat(tree.script().statements()).isEmpty(); }
@Test public void test() throws Exception { CompilationUnitTree tree = parse("<?php $a;", PHPLexicalGrammar.COMPILATION_UNIT); assertThat(tree.is(Kind.COMPILATION_UNIT)).isTrue(); assertThat(tree.script().fileOpeningTagToken().text()).isEqualTo("<?php"); assertThat(tree.script().statements()).hasSize(1); assertThat(tree.eofToken().line()).isEqualTo(1); }
@Test public void test_isDescendant() { Tree tree = PHPParserBuilder.createParser().parse("<?= for(;;) {} ?>"); StatementTree statementTree = ((CompilationUnitTree) tree).script().statements().get(0); assertThat(isDescendant(statementTree, tree)).isTrue(); assertThat(isDescendant(tree, statementTree)).isFalse(); assertThat(isDescendant(tree, tree)).isTrue(); assertThat(isDescendant(statementTree, statementTree)).isTrue(); }
@Test public void without_php() throws Exception { CompilationUnitTree tree = parse("hello world\n", PHPLexicalGrammar.COMPILATION_UNIT); assertThat(tree.is(Kind.COMPILATION_UNIT)).isTrue(); assertThat(tree.script().fileOpeningTagToken().text()).isEqualTo("hello world\n"); assertThat(tree.eofToken().line()).isEqualTo(2); }
@Test public void empty() throws Exception { CompilationUnitTree tree = parse("", PHPLexicalGrammar.COMPILATION_UNIT); assertThat(tree.is(Kind.COMPILATION_UNIT)).isTrue(); assertThat(tree.script()).isNull(); assertThat(tree.eofToken().line()).isEqualTo(1); }
@Test public void retrieve_symbol_by_tree() { ExpressionTree dollarAUsage = ((AssignmentExpressionTree) ((ExpressionStatementTree) ((FunctionDeclarationTree) cut.script().statements().get(5)).body().statements().get(3)).expression()).variable(); Symbol symbol = SYMBOL_MODEL.getSymbol(dollarAUsage); assertThat(symbol).isNotNull(); assertThat(symbol.name()).isEqualTo("$a"); }
@Test public void test_buildCFG() { CompilationUnitTree tree = parse("<?php " + "function foo() {" + " $expr = function() {echo 'Hello';};" + "}" + "echo 'Hello';", PHPLexicalGrammar.COMPILATION_UNIT); FunctionDeclarationTree func = (FunctionDeclarationTree) tree.script().statements().get(0); ExpressionStatementTree expr = (ExpressionStatementTree) func.body().statements().get(0); ControlFlowGraph cfg = ControlFlowGraph.build(func, checkContext); assertThat(cfg.start().elements().get(0)).isEqualTo(expr); FunctionExpressionTree funcExpr = ((FunctionExpressionTree) ((AssignmentExpressionTree) expr.expression()).value()); StatementTree echo = funcExpr.body().statements().get(0); cfg = ControlFlowGraph.build(funcExpr, checkContext); assertThat(cfg.start().elements().get(0)).isEqualTo(echo); StatementTree scriptEcho = tree.script().statements().get(1); cfg = ControlFlowGraph.build(tree.script(), checkContext); assertThat(cfg.start().elements().get(0)).isEqualTo(func); assertThat(cfg.start().elements().get(1)).isEqualTo(scriptEcho); }
@Test public void test_buildCFG_with_method() { CompilationUnitTree tree = parse("<?php " + "class A {" + " function foo() {" + " echo 'Hello';" + " }" + " abstract function bar();" + "}", PHPLexicalGrammar.COMPILATION_UNIT); ClassDeclarationTree cls = (ClassDeclarationTree) tree.script().statements().get(0); MethodDeclarationTree method = (MethodDeclarationTree) cls.members().get(0); StatementTree echo = ((BlockTree) method.body()).statements().get(0); ControlFlowGraph cfg = ControlFlowGraph.build(method, checkContext); assertThat(cfg.start().elements().get(0)).isEqualTo(echo); MethodDeclarationTree abstractMethod = (MethodDeclarationTree) cls.members().get(1); cfg = ControlFlowGraph.build(abstractMethod, checkContext); assertThat(cfg).isNull(); }
private void verifyLiveVariableAnalysis(String argsList, String body) { CompilationUnitTree cut = parse("<?php function f(" + argsList + ") { " + body + " }", PHPLexicalGrammar.COMPILATION_UNIT); SymbolTableImpl symbolTable = SymbolTableImpl.create(cut); FunctionDeclarationTree functionTree = (FunctionDeclarationTree) cut.script().statements().get(0); ControlFlowGraph cfg = ControlFlowGraph.build(functionTree.body()); LiveVariablesAnalysis analysis = LiveVariablesAnalysis.analyze(cfg, symbolTable); Validator.assertLiveVariables(cfg, analysis); }
@Test public void test_cfg_failure_logs() { CompilationUnitTree tree = parse("<?php\n" + "function foo() {\n" + " break;\n" + "}\n", PHPLexicalGrammar.COMPILATION_UNIT); FunctionDeclarationTree func = (FunctionDeclarationTree) tree.script().statements().get(0); ControlFlowGraph cfg = ControlFlowGraph.build(func, checkContext); assertThat(cfg).isNull(); assertThat(logTester.logs(LoggerLevel.WARN)).contains("Failed to build control flow graph for file [mock.php] at line 2"); assertThat(logTester.logs(LoggerLevel.WARN)).contains("Failed to build CFG"); logTester.clear(); // testing mechanism avoiding reporting failure multiple times for the same tree cfg = ControlFlowGraph.build(func, checkContext); assertThat(cfg).isNull(); assertThat(logTester.logs()).isEmpty(); }
@Test public void read_symbols() { String body = "" + "$foo = 1;" + "$bar = bar();" + "$bar += bar();" + "read($bar);" + "$qix += 1 + 2;"; CompilationUnitTree cut = parse("<?php function f() { " + body + " }", PHPLexicalGrammar.COMPILATION_UNIT); SymbolTableImpl symbolTable = SymbolTableImpl.create(cut); FunctionDeclarationTree functionTree = (FunctionDeclarationTree) cut.script().statements().get(0); ControlFlowGraph cfg = ControlFlowGraph.build(functionTree.body()); LiveVariablesAnalysis analysis = LiveVariablesAnalysis.analyze(cfg, symbolTable); Set<Symbol> readSymbols = analysis.getReadSymbols(); assertThat(readSymbols).extracting("name").containsExactlyInAnyOrder("$bar", "$qix"); }