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