Path: blob/master/test/jdk/tools/launcher/SourceMode.java
41145 views
/*1* Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*/2223/**24* @test25* @bug 8192920 8204588 821027526* @summary Test source mode27* @modules jdk.compiler jdk.jlink28* @run main SourceMode29*/303132import java.io.IOException;33import java.io.PrintStream;34import java.nio.file.Files;35import java.nio.file.Path;36import java.nio.file.Paths;37import java.nio.file.attribute.PosixFilePermission;38import java.util.ArrayList;39import java.util.Arrays;40import java.util.HashMap;41import java.util.List;42import java.util.Map;43import java.util.Set;44import java.util.spi.ToolProvider;4546public class SourceMode extends TestHelper {4748public static void main(String... args) throws Exception {49new SourceMode().run(args);50}5152// To reduce the chance of creating shebang lines that are too long,53// use a shorter path for a java command if the standard path is too long.54private final Path shebangJavaCmd;5556// Whether or not to automatically skip the shebang tests57private final boolean skipShebangTest;5859private final PrintStream log;6061private static final String thisVersion = System.getProperty("java.specification.version");6263SourceMode() throws Exception {64log = System.err;6566if (isWindows) {67// Skip shebang tests on Windows, because that requires Cygwin.68skipShebangTest = true;69shebangJavaCmd = null;70} else {71// Try to ensure the path to the Java launcher is reasonably short,72// to work around the mostly undocumented limit of 120 characters73// for a shebang line.74// The value of 120 is the typical kernel compile-time buffer limit.75// The following limit of 80 allows room for arguments to be placed76// after the path to the launcher on the shebang line.77Path cmd = Paths.get(javaCmd);78if (cmd.toString().length() < 80) {79shebangJavaCmd = cmd;80} else {81// Create a small image in the current directory, such that82// the path for the launcher is just "tmpJDK/bin/java".83Path tmpJDK = Paths.get("tmpJDK");84ToolProvider jlink = ToolProvider.findFirst("jlink")85.orElseThrow(() -> new Exception("cannot find jlink"));86jlink.run(System.out, System.err,87"--add-modules", "jdk.compiler,jdk.zipfs", "--output", tmpJDK.toString());88shebangJavaCmd = tmpJDK.resolve("bin").resolve("java");89}90log.println("Using java command: " + shebangJavaCmd);91skipShebangTest = false;92}93}9495// java Simple.java 1 2 396@Test97void testSimpleJava() throws IOException {98starting("testSimpleJava");99Path file = getSimpleFile("Simple.java", false);100TestResult tr = doExec(javaCmd, file.toString(), "1", "2", "3");101if (!tr.isOK())102error(tr, "Bad exit code: " + tr.exitValue);103if (!tr.contains("[1, 2, 3]"))104error(tr, "Expected output not found");105show(tr);106}107108// java --source N simple 1 2 3109@Test110void testSimple() throws IOException {111starting("testSimple");112Path file = getSimpleFile("simple", false);113TestResult tr = doExec(javaCmd, "--source", thisVersion, file.toString(), "1", "2", "3");114if (!tr.isOK())115error(tr, "Bad exit code: " + tr.exitValue);116if (!tr.contains("[1, 2, 3]"))117error(tr, "Expected output not found");118show(tr);119}120121// execSimple 1 2 3122@Test123void testExecSimple() throws IOException {124starting("testExecSimple");125if (skipShebangTest) {126log.println("SKIPPED");127return;128}129Path file = setExecutable(getSimpleFile("execSimple", true));130TestResult tr = doExec(file.toAbsolutePath().toString(), "1", "2", "3");131if (!tr.isOK())132error(tr, "Bad exit code: " + tr.exitValue);133if (!tr.contains("[1, 2, 3]"))134error(tr, "Expected output not found");135show(tr);136}137138// java @simpleJava.at (contains Simple.java 1 2 3)139@Test140void testSimpleJavaAtFile() throws IOException {141starting("testSimpleJavaAtFile");142Path file = getSimpleFile("Simple.java", false);143Path atFile = Paths.get("simpleJava.at");144createFile(atFile, List.of(file + " 1 2 3"));145TestResult tr = doExec(javaCmd, "@" + atFile);146if (!tr.isOK())147error(tr, "Bad exit code: " + tr.exitValue);148if (!tr.contains("[1, 2, 3]"))149error(tr, "Expected output not found");150show(tr);151}152153// java @simple.at (contains --source N simple 1 2 3)154@Test155void testSimpleAtFile() throws IOException {156starting("testSimpleAtFile");157Path file = getSimpleFile("simple", false);158Path atFile = Paths.get("simple.at");159createFile(atFile, List.of("--source " + thisVersion + " " + file + " 1 2 3"));160TestResult tr = doExec(javaCmd, "@" + atFile);161if (!tr.isOK())162error(tr, "Bad exit code: " + tr.exitValue);163if (!tr.contains("[1, 2, 3]"))164error(tr, "Expected output not found");165show(tr);166}167168// java -cp classes Main.java 1 2 3169@Test170void testClasspath() throws IOException {171starting("testClasspath");172Path base = Files.createDirectories(Paths.get("testClasspath"));173Path otherJava = base.resolve("Other.java");174createFile(otherJava, List.of(175"public class Other {",176" public static String join(String[] args) {",177" return String.join(\"-\", args);",178" }",179"}"180));181Path classes = Files.createDirectories(base.resolve("classes"));182Path mainJava = base.resolve("Main.java");183createFile(mainJava, List.of(184"class Main {",185" public static void main(String[] args) {",186" System.out.println(Other.join(args));",187" }}"188));189compile("-d", classes.toString(), otherJava.toString());190TestResult tr = doExec(javaCmd, "-cp", classes.toString(),191mainJava.toString(), "1", "2", "3");192if (!tr.isOK())193error(tr, "Bad exit code: " + tr.exitValue);194if (!tr.contains("1-2-3"))195error(tr, "Expected output not found");196show(tr);197}198199// java --add-exports=... Export.java --help200@Test201void testAddExports() throws IOException {202starting("testAddExports");203Path exportJava = Paths.get("Export.java");204createFile(exportJava, List.of(205"public class Export {",206" public static void main(String[] args) {",207" new com.sun.tools.javac.main.Main(\"demo\").compile(args);",208" }",209"}"210));211// verify access fails without --add-exports212TestResult tr1 = doExec(javaCmd, exportJava.toString(), "--help");213if (tr1.isOK())214error(tr1, "Compilation succeeded unexpectedly");215show(tr1);216// verify access succeeds with --add-exports217TestResult tr2 = doExec(javaCmd,218"--add-exports", "jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED",219exportJava.toString(), "--help");220if (!tr2.isOK())221error(tr2, "Bad exit code: " + tr2.exitValue);222if (!(tr2.contains("demo") && tr2.contains("Usage")))223error(tr2, "Expected output not found");224show(tr2);225}226227// java -cp ... HelloWorld.java (for a class "java" in package "HelloWorld")228@Test229void testClassNamedJava() throws IOException {230starting("testClassNamedJava");231Path base = Files.createDirectories(Paths.get("testClassNamedJava"));232Path src = Files.createDirectories(base.resolve("src"));233Path srcfile = src.resolve("java.java");234createFile(srcfile, List.of(235"package HelloWorld;",236"class java {",237" public static void main(String... args) {",238" System.out.println(HelloWorld.java.class.getName());",239" }",240"}"241));242Path classes = base.resolve("classes");243compile("-d", classes.toString(), srcfile.toString());244TestResult tr =245doExec(javaCmd, "-cp", classes.toString(), "HelloWorld.java");246if (!tr.isOK())247error(tr, "Command failed");248if (!tr.contains("HelloWorld.java"))249error(tr, "Expected output not found");250show(tr);251}252253// java --source N -cp ... HelloWorld254@Test255void testSourceClasspath() throws IOException {256starting("testSourceClasspath");257Path base = Files.createDirectories(Paths.get("testSourceClasspath"));258Path src = Files.createDirectories(base.resolve("src"));259Path srcfile = src.resolve("java.java");260createFile(srcfile, List.of(261"class HelloWorld {",262" public static void main(String... args) {",263" System.out.println(\"Hello World\");",264" }",265"}"266));267Path classes = base.resolve("classes");268compile("-d", classes.toString(), srcfile.toString());269TestResult tr =270doExec(javaCmd, "--source", thisVersion, "-cp", classes.toString(), "HelloWorld");271if (tr.isOK())272error(tr, "Command succeeded unexpectedly");273if (!tr.contains("file not found: HelloWorld"))274error(tr, "Expected output not found");275show(tr);276}277278// java --source279@Test280void testSourceNoArg() throws IOException {281starting("testSourceNoArg");282TestResult tr = doExec(javaCmd, "--source");283if (tr.isOK())284error(tr, "Command succeeded unexpectedly");285if (!tr.contains("--source requires source version"))286error(tr, "Expected output not found");287show(tr);288}289290// java --source N -jar simple.jar291@Test292void testSourceJarConflict() throws IOException {293starting("testSourceJarConflict");294Path base = Files.createDirectories(Paths.get("testSourceJarConflict"));295Path file = getSimpleFile("Simple.java", false);296Path classes = Files.createDirectories(base.resolve("classes"));297compile("-d", classes.toString(), file.toString());298Path simpleJar = base.resolve("simple.jar");299createJar("cf", simpleJar.toString(), "-C", classes.toString(), ".");300TestResult tr =301doExec(javaCmd, "--source", thisVersion, "-jar", simpleJar.toString());302if (tr.isOK())303error(tr, "Command succeeded unexpectedly");304if (!tr.contains("Option -jar is not allowed with --source"))305error(tr, "Expected output not found");306show(tr);307}308309// java --source N -m jdk.compiler310@Test311void testSourceModuleConflict() throws IOException {312starting("testSourceModuleConflict");313TestResult tr = doExec(javaCmd, "--source", thisVersion, "-m", "jdk.compiler");314if (tr.isOK())315error(tr, "Command succeeded unexpectedly");316if (!tr.contains("Option -m is not allowed with --source"))317error(tr, "Expected output not found");318show(tr);319}320321// #!.../java --source N -version322@Test323void testTerminalOptionInShebang() throws IOException {324starting("testTerminalOptionInShebang");325if (skipShebangTest || isAIX || isMacOSX) {326// On MacOSX, we cannot distinguish between terminal options on the327// shebang line and those on the command line.328// On Solaris, all options after the first on the shebang line are329// ignored. Similar on AIX.330log.println("SKIPPED");331return;332}333Path base = Files.createDirectories(334Paths.get("testTerminalOptionInShebang"));335Path bad = base.resolve("bad");336createFile(bad, List.of(337"#!" + shebangJavaCmd + " --source " + thisVersion + " -version"));338setExecutable(bad);339TestResult tr = doExec(bad.toString());340if (!tr.contains("Option -version is not allowed in this context"))341error(tr, "Expected output not found");342show(tr);343}344345// #!.../java --source N @bad.at (contains -version)346@Test347void testTerminalOptionInShebangAtFile() throws IOException {348starting("testTerminalOptionInShebangAtFile");349if (skipShebangTest || isAIX || isMacOSX) {350// On MacOSX, we cannot distinguish between terminal options in a351// shebang @-file and those on the command line.352// On Solaris, all options after the first on the shebang line are353// ignored. Similar on AIX.354log.println("SKIPPED");355return;356}357// Use a short directory name, to avoid line length limitations358Path base = Files.createDirectories(Paths.get("testBadAtFile"));359Path bad_at = base.resolve("bad.at");360createFile(bad_at, List.of("-version"));361Path bad = base.resolve("bad");362createFile(bad, List.of(363"#!" + shebangJavaCmd + " --source " + thisVersion + " @" + bad_at));364setExecutable(bad);365TestResult tr = doExec(bad.toString());366if (!tr.contains("Option -version in @testBadAtFile/bad.at is "367+ "not allowed in this context"))368error(tr, "Expected output not found");369show(tr);370}371372// #!.../java --source N HelloWorld373@Test374void testMainClassInShebang() throws IOException {375starting("testMainClassInShebang");376if (skipShebangTest || isAIX || isMacOSX) {377// On MacOSX, we cannot distinguish between a main class on the378// shebang line and one on the command line.379// On Solaris, all options after the first on the shebang line are380// ignored. Similar on AIX.381log.println("SKIPPED");382return;383}384Path base = Files.createDirectories(Paths.get("testMainClassInShebang"));385Path bad = base.resolve("bad");386createFile(bad, List.of(387"#!" + shebangJavaCmd + " --source " + thisVersion + " HelloWorld"));388setExecutable(bad);389TestResult tr = doExec(bad.toString());390if (!tr.contains("Cannot specify main class in this context"))391error(tr, "Expected output not found");392show(tr);393}394395//--------------------------------------------------------------------------396397private void starting(String label) {398System.out.println();399System.out.println("*** Starting: " + label + " (stdout)");400401System.err.println();402System.err.println("*** Starting: " + label + " (stderr)");403}404405private void show(TestResult tr) {406log.println("*** Test Output:");407for (String line: tr.testOutput) {408log.println(line);409}410log.println("*** End Of Test Output:");411}412413private Map<String,String> getLauncherDebugEnv() {414return Map.of("_JAVA_LAUNCHER_DEBUG", "1");415}416417private Path getSimpleFile(String name, boolean shebang) throws IOException {418Path file = Paths.get(name);419if (!Files.exists(file)) {420createFile(file, List.of(421(shebang ? "#!" + shebangJavaCmd + " --source=" + thisVersion: ""),422"public class Simple {",423" public static void main(String[] args) {",424" System.out.println(java.util.Arrays.toString(args));",425" }}"));426}427return file;428}429430private void createFile(Path file, List<String> lines) throws IOException {431lines.stream()432.filter(line -> line.length() > 128)433.forEach(line -> {434log.println("*** Warning: long line ("435+ line.length()436+ " chars) in file " + file);437log.println("*** " + line);438});439log.println("*** File: " + file);440lines.stream().forEach(log::println);441log.println("*** End Of File");442createFile(file.toFile(), lines);443}444445private Path setExecutable(Path file) throws IOException {446Set<PosixFilePermission> perms = Files.getPosixFilePermissions(file);447perms.add(PosixFilePermission.OWNER_EXECUTE);448Files.setPosixFilePermissions(file, perms);449return file;450}451452private void error(TestResult tr, String message) {453show(tr);454throw new RuntimeException(message);455}456}457458459