test/langtools/jdk/jshell/CompletenessStressTest.java
changeset 47216 71c04702a3d5
parent 40498 f54048be4a57
equal deleted inserted replaced
47215:4ebc2e2fb97c 47216:71c04702a3d5
       
     1 /*
       
     2  * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
       
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
       
     4  *
       
     5  * This code is free software; you can redistribute it and/or modify it
       
     6  * under the terms of the GNU General Public License version 2 only, as
       
     7  * published by the Free Software Foundation.
       
     8  *
       
     9  * This code is distributed in the hope that it will be useful, but WITHOUT
       
    10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
       
    11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
       
    12  * version 2 for more details (a copy is included in the LICENSE file that
       
    13  * accompanied this code).
       
    14  *
       
    15  * You should have received a copy of the GNU General Public License version
       
    16  * 2 along with this work; if not, write to the Free Software Foundation,
       
    17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
       
    18  *
       
    19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
       
    20  * or visit www.oracle.com if you need additional information or have any
       
    21  * questions.
       
    22  */
       
    23 
       
    24 import java.io.File;
       
    25 import java.io.IOException;
       
    26 import java.io.StringWriter;
       
    27 import java.nio.charset.StandardCharsets;
       
    28 import java.nio.file.Files;
       
    29 import java.nio.file.Path;
       
    30 import java.nio.file.Paths;
       
    31 import java.util.ArrayList;
       
    32 import java.util.List;
       
    33 import java.util.Set;
       
    34 import java.util.stream.Collectors;
       
    35 
       
    36 import javax.lang.model.element.Modifier;
       
    37 import javax.tools.JavaCompiler;
       
    38 import javax.tools.JavaFileObject;
       
    39 import javax.tools.StandardJavaFileManager;
       
    40 import javax.tools.ToolProvider;
       
    41 
       
    42 import com.sun.source.tree.BlockTree;
       
    43 import com.sun.source.tree.BreakTree;
       
    44 import com.sun.source.tree.CaseTree;
       
    45 import com.sun.source.tree.ClassTree;
       
    46 import com.sun.source.tree.CompilationUnitTree;
       
    47 import com.sun.source.tree.ContinueTree;
       
    48 import com.sun.source.tree.DoWhileLoopTree;
       
    49 import com.sun.source.tree.ExpressionStatementTree;
       
    50 import com.sun.source.tree.ForLoopTree;
       
    51 import com.sun.source.tree.IfTree;
       
    52 import com.sun.source.tree.ImportTree;
       
    53 import com.sun.source.tree.LabeledStatementTree;
       
    54 import com.sun.source.tree.LineMap;
       
    55 import com.sun.source.tree.MethodTree;
       
    56 import com.sun.source.tree.ReturnTree;
       
    57 import com.sun.source.tree.StatementTree;
       
    58 import com.sun.source.tree.SwitchTree;
       
    59 import com.sun.source.tree.Tree;
       
    60 import com.sun.source.tree.WhileLoopTree;
       
    61 import com.sun.source.util.SourcePositions;
       
    62 import com.sun.source.util.Trees;
       
    63 import com.sun.tools.javac.api.JavacTaskImpl;
       
    64 
       
    65 import jdk.jshell.SourceCodeAnalysis;
       
    66 
       
    67 import org.testng.annotations.DataProvider;
       
    68 import org.testng.annotations.Test;
       
    69 
       
    70 import static java.lang.Integer.max;
       
    71 import static java.lang.Integer.min;
       
    72 import static jdk.jshell.SourceCodeAnalysis.Completeness.*;
       
    73 
       
    74 public class CompletenessStressTest extends KullaTesting {
       
    75     public final static String JDK_ROOT_SRC_PROP = "jdk.root.src";
       
    76     public final static String JDK_ROOT_SRC;
       
    77 
       
    78     static {
       
    79         JDK_ROOT_SRC = System.getProperty(JDK_ROOT_SRC_PROP);
       
    80     }
       
    81 
       
    82     public File getSourceFile(String fileName) {
       
    83         for (File dir : getDirectoriesToTest()) {
       
    84             File file = new File(dir, fileName);
       
    85             if (file.exists()) {
       
    86                 return file;
       
    87             }
       
    88         }
       
    89         throw new AssertionError("File not found: " + fileName);
       
    90     }
       
    91 
       
    92     public File[] getDirectoriesToTest() {
       
    93         return new File[]{
       
    94                 new File(JDK_ROOT_SRC, "nashorn/src"),
       
    95                 new File(JDK_ROOT_SRC, "langtools/src"),
       
    96                 new File(JDK_ROOT_SRC, "jaxp/src"),
       
    97                 new File(JDK_ROOT_SRC, "jaxws/src"),
       
    98                 new File(JDK_ROOT_SRC, "jdk/src"),
       
    99                 new File(JDK_ROOT_SRC, "corba/src")
       
   100         };
       
   101     }
       
   102 
       
   103     @DataProvider(name = "crawler")
       
   104     public Object[][] dataProvider() throws IOException {
       
   105         File[] srcDirs = getDirectoriesToTest();
       
   106         List<String[]> list = new ArrayList<>();
       
   107         for (File srcDir : srcDirs) {
       
   108             String srcDirName = srcDir.getAbsolutePath();
       
   109             // this is just to obtain pretty test names for testng tests
       
   110             List<String[]> a = Files.walk(Paths.get(srcDirName))
       
   111                     .map(Path::toFile)
       
   112                     .map(File::getAbsolutePath)
       
   113                     .filter(n -> n.endsWith(".java"))
       
   114                     .map(n -> n.replace(srcDirName, ""))
       
   115                     .map(n -> new String[]{n})
       
   116                     .collect(Collectors.toList());
       
   117             if (a.isEmpty()) {
       
   118                 throw new AssertionError("Java sources have not been found in directory: " + srcDirName);
       
   119             }
       
   120             list.addAll(a);
       
   121         }
       
   122         return list.toArray(new String[list.size()][]);
       
   123     }
       
   124 
       
   125     @Test(dataProvider = "crawler")
       
   126     public void testFile(String fileName) throws IOException {
       
   127         File file = getSourceFile(fileName);
       
   128         final JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
       
   129         final StandardJavaFileManager fileManager = compiler.getStandardFileManager(null, null, null);
       
   130         boolean success = true;
       
   131         StringWriter writer = new StringWriter();
       
   132         writer.write("Testing : " + file.toString() + "\n");
       
   133         String text = new String(Files.readAllBytes(file.toPath()), StandardCharsets.UTF_8);
       
   134         Iterable<? extends JavaFileObject> compilationUnits = fileManager.getJavaFileObjects(file);
       
   135         JavacTaskImpl task = (JavacTaskImpl) compiler.getTask(null, fileManager, null, null, null, compilationUnits);
       
   136         Iterable<? extends CompilationUnitTree> asts = task.parse();
       
   137         Trees trees = Trees.instance(task);
       
   138         SourcePositions sp = trees.getSourcePositions();
       
   139 
       
   140         for (CompilationUnitTree cut : asts) {
       
   141             for (ImportTree imp : cut.getImports()) {
       
   142                 success &= testStatement(writer, sp, text, cut, imp);
       
   143             }
       
   144             for (Tree decl : cut.getTypeDecls()) {
       
   145                 success &= testStatement(writer, sp, text, cut, decl);
       
   146                 if (decl instanceof ClassTree) {
       
   147                     ClassTree ct = (ClassTree) decl;
       
   148                     for (Tree mem : ct.getMembers()) {
       
   149                         if (mem instanceof MethodTree) {
       
   150                             MethodTree mt = (MethodTree) mem;
       
   151                             BlockTree bt = mt.getBody();
       
   152                             // No abstract methods or constructors
       
   153                             if (bt != null && mt.getReturnType() != null) {
       
   154                                 // The modifiers synchronized, abstract, and default are not allowed on
       
   155                                 // top-level declarations and are errors.
       
   156                                 Set<Modifier> modifier = mt.getModifiers().getFlags();
       
   157                                 if (!modifier.contains(Modifier.ABSTRACT)
       
   158                                         && !modifier.contains(Modifier.SYNCHRONIZED)
       
   159                                         && !modifier.contains(Modifier.DEFAULT)) {
       
   160                                     success &= testStatement(writer, sp, text, cut, mt);
       
   161                                 }
       
   162                                 testBlock(writer, sp, text, cut, bt);
       
   163                             }
       
   164                         }
       
   165                     }
       
   166                 }
       
   167             }
       
   168         }
       
   169         fileManager.close();
       
   170         if (!success) {
       
   171             throw new AssertionError(writer.toString());
       
   172         }
       
   173     }
       
   174 
       
   175     private boolean isLegal(StatementTree st) {
       
   176         return !(st instanceof ReturnTree) &&
       
   177                 !(st instanceof ContinueTree) && !(st instanceof BreakTree);
       
   178     }
       
   179 
       
   180     private boolean testBranch(StringWriter writer, SourcePositions sp, String text, CompilationUnitTree cut, StatementTree statementTree) {
       
   181         if (statementTree instanceof BlockTree) {
       
   182             return testBlock(writer, sp, text, cut, (BlockTree) statementTree);
       
   183         } else if (isLegal(statementTree)) {
       
   184             return testStatement(writer, sp, text, cut, statementTree);
       
   185         }
       
   186         return true;
       
   187     }
       
   188 
       
   189     private boolean testBlock(StringWriter writer, SourcePositions sp, String text, CompilationUnitTree cut, BlockTree blockTree) {
       
   190         boolean success = true;
       
   191         for (StatementTree st : blockTree.getStatements()) {
       
   192             if (isLegal(st)) {
       
   193                 success &= testStatement(writer, sp, text, cut, st);
       
   194             }
       
   195             if (st instanceof IfTree) {
       
   196                 IfTree ifTree = (IfTree) st;
       
   197                 success &= testBranch(writer, sp, text, cut, ifTree.getThenStatement());
       
   198                 success &= testBranch(writer, sp, text, cut, ifTree.getElseStatement());
       
   199             } else if (st instanceof WhileLoopTree) {
       
   200                 WhileLoopTree whileLoopTree = (WhileLoopTree) st;
       
   201                 success &= testBranch(writer, sp, text, cut, whileLoopTree.getStatement());
       
   202             } else if (st instanceof DoWhileLoopTree) {
       
   203                 DoWhileLoopTree doWhileLoopTree = (DoWhileLoopTree) st;
       
   204                 success &= testBranch(writer, sp, text, cut, doWhileLoopTree.getStatement());
       
   205             } else if (st instanceof ForLoopTree) {
       
   206                 ForLoopTree forLoopTree = (ForLoopTree) st;
       
   207                 success &= testBranch(writer, sp, text, cut, forLoopTree.getStatement());
       
   208             } else if (st instanceof LabeledStatementTree) {
       
   209                 LabeledStatementTree labelTree = (LabeledStatementTree) st;
       
   210                 success &= testBranch(writer, sp, text, cut, labelTree.getStatement());
       
   211             } else if (st instanceof SwitchTree) {
       
   212                 SwitchTree switchTree = (SwitchTree) st;
       
   213                 for (CaseTree caseTree : switchTree.getCases()) {
       
   214                     for (StatementTree statementTree : caseTree.getStatements()) {
       
   215                         success &= testBranch(writer, sp, text, cut, statementTree);
       
   216                     }
       
   217                 }
       
   218             }
       
   219         }
       
   220         return success;
       
   221     }
       
   222 
       
   223     private boolean testStatement(StringWriter writer, SourcePositions sp, String text, CompilationUnitTree cut, Tree statement) {
       
   224         if (statement == null) {
       
   225             return true;
       
   226         }
       
   227         int start = (int) sp.getStartPosition(cut, statement);
       
   228         int end = (int) sp.getEndPosition(cut, statement);
       
   229         char ch = text.charAt(end - 1);
       
   230         SourceCodeAnalysis.Completeness expected = COMPLETE;
       
   231         LineMap lineMap = cut.getLineMap();
       
   232         int row = (int) lineMap.getLineNumber(start);
       
   233         int column = (int) lineMap.getColumnNumber(start);
       
   234         switch (ch) {
       
   235             case ',':
       
   236             case ';':
       
   237                 expected = (statement instanceof ExpressionStatementTree)
       
   238                         ? COMPLETE
       
   239                         : COMPLETE_WITH_SEMI;
       
   240                 --end;
       
   241                 break;
       
   242             case '}':
       
   243                 break;
       
   244             default:
       
   245                 writer.write(String.format("Unexpected end: row %d, column %d: '%c' -- %s\n",
       
   246                         row, column, ch, text.substring(start, end)));
       
   247                 return true;
       
   248         }
       
   249         String unit = text.substring(start, end);
       
   250         SourceCodeAnalysis.CompletionInfo ci = getAnalysis().analyzeCompletion(unit);
       
   251         if (ci.completeness() != expected) {
       
   252             if (expected == COMPLETE_WITH_SEMI && (ci.completeness() == CONSIDERED_INCOMPLETE || ci.completeness() == EMPTY)) {
       
   253                 writer.write(String.format("Empty statement: row %d, column %d: -- %s\n",
       
   254                         start, end, unit));
       
   255             } else {
       
   256                 writer.write(String.format("Expected %s got %s: '%s'  row %d, column %d: -- %s\n",
       
   257                         expected, ci.completeness(), unit, row, column, unit));
       
   258                 return false;
       
   259             }
       
   260         }
       
   261         return true;
       
   262     }
       
   263 }