/* * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ /* * @test * @bug 8004182 8028545 * @summary Add support for profiles in javac * @modules java.desktop * java.sql.rowset * jdk.compiler/com.sun.tools.javac.api * jdk.compiler/com.sun.tools.javac.jvm * jdk.security.auth */ import java.io.PrintWriter; import java.io.StringWriter; import java.lang.annotation.Annotation; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.net.URI; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.EnumMap; import java.util.List; import java.util.Map; import javax.tools.Diagnostic; import javax.tools.DiagnosticCollector; import javax.tools.JavaCompiler; import javax.tools.JavaFileObject; import javax.tools.SimpleJavaFileObject; import javax.tools.StandardJavaFileManager; import com.sun.source.util.JavacTask; import com.sun.tools.javac.api.JavacTool; import com.sun.tools.javac.jvm.Profile; import com.sun.tools.javac.jvm.Target; public class ProfileOptionTest { public static void main(String... args) throws Exception { new ProfileOptionTest().run(); } private final JavaCompiler javac = JavacTool.create(); private final StandardJavaFileManager fm = javac.getStandardFileManager(null, null, null); // ---------- Test cases, invoked reflectively via run. ---------- @Test void testInvalidProfile_API() throws Exception { JavaFileObject fo = new StringJavaFileObject("Test.java", "class Test { }"); String badName = "foo"; List opts = Arrays.asList("--release", "8", "-profile", badName); StringWriter sw = new StringWriter(); try { JavacTask task = (JavacTask) javac.getTask(sw, fm, null, opts, null, Arrays.asList(fo)); throw new Exception("expected exception not thrown"); } catch (IllegalArgumentException e) { // expected } } @Test void testInvalidProfile_CommandLine() throws Exception { String badName = "foo"; String[] opts = { "--release", "8", "-profile", badName }; StringWriter sw = new StringWriter(); PrintWriter pw = new PrintWriter(sw); int rc = com.sun.tools.javac.Main.compile(opts, pw); // sadly, command line errors are not (yet?) reported to // the diag listener String out = sw.toString(); if (!out.isEmpty()) System.err.println(out.trim()); if (!out.contains("invalid profile: " + badName)) { error("expected message not found"); } } @Test void testTargetProfileCombinations() throws Exception { JavaFileObject fo = new StringJavaFileObject("Test.java", "class Test { }"); for (Target t: Target.values()) { switch (t) { case JDK1_1: case JDK1_2: case JDK1_3: case JDK1_4: case JDK1_5: // not supported continue; } for (Profile p: Profile.values()) { List opts = new ArrayList<>(); opts.addAll(Arrays.asList("-source", t.name, "-target", t.name)); opts.add("-Xlint:-options"); // don't warn about no -bootclasspath if (p != Profile.DEFAULT) opts.addAll(Arrays.asList("-profile", p.name)); IllegalStateException ise; StringWriter sw = new StringWriter(); try { JavacTask task = (JavacTask) javac.getTask(sw, fm, null, opts, null, Arrays.asList(fo)); task.analyze(); ise = null; } catch (IllegalStateException e) { ise = e; } // sadly, command line errors are not (yet?) reported to // the diag listener String out = sw.toString(); if (!out.isEmpty()) System.err.println(out.trim()); switch (t) { case JDK1_8: if (ise != null) error("unexpected exception from compiler: " + ise); break; case JDK1_9: case JDK1_10: case JDK1_11: case JDK1_12: case JDK1_13: if (p == Profile.DEFAULT) break; if (ise == null) error("IllegalStateException not thrown as expected"); else if (!ise.getMessage().contains("option -profile " + "not allowed with target " + t.name)) { error("exception not thrown as expected: " + ise); } break; default: if (p == Profile.DEFAULT) break; if (ise == null) error("IllegalStateException not thrown as expected"); else if (!ise.getMessage().contains("profile " + p.name + " is not valid for target release " + t.name)) { error("exception not thrown as expected: " + ise); } break; } } } } @Test void testClassesInProfiles() throws Exception { for (Profile p: Profile.values()) { for (Map.Entry> e: testClasses.entrySet()) { for (JavaFileObject fo: e.getValue()) { DiagnosticCollector dl = new DiagnosticCollector(); List opts = (p == Profile.DEFAULT) ? Collections.emptyList() : Arrays.asList("--release", "8", "-profile", p.name); JavacTask task = (JavacTask) javac.getTask(null, fm, dl, opts, null, Arrays.asList(fo)); task.analyze(); List expectDiagCodes = new ArrayList<>(); if (fo.getName().equals("TPolicyFile.java")) { expectDiagCodes.add("compiler.warn.has.been.deprecated.for.removal"); } if (p.value < e.getKey().value) { expectDiagCodes.add("compiler.err.not.in.profile"); } checkDiags(opts + " " + fo.getName(), dl.getDiagnostics(), expectDiagCodes); } } } } Map> testClasses = new EnumMap>(Profile.class); void initTestClasses() { // The following table assumes the existence of specific classes // in specific profiles, as defined in the Java SE 8 spec. init(Profile.COMPACT1, java.lang.String.class); init(Profile.COMPACT2, javax.xml.XMLConstants.class); //init(Profile.COMPACT3, // javax.sql.rowset.Predicate.class, // com.sun.security.auth.PolicyFile.class); // specifically included in 3 init(Profile.COMPACT3, javax.sql.rowset.Predicate.class); init(Profile.DEFAULT, java.beans.BeanInfo.class); } void init(Profile p, Class... classes) { List srcs = new ArrayList(); for (Class c: classes) { String name = "T" + c.getSimpleName(); String src = "class T" + name + "{" + "\n" + " Class c = " + c.getName() + ".class;\n" + "}"; srcs.add(new StringJavaFileObject(name + ".java", src)); } testClasses.put(p, srcs); } void checkDiags(String msg, List> diags, List expectDiagCodes) { System.err.print(msg); if (diags.isEmpty()) System.err.println(" OK"); else { System.err.println(); System.err.println(diags); } List foundDiagCodes = new ArrayList(); for (Diagnostic d: diags) foundDiagCodes.add(d.getCode()); if (!foundDiagCodes.equals(expectDiagCodes)) { System.err.println("Found diag codes: " + foundDiagCodes); System.err.println("Expected diag codes: " + expectDiagCodes); error("expected diagnostics not found"); } } /** Marker annotation for test cases. */ @Retention(RetentionPolicy.RUNTIME) @interface Test { } /** Run all test cases. */ void run() throws Exception { try { initTestClasses(); for (Method m: getClass().getDeclaredMethods()) { Annotation a = m.getAnnotation(Test.class); if (a != null) { System.err.println(m.getName()); try { m.invoke(this, new Object[] { }); } catch (InvocationTargetException e) { Throwable cause = e.getCause(); throw (cause instanceof Exception) ? ((Exception) cause) : e; } System.err.println(); } } if (errors > 0) throw new Exception(errors + " errors occurred"); } finally { fm.close(); } } void error(String msg) { System.err.println("Error: " + msg); errors++; } int errors; private static class StringJavaFileObject extends SimpleJavaFileObject { StringJavaFileObject(String name, String text) { super(URI.create(name), JavaFileObject.Kind.SOURCE); this.text = text; } @Override public CharSequence getCharContent(boolean b) { return text; } private String text; } }