langtools/test/tools/javac/options/modes/OptionModesTester.java
changeset 40316 20b50a99fe8d
parent 36526 3b41f1c69604
equal deleted inserted replaced
40315:9e994c77db6a 40316:20b50a99fe8d
       
     1 /*
       
     2  * Copyright (c) 2014, 2016, 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 com.sun.tools.javac.api.JavacTool;
       
    25 import com.sun.tools.javac.file.JavacFileManager;
       
    26 import com.sun.tools.javac.util.Context;
       
    27 import java.io.ByteArrayOutputStream;
       
    28 import java.io.FileWriter;
       
    29 import java.io.IOException;
       
    30 import java.io.PrintStream;
       
    31 import java.io.PrintWriter;
       
    32 import java.io.StringWriter;
       
    33 import java.io.UncheckedIOException;
       
    34 import java.lang.annotation.Annotation;
       
    35 import java.lang.annotation.Retention;
       
    36 import java.lang.annotation.RetentionPolicy;
       
    37 import java.lang.reflect.InvocationTargetException;
       
    38 import java.lang.reflect.Method;
       
    39 import java.nio.file.Files;
       
    40 import java.nio.file.Path;
       
    41 import java.nio.file.Paths;
       
    42 import java.util.ArrayList;
       
    43 import java.util.Arrays;
       
    44 import java.util.EnumMap;
       
    45 import java.util.Iterator;
       
    46 import java.util.List;
       
    47 import java.util.Map;
       
    48 import java.util.stream.Collectors;
       
    49 import javax.tools.JavaFileManager;
       
    50 import javax.tools.JavaFileObject;
       
    51 import javax.tools.StandardJavaFileManager;
       
    52 import javax.tools.ToolProvider;
       
    53 
       
    54 public class OptionModesTester {
       
    55 
       
    56     /** Marker annotation for test methods to be invoked by runTests. */
       
    57     @Retention(RetentionPolicy.RUNTIME)
       
    58     @interface Test { }
       
    59 
       
    60     /**
       
    61      * Run all methods annotated with @Test, and throw an exception if any
       
    62      * errors are reported..
       
    63      * Typically called on a tester object in main()
       
    64      * @throws Exception if any errors occurred
       
    65      */
       
    66     void runTests() throws Exception {
       
    67         for (Method m: getClass().getDeclaredMethods()) {
       
    68             Annotation a = m.getAnnotation(Test.class);
       
    69             if (a != null) {
       
    70                 try {
       
    71                     out.println("Running test " + m.getName());
       
    72                     m.invoke(this);
       
    73                 } catch (InvocationTargetException e) {
       
    74                     Throwable cause = e.getCause();
       
    75                     throw (cause instanceof Exception) ? ((Exception) cause) : e;
       
    76                 }
       
    77                 out.println();
       
    78             }
       
    79         }
       
    80         if (errors > 0)
       
    81             throw new Exception(errors + " errors occurred");
       
    82     }
       
    83 
       
    84     TestResult runMain(String[] opts, String[] files) {
       
    85         out.println("Main " + Arrays.toString(opts) + " " + Arrays.toString(files));
       
    86         return run(new TestResult(opts), (tr, c, pw) -> {
       
    87             com.sun.tools.javac.main.Main compiler =
       
    88                 new com.sun.tools.javac.main.Main("javac", pw);
       
    89             int rc = compiler.compile(join(opts, files), c).exitCode;
       
    90             tr.setResult(rc);
       
    91         });
       
    92     }
       
    93 
       
    94     TestResult runCall(String[] opts, String[] files) {
       
    95         out.println("Call " + Arrays.toString(opts) + " " + Arrays.toString(files));
       
    96         return run(new TestResult(opts), (tr, c, pw) -> {
       
    97             boolean ok = JavacTool.create()
       
    98                     .getTask(pw, null, null, Arrays.asList(opts), null, getFiles(files), c)
       
    99                     .call();
       
   100             tr.setResult(ok);
       
   101         });
       
   102     }
       
   103 
       
   104     TestResult runParse(String[] opts, String[] files) {
       
   105         out.println("Parse " + Arrays.toString(opts) + " " + Arrays.toString(files));
       
   106         return run(new TestResult(opts), (tr, c, pw) -> {
       
   107             JavacTool.create()
       
   108                     .getTask(pw, null, null, Arrays.asList(opts), null, getFiles(files), c)
       
   109                     .parse();
       
   110             tr.setResult(true);
       
   111         });
       
   112     }
       
   113 
       
   114     TestResult runAnalyze(String[] opts, String[] files) {
       
   115         out.println("Analyze " + Arrays.toString(opts) + " " + Arrays.toString(files));
       
   116         return run(new TestResult(opts), (tr, c, pw) -> {
       
   117             JavacTool.create()
       
   118                     .getTask(pw, null, null, Arrays.asList(opts), null, getFiles(files), c)
       
   119                     .analyze();
       
   120             tr.setResult(true);
       
   121         });
       
   122     }
       
   123 
       
   124     interface Runnable {
       
   125         void run(TestResult tr, Context c, PrintWriter pw) throws IOException;
       
   126     }
       
   127 
       
   128     TestResult run(TestResult tr, Runnable r) {
       
   129         StringWriter sw = new StringWriter();
       
   130         PrintWriter pw = new PrintWriter(sw);
       
   131         StreamOutput sysOut = new StreamOutput(System.out, System::setOut);
       
   132         StreamOutput sysErr = new StreamOutput(System.err, System::setErr);
       
   133         Context context = new Context();
       
   134         JavacFileManager.preRegister(context);
       
   135         try {
       
   136             r.run(tr, context, pw);
       
   137         } catch (IllegalArgumentException | IllegalStateException | IOException e) {
       
   138             tr.setThrown(e);
       
   139         } finally {
       
   140             try {
       
   141                 ((JavacFileManager) context.get(JavaFileManager.class)).close();
       
   142             } catch (IOException e) {
       
   143                 throw new UncheckedIOException(e);
       
   144             }
       
   145             tr.setLogs(sw.toString(), sysOut.close(), sysErr.close());
       
   146         }
       
   147         tr.setContext(context);
       
   148         tr.show();
       
   149         return tr;
       
   150     }
       
   151 
       
   152     enum Log { DIRECT, STDOUT, STDERR };
       
   153 
       
   154     class TestResult {
       
   155         final List<String> args;
       
   156         Throwable thrown;
       
   157         List<Throwable> suppressed = new ArrayList<>();
       
   158         Object rc; // Number or Boolean
       
   159         Map<Log, String> logs;
       
   160         Context context;
       
   161 
       
   162         TestResult(String... args) {
       
   163             this.args = Arrays.asList(args);
       
   164         }
       
   165 
       
   166         TestResult(List<String> args, Iterable<? extends JavaFileObject> files) {
       
   167             this.args = new ArrayList<>();
       
   168             this.args.addAll(args);
       
   169             for (JavaFileObject f: files)
       
   170                 this.args.add(f.getName());
       
   171         }
       
   172 
       
   173         void setResult(int rc) {
       
   174             this.rc = rc;
       
   175         }
       
   176 
       
   177         void setResult(boolean ok) {
       
   178             this.rc = ok ? 0 : 1;
       
   179         }
       
   180 
       
   181         void setSuppressed(Throwable thrown) {
       
   182             this.suppressed.add(thrown);
       
   183         }
       
   184 
       
   185         void setThrown(Throwable thrown) {
       
   186             this.thrown = thrown;
       
   187         }
       
   188 
       
   189         void setLogs(String direct, String stdOut, String stdErr) {
       
   190             logs = new EnumMap<>(Log.class);
       
   191             logs.put(Log.DIRECT, direct);
       
   192             logs.put(Log.STDOUT, stdOut);
       
   193             logs.put(Log.STDERR, stdErr);
       
   194         }
       
   195 
       
   196         void setContext(Context context) {
       
   197             this.context = context;
       
   198         }
       
   199 
       
   200         final void show() {
       
   201             String NL = System.getProperty("line.separator");
       
   202             boolean needSep = false;
       
   203             if (rc != null) {
       
   204                 out.print("rc:" + rc);
       
   205                 needSep = true;
       
   206             }
       
   207             if (thrown != null) {
       
   208                 if (needSep) out.print("; ");
       
   209                 out.print("thrown:" + thrown);
       
   210                 needSep = true;
       
   211             }
       
   212             if (!suppressed.isEmpty()) {
       
   213                 if (needSep) out.print("; ");
       
   214                 out.print("suppressed:" + suppressed);
       
   215                 needSep = true;
       
   216             }
       
   217             if (needSep)
       
   218                 out.println();
       
   219             logs.forEach((k, v) -> {
       
   220                 if (!v.isEmpty()) {
       
   221                     out.println("javac/" + k + ":");
       
   222                     if (v.endsWith(NL))
       
   223                         out.print(v);
       
   224                     else
       
   225                         out.println(v);
       
   226                 }
       
   227 
       
   228             });
       
   229         }
       
   230 
       
   231         TestResult checkOK() {
       
   232             if (thrown != null) {
       
   233                 error("unexpected exception thrown: " + thrown);
       
   234             } else if (rc == null) {
       
   235                 error("no result set");
       
   236             } else if (rc != (Integer) 0 && rc != (Boolean) true) {
       
   237                 error("compilation failed unexpectedly; rc=" + rc);
       
   238             }
       
   239             return this;
       
   240         }
       
   241 
       
   242         TestResult checkResult(int expect) {
       
   243             if (thrown != null) {
       
   244                 error("unexpected exception thrown: " + thrown);
       
   245             } else if (rc != (Integer) expect) {
       
   246                 error("unexpected result: " + rc +", expected:" + expect);
       
   247             }
       
   248             return this;
       
   249         }
       
   250 
       
   251         TestResult checkResult(boolean expect) {
       
   252             if (thrown != null) {
       
   253                 error("unexpected exception thrown: " + thrown);
       
   254             } else if (rc != (Integer) (expect ? 0 : 1)) {
       
   255                 error("unexpected result: " + rc +", expected:" + expect);
       
   256             }
       
   257             return this;
       
   258         }
       
   259 
       
   260         TestResult checkLog(String... expects) {
       
   261             return checkLog(Log.DIRECT, expects);
       
   262         }
       
   263 
       
   264         TestResult checkLog(Log l, String... expects) {
       
   265             for (String e: expects) {
       
   266                 if (!logs.get(l).contains(e))
       
   267                     error("expected string not found: " + e);
       
   268             }
       
   269             return this;
       
   270         }
       
   271 
       
   272         TestResult checkIllegalArgumentException() {
       
   273             return checkThrown(IllegalArgumentException.class);
       
   274         }
       
   275 
       
   276         TestResult checkIllegalStateException() {
       
   277             return checkThrown(IllegalStateException.class);
       
   278         }
       
   279 
       
   280         TestResult checkThrown(Class<? extends Throwable> t) {
       
   281             if (thrown == null)
       
   282                 error("expected exception not thrown: " + t);
       
   283             else if (!t.isAssignableFrom(thrown.getClass()))
       
   284                 error("unexpected exception thrown: " + thrown + ";  expected: " + t);
       
   285             return this;
       
   286         }
       
   287 
       
   288         TestResult checkClass(String name) {
       
   289             Path p = getOutDir().resolve(name.replace(".", "/") + ".class");
       
   290             if (!Files.exists(p))
       
   291                 error("expected class not found: " + name + " (" + p + ")");
       
   292             return this;
       
   293         }
       
   294 
       
   295         Path getOutDir() {
       
   296             Iterator<String> iter = args.iterator();
       
   297             while (iter.hasNext()) {
       
   298                 if (iter.next().equals("-d")) {
       
   299                     return Paths.get(iter.next());
       
   300                 }
       
   301             }
       
   302             return null;
       
   303         }
       
   304     }
       
   305 
       
   306     /**
       
   307      * Utility class to simplify the handling of temporarily setting a
       
   308      * new stream for System.out or System.err.
       
   309      */
       
   310     private static class StreamOutput {
       
   311         // functional interface to set a stream.
       
   312         private interface Initializer {
       
   313             void set(PrintStream s);
       
   314         }
       
   315 
       
   316         private final ByteArrayOutputStream baos = new ByteArrayOutputStream();
       
   317         private final PrintStream ps = new PrintStream(baos);
       
   318         private final PrintStream prev;
       
   319         private final Initializer init;
       
   320 
       
   321         StreamOutput(PrintStream s, Initializer init) {
       
   322             prev = s;
       
   323             init.set(ps);
       
   324             this.init = init;
       
   325         }
       
   326 
       
   327         String close() {
       
   328             init.set(prev);
       
   329             ps.close();
       
   330             return baos.toString();
       
   331         }
       
   332     }
       
   333 
       
   334     List<JavaFileObject> getFiles(String... paths) {
       
   335         List<JavaFileObject> files = new ArrayList<>();
       
   336         for (JavaFileObject f : fm.getJavaFileObjects(paths))
       
   337             files.add(f);
       
   338         return files;
       
   339     }
       
   340 
       
   341     String toString(List<JavaFileObject> files) {
       
   342         return files.stream().map(f -> f.getName()).collect(Collectors.toList()).toString();
       
   343     }
       
   344 
       
   345     void mkdirs(String path) throws IOException {
       
   346         Files.createDirectories(Paths.get(path));
       
   347     }
       
   348 
       
   349     void writeFile(String path, String body) throws IOException {
       
   350         Path p = Paths.get(path);
       
   351         if (p.getParent() != null)
       
   352             Files.createDirectories(p.getParent());
       
   353         try (FileWriter w = new FileWriter(path)) {
       
   354             w.write(body);
       
   355         }
       
   356     }
       
   357 
       
   358     String[] join(String[] a, String[] b) {
       
   359         String[] result = new String[a.length + b.length];
       
   360         System.arraycopy(a, 0, result, 0, a.length);
       
   361         System.arraycopy(b, 0, result, a.length, b.length);
       
   362         return result;
       
   363     }
       
   364 
       
   365     void error(String message) {
       
   366         out.print(">>>>> ");
       
   367         out.println(message);
       
   368         errors++;
       
   369     }
       
   370 
       
   371     StandardJavaFileManager fm =
       
   372             ToolProvider.getSystemJavaCompiler().getStandardFileManager(null, null, null);
       
   373     PrintStream out = System.err;
       
   374     int errors;
       
   375 
       
   376 }