--- /dev/null 2016-08-07 17:48:30.000000000 -0700 +++ new/langtools/test/tools/javac/modules/InheritRuntimeEnvironmentTest.java 2016-08-07 17:48:30.000000000 -0700 @@ -0,0 +1,421 @@ +/* + * Copyright (c) 2015, 2016, 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 8156998 + * @summary Test --inherit-runtime-environment + * @library /tools/lib + * @modules + * jdk.compiler/com.sun.tools.javac.api + * jdk.compiler/com.sun.tools.javac.main + * @build toolbox.ToolBox toolbox.JarTask toolbox.JavacTask toolbox.JavaTask ModuleTestBase + * @run main InheritRuntimeEnvironmentTest + */ + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; + +import toolbox.ModuleBuilder; +import toolbox.JavaTask; +import toolbox.JavacTask; +import toolbox.Task; + +/** + * Tests that javac picks up runtime options with --inherit-runtime-environment. + * For each option, javac is first run using the option directly, as a control. + * javac is then run again, with the same option(s) being passed to the runtime, + * and --inherit-runtime-environment being used by javac. + * @author jjg + */ +public class InheritRuntimeEnvironmentTest extends ModuleTestBase { + public static void main(String... args) throws Exception { + InheritRuntimeEnvironmentTest t = new InheritRuntimeEnvironmentTest(); + t.runTests(); + } + + /** + * Tests that code being compiled can access JDK-internal API using -add-exports. + * @param base + * @throws Exception + */ + @Test + public void testAddExports(Path base) throws Exception { + Path src = base.resolve("src"); + tb.writeJavaFiles(src, + "class C { com.sun.tools.javac.main.Main main; }"); + + new TestCase(base) + .testOpts("--add-exports", "jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED") + .files(findJavaFiles(src)) + .run(); + } + + /** + * Tests that code in the unnamed module can access a module on the module path using --add-modules. + */ + @Test + public void testAddModules(Path base) throws Exception { + Path modules = base.resolve("modules"); + new ModuleBuilder(tb, "m1") + .exports("pkg1") + .classes("package pkg1; public class C1 { }") + .build(modules); + + Path src = base.resolve("src"); + tb.writeJavaFiles(src, + "class C { pkg1.C1 c1; }"); + + new TestCase(base) + .testOpts("--module-path", modules.toString(), "--add-modules", "m1") + .files(findJavaFiles(src)) + .run(); + } + + /** + * Tests that a module on the module path is not visible when --limit-modules is used to + * restrict the set of observable modules. + */ + @Test + public void testLimitModules(Path base) throws Exception { + Path modules = base.resolve("modules"); + new ModuleBuilder(tb, "m1") + .exports("pkg1") + .classes("package pkg1; public class C1 { }") + .build(modules); + + Path src = base.resolve("src"); + new ModuleBuilder(tb, "m2") + .requires("m1") + .classes("package pkg2; public class C2 { pkg1.C1 c1; }") + .write(src); + + // This is the control, to verify that by default, the module being compiled will + // be able to read modules on the module path + new TestCase(base) + .testOpts("--module-path", modules.toString()) + .otherOpts("--module-source-path", src.toString()) + .files(findJavaFiles(src)) + .run(); + + // This is the test, to verify that the module being compiled will not be able to read + // modules on the module path when a --limit-modules is used + new TestCase(base) + .testOpts("--module-path", modules.toString(), "--limit-modules", "jdk.compiler") + .otherOpts("-XDrawDiagnostics", + "--module-source-path", src.toString()) + .files(findJavaFiles(src)) + .expect(Task.Expect.FAIL, "compiler.err.module.not.found") + .run(); + } + + /** + * Tests that a module being compiled can see another module on the module path + * using --module-path. + */ + @Test + public void testModulePath(Path base) throws Exception { + Path modules = base.resolve("modules"); + new ModuleBuilder(tb, "m1") + .exports("pkg1") + .classes("package pkg1; public class C1 { }") + .build(modules); + + Path src = base.resolve("src"); + new ModuleBuilder(tb, "m2") + .requires("m1") + .classes("package pkg2; public class C2 { pkg1.C1 c1; }") + .write(src); + + new TestCase(base) + .testOpts("--module-path", modules.toString()) + .otherOpts("--module-source-path", src.toString()) + .files(findJavaFiles(src)) + .run(); + } + + /** + * Tests that a module being compiled can see classes patches into an existing module + * with --patch-module + */ + @Test + public void testPatchModule(Path base) throws Exception { + Path patchSrc = base.resolve("patchSrc"); + tb.writeJavaFiles(patchSrc, + "package java.util; public class Xyzzy { }"); + Path patch = base.resolve("patch"); + Files.createDirectories(patch); + + new JavacTask(tb) + .options("-Xmodule:java.base") + .outdir(patch) + .sourcepath(patchSrc) + .files(findJavaFiles(patchSrc)) + .run() + .writeAll(); + + Path src = base.resolve("src"); + tb.writeJavaFiles(src, + "public class C { java.util.Xyzzy x; }"); + + new TestCase(base) + .testOpts("--patch-module", "java.base=" + patch) + .files(findJavaFiles(src)) + .run(); + } + + /** + * Tests that options in @files are also effective. + * The test is similar to testModulePath, except that the test options are provided in an @-file. + */ + @Test + public void testAtFile(Path base) throws Exception { + Path modules = base.resolve("modules"); + new ModuleBuilder(tb, "m1") + .exports("pkg1") + .classes("package pkg1; public class C1 { }") + .build(modules); + + Path src = base.resolve("src"); + new ModuleBuilder(tb, "m2") + .requires("m1") + .classes("package pkg2; public class C2 { pkg1.C1 c1; }") + .write(src); + + Path atFile = base.resolve("atFile"); + tb.writeFile(atFile, "--module-path " + modules); + + new TestCase(base) + .testOpts("@" + atFile) + .otherOpts("--module-source-path", src.toString()) + .files(findJavaFiles(src)) + .run(); + } + + /** + * Tests that --inherit-runtime-environment works in conjunction with + * environment variables. + * This is a variant of testAddExports. + * The use of environment variables is sufficiently custom that it is + * not easy to do this directly with a simple TestCase. + */ + @Test + public void testEnvVars(Path base) throws Exception { + Path src = base.resolve("src"); + tb.writeJavaFiles(src, + "class C { com.sun.tools.javac.main.Main main; }"); + List testOpts = + Arrays.asList("--add-exports", "jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED"); + List files = Arrays.asList(findJavaFiles(src)); + + String envName = "_JAVAC_OPTIONS"; + String envValue = String.join(" ", testOpts); + + out.println(" javac:"); + Path javacOutDir = base.resolve("out-javac"); + Files.createDirectories(javacOutDir); + + out.println(" env: " + envName + "=" + envValue); + out.println(" outdir: " + javacOutDir); + out.println(" files: " + files); + + new JavacTask(tb, Task.Mode.EXEC) + .envVar(envName, envValue) + .outdir(javacOutDir) + .files(files) + .run() + .writeAll() + .getOutput(Task.OutputKind.DIRECT); + + out.println(" java:"); + Path javaOutDir = base.resolve("out-java"); + Files.createDirectories(javaOutDir); + + Path atFile = base.resolve("atFile"); + tb.writeFile(atFile, String.join(" ", testOpts)); + + List vmOpts = Arrays.asList( + "@" + atFile, + "--module", "jdk.compiler/com.sun.tools.javac.Main" + ); + + List classArgs = join( + Arrays.asList("-d", javaOutDir.toString()), + files.stream() + .map(p -> p.toString()) + .collect(Collectors.toList()) + ); + + envValue = "--inherit-runtime-environment"; + + out.println(" env: " + envName + "=" + envValue); + out.println(" vmOpts: " + vmOpts); + out.println(" classArgs: " + classArgs); + + new JavaTask(tb) + .envVar(envName, envValue) + .vmOptions(vmOpts) + .classArgs(classArgs) + .run() + .writeAll() + .getOutput(Task.OutputKind.STDERR); + } + + /** + * Runs javac with given test options, first directly, and then again, specifying the + * options to the runtime, and using --inherit-runtime-environment. + */ + class TestCase { + final Path base; + List testOpts = Collections.emptyList(); + List otherOpts = Collections.emptyList(); + List files = Collections.emptyList(); + Task.Expect expect = Task.Expect.SUCCESS; + String expectedText; + + /** + * Creates a test case, specifying a base directory for work files. + */ + TestCase(Path base) { + this.base = base; + } + + /** + * Set the "test options" to be passed to javac or to the runtime. + */ + TestCase testOpts(String... testOpts) { + this.testOpts = Arrays.asList(testOpts); + return this; + } + + /** + * Sets additional options required for the compilation. + */ + TestCase otherOpts(String... otherOpts) { + this.otherOpts = Arrays.asList(otherOpts); + return this; + } + + /** + * Sets the files to be compiled. + */ + TestCase files(Path... files) { + this.files = Arrays.asList(files); + return this; + } + + /** + * Sets the expected output, and any expected output from javac. + * The default is {@code Expect.SUCCESS} and no specific output expected. + */ + TestCase expect(Task.Expect expect, String expectedText) { + this.expect = expect; + this.expectedText = expectedText; + return this; + } + + /** + * Runs the test case. + * First, javac is run passing the test options directly to javac. + * Then, javac is run again, passing the test options to the runtime, + * and using --inherit-runtime-environment. + */ + void run() throws IOException { + runJavac(); + runJava(); + } + + private void runJavac() throws IOException { + out.println(" javac:"); + Path javacOutDir = base.resolve("out-javac"); + Files.createDirectories(javacOutDir); + + List options = join(testOpts, otherOpts); + + out.println(" options: " + options); + out.println(" outdir: " + javacOutDir); + out.println(" files: " + files); + + String log = new JavacTask(tb, Task.Mode.CMDLINE) + .options(options) + .outdir(javacOutDir) + .files(files) + .run(expect) + .writeAll() + .getOutput(Task.OutputKind.DIRECT); + + if (expectedText != null && !log.contains(expectedText)) + error("expected text not found"); + } + + private void runJava() throws IOException { + out.println(" java:"); + Path javaOutDir = base.resolve("out-java"); + Files.createDirectories(javaOutDir); + + List vmOpts = join( + testOpts, + Arrays.asList("--module", "jdk.compiler/com.sun.tools.javac.Main") + ); + + List classArgs = join( + Arrays.asList("--inherit-runtime-environment", + "-d", javaOutDir.toString()), + otherOpts, + files.stream() + .map(p -> p.toString()) + .collect(Collectors.toList()) + ); + + out.println(" vmOpts: " + vmOpts); + out.println(" classArgs: " + classArgs); + + String log = new JavaTask(tb) + .vmOptions(vmOpts) + .classArgs(classArgs) + .run(expect) + .writeAll() + .getOutput(Task.OutputKind.STDERR); + + if (expectedText != null && !log.contains(expectedText)) + error("expected text not found"); + } + } + + /** + * Join a series of lists. + */ + @SafeVarargs + private List join(List... lists) { + return Arrays.stream(lists) + .flatMap(list -> list.stream()) + .collect(Collectors.toList()); + } + +} +