--- old/test/tools/javac/modules/XModuleTest.java 2017-02-08 11:44:19.794727082 -0800 +++ new/test/tools/javac/modules/XModuleTest.java 2017-02-08 11:44:19.657726053 -0800 @@ -23,6 +23,7 @@ /* * @test + * @bug 8173777 * @summary tests for multi-module mode compilation * @library /tools/lib * @modules @@ -34,10 +35,12 @@ * @run main XModuleTest */ +import java.nio.file.Files; import java.nio.file.Path; import java.util.Arrays; import java.util.List; import java.util.Set; +import java.util.stream.Collectors; import javax.annotation.processing.AbstractProcessor; import javax.annotation.processing.RoundEnvironment; @@ -69,7 +72,7 @@ tb.createDirectories(classes); String log = new JavacTask(tb) - .options("-Xmodule:java.compiler") + .options("--patch-module", "java.compiler=" + src.toString()) .outdir(classes) .files(findJavaFiles(src)) .run() @@ -81,23 +84,136 @@ } @Test - public void testSourcePath(Path base) throws Exception { + public void testCorrectXModuleMultiModule(Path base) throws Exception { //note: avoiding use of java.base, as that gets special handling on some places: Path src = base.resolve("src"); - tb.writeJavaFiles(src, "package javax.lang.model.element; public interface Extra extends Element, Other { }", "package javax.lang.model.element; interface Other { }"); + Path m1 = src.resolve("m1"); + tb.writeJavaFiles(m1, "package javax.lang.model.element; public interface Extra extends Element { }"); + Path m2 = src.resolve("m2"); + tb.writeJavaFiles(m2, "package com.sun.source.tree; public interface Extra extends Tree { }"); Path classes = base.resolve("classes"); tb.createDirectories(classes); String log = new JavacTask(tb) - .options("-Xmodule:java.compiler", "-sourcepath", src.toString()) + .options("--patch-module", "java.compiler=" + m1.toString(), + "--patch-module", "jdk.compiler=" + m2.toString(), + "--module-source-path", "dummy") .outdir(classes) - .files(src.resolve("javax/lang/model/element/Extra.java")) + .files(findJavaFiles(src)) .run() .writeAll() .getOutput(Task.OutputKind.DIRECT); if (!log.isEmpty()) throw new Exception("expected output not found: " + log); + + checkFileExists(classes, "java.compiler/javax/lang/model/element/Extra.class"); + checkFileExists(classes, "jdk.compiler/com/sun/source/tree/Extra.class"); + } + + @Test + public void testCorrectXModuleMultiModule2(Path base) throws Exception { + //note: avoiding use of java.base, as that gets special handling on some places: + Path src = base.resolve("src"); + Path m1 = src.resolve("m1"); + tb.writeJavaFiles(m1, + "package javax.lang.model.element; public interface Extra extends Element { }"); + Path m2 = src.resolve("m2"); + tb.writeJavaFiles(m2, + "package com.sun.source.tree; public interface Extra extends Tree { }"); + Path msp = base.resolve("msp"); + Path m3 = msp.resolve("m3x"); + tb.writeJavaFiles(m3, + "module m3x { }", + "package m3; public class Test { }"); + Path m4 = msp.resolve("m4x"); + tb.writeJavaFiles(m4, + "module m4x { }", + "package m4; public class Test { }"); + Path classes = base.resolve("classes"); + tb.createDirectories(classes); + + String log = new JavacTask(tb) + .options("--patch-module", "java.compiler=" + m1.toString(), + "--patch-module", "jdk.compiler=" + m2.toString(), + "--module-source-path", msp.toString()) + .outdir(classes) + .files(findJavaFiles(src, msp)) + .run() + .writeAll() + .getOutput(Task.OutputKind.DIRECT); + + if (!log.isEmpty()) + throw new Exception("expected output not found: " + log); + + checkFileExists(classes, "java.compiler/javax/lang/model/element/Extra.class"); + checkFileExists(classes, "jdk.compiler/com/sun/source/tree/Extra.class"); + checkFileExists(classes, "m3x/m3/Test.class"); + checkFileExists(classes, "m4x/m4/Test.class"); + } + + @Test + public void testPatchModuleModuleSourcePathConflict(Path base) throws Exception { + //note: avoiding use of java.base, as that gets special handling on some places: + Path src = base.resolve("src"); + Path m1 = src.resolve("m1x"); + tb.writeJavaFiles(m1, + "module m1x { }", + "package m1; public class Test { }"); + Path m2 = src.resolve("m2x"); + tb.writeJavaFiles(m2, + "module m2x { }", + "package m2; public class Test { }"); + Path classes = base.resolve("classes"); + tb.createDirectories(classes); + + List log = new JavacTask(tb) + .options("--patch-module", "m1x=" + m2.toString(), + "--module-source-path", src.toString(), + "-XDrawDiagnostics") + .outdir(classes) + .files(findJavaFiles(src.resolve("m1x").resolve("m1"), + src.resolve("m2x").resolve("m2"))) + .run(Expect.FAIL) + .writeAll() + .getOutputLines(Task.OutputKind.DIRECT); + + List expectedOut = Arrays.asList( + "Test.java:1:1: compiler.err.file.patched.and.msp: m1x, m2x", + "1 error" + ); + + if (!expectedOut.equals(log)) + throw new Exception("expected output not found: " + log); + } + + @Test + public void testSourcePath(Path base) throws Exception { + //note: avoiding use of java.base, as that gets special handling on some places: + Path src = base.resolve("src"); + tb.writeJavaFiles(src, "package javax.lang.model.element; public interface Extra extends Element, Other { }"); + Path srcPath = base.resolve("src-path"); + tb.writeJavaFiles(srcPath, "package javax.lang.model.element; interface Other { }"); + Path classes = base.resolve("classes"); + tb.createDirectories(classes); + + List log = new JavacTask(tb) + .options("--patch-module", "java.compiler=" + src.toString(), + "-sourcepath", srcPath.toString(), + "-XDrawDiagnostics") + .outdir(classes) + .files(src.resolve("javax/lang/model/element/Extra.java")) + .run(Expect.FAIL) + .writeAll() + .getOutputLines(Task.OutputKind.DIRECT); + + List expectedOut = Arrays.asList( + "Extra.java:1:75: compiler.err.cant.resolve: kindname.class, Other, , ", + "1 error" + ); + + if (!expectedOut.equals(log)) + throw new Exception("expected output not found: " + log); } @Test @@ -124,7 +240,7 @@ tb.createDirectories(classes); List log = new JavacTask(tb) - .options("-Xmodule:java.compiler", + .options("--patch-module", "java.compiler=" + src.toString(), "--class-path", cpClasses.toString(), "-XDrawDiagnostics") .outdir(classes) @@ -152,16 +268,37 @@ Path classes = base.resolve("classes"); tb.createDirectories(classes); - List log = new JavacTask(tb) - .options("-XDrawDiagnostics", "-Xmodule:java.compiler") + List log; + List expected; + + log = new JavacTask(tb) + .options("-XDrawDiagnostics", + "--patch-module", "java.compiler=" + src.toString()) + .outdir(classes) + .files(findJavaFiles(src)) + .run(Task.Expect.FAIL) + .writeAll() + .getOutputLines(Task.OutputKind.DIRECT); + + expected = Arrays.asList("Extra.java:1:1: compiler.err.module-info.with.patched.module.sourcepath", + "1 error"); + + if (!expected.equals(log)) + throw new Exception("expected output not found: " + log); + + //multi-module mode: + log = new JavacTask(tb) + .options("-XDrawDiagnostics", + "--patch-module", "java.compiler=" + src.toString(), + "--module-source-path", "dummy") .outdir(classes) .files(findJavaFiles(src)) .run(Task.Expect.FAIL) .writeAll() .getOutputLines(Task.OutputKind.DIRECT); - List expected = Arrays.asList("Extra.java:1:1: compiler.err.module-info.with.xmodule.sourcepath", - "1 error"); + expected = Arrays.asList("- compiler.err.locn.module-info.not.allowed.on.patch.path: module-info.java", + "1 error"); if (!expected.equals(log)) throw new Exception("expected output not found: " + log); @@ -173,7 +310,7 @@ Path srcMod = base.resolve("src-mod"); tb.writeJavaFiles(srcMod, "module mod {}"); - Path classes = base.resolve("classes"); + Path classes = base.resolve("classes").resolve("java.compiler"); tb.createDirectories(classes); String logMod = new JavacTask(tb) @@ -192,62 +329,36 @@ "package javax.lang.model.element; public interface Extra { }"); tb.createDirectories(classes); - List log = new JavacTask(tb) - .options("-XDrawDiagnostics", "-Xmodule:java.compiler") - .outdir(classes) - .files(findJavaFiles(src)) - .run(Task.Expect.FAIL) - .writeAll() - .getOutputLines(Task.OutputKind.DIRECT); - - List expected = Arrays.asList("Extra.java:1:1: compiler.err.module-info.with.xmodule.classpath", - "1 error"); + List log; + List expected; - if (!expected.equals(log)) - throw new Exception("expected output not found: " + log); - } - - @Test - public void testModuleSourcePathXModule(Path base) throws Exception { - //note: avoiding use of java.base, as that gets special handling on some places: - Path src = base.resolve("src"); - tb.writeJavaFiles(src, "package javax.lang.model.element; public interface Extra extends Element { }"); - Path classes = base.resolve("classes"); - tb.createDirectories(classes); - - List log = new JavacTask(tb) - .options("-XDrawDiagnostics", "-Xmodule:java.compiler", "--module-source-path", src.toString()) + log = new JavacTask(tb) + .options("-XDrawDiagnostics", + "--patch-module", "java.compiler=" + src.toString()) .outdir(classes) .files(findJavaFiles(src)) .run(Task.Expect.FAIL) .writeAll() .getOutputLines(Task.OutputKind.DIRECT); - List expected = Arrays.asList("- compiler.err.xmodule.no.module.sourcepath"); + expected = Arrays.asList("Extra.java:1:1: compiler.err.module-info.with.patched.module.classoutput", + "1 error"); if (!expected.equals(log)) throw new Exception("expected output not found: " + log); - } - @Test - public void testXModuleTooMany(Path base) throws Exception { - //note: avoiding use of java.base, as that gets special handling on some places: - Path src = base.resolve("src"); - tb.writeJavaFiles(src, "package javax.lang.model.element; public interface Extra extends Element { }"); - Path classes = base.resolve("classes"); - tb.createDirectories(classes); - - List log = new JavacTask(tb, Task.Mode.CMDLINE) - .options("-XDrawDiagnostics", "-Xmodule:java.compiler", "-Xmodule:java.compiler") - .outdir(classes) + log = new JavacTask(tb) + .options("-XDrawDiagnostics", + "--patch-module", "java.compiler=" + src.toString(), + "--module-source-path", "dummy") + .outdir(classes.getParent()) .files(findJavaFiles(src)) .run(Task.Expect.FAIL) .writeAll() .getOutputLines(Task.OutputKind.DIRECT); - List expected = Arrays.asList("javac: option -Xmodule: can only be specified once", - "Usage: javac ", - "use --help for a list of possible options"); + expected = Arrays.asList("- compiler.err.locn.module-info.not.allowed.on.patch.path: module-info.class", + "1 error"); if (!expected.equals(log)) throw new Exception("expected output not found: " + log); @@ -266,7 +377,7 @@ new JavacTask(tb, Task.Mode.CMDLINE) .options("--module-path", modules.toString(), - "-Xmodule:m1") + "--patch-module", "m1=" + src.toString()) .files(findJavaFiles(src)) .run() .writeAll(); @@ -282,7 +393,7 @@ List log = new JavacTask(tb, Task.Mode.CMDLINE) .options("-XDrawDiagnostics", "--module-path", modules.toString(), - "-Xmodule:m1") + "--patch-module", "m1=" + src2.toString()) .files(findJavaFiles(src2)) .run(Task.Expect.FAIL) .writeAll() @@ -315,7 +426,7 @@ new JavacTask(tb, Task.Mode.CMDLINE) .options("--module-path", modules.toString(), "--upgrade-module-path", upgrade.toString(), - "-Xmodule:m1") + "--patch-module", "m1=" + src.toString()) .files(findJavaFiles(src)) .run() .writeAll(); @@ -365,7 +476,7 @@ tb.createDirectories(classes); String log = new JavacTask(tb) - .options("-Xmodule:m", + .options("--patch-module", "m=" + sourcePath.toString(), "--class-path", classPath.toString(), "--source-path", sourcePath.toString(), "--module-path", modulePath.toString(), @@ -419,4 +530,165 @@ } } + @Test + public void testSingleModeIncremental(Path base) throws Exception { + //note: avoiding use of java.base, as that gets special handling on some places: + Path src = base.resolve("src"); + tb.writeJavaFiles(src, + "package javax.lang.model.element; public interface Extra extends Element { }", + "package javax.lang.model.element; public interface Extra2 extends Extra { }"); + Path classes = base.resolve("classes"); + tb.createDirectories(classes); + + Thread.sleep(2000); //ensure newer timestamps on classfiles: + + new JavacTask(tb) + .options("--patch-module", "java.compiler=" + src.toString()) + .outdir(classes) + .files(findJavaFiles(src)) + .run() + .writeAll() + .getOutput(Task.OutputKind.DIRECT); + + List log = new JavacTask(tb) + .options("--patch-module", "java.compiler=" + src.toString(), + "-verbose") + .outdir(classes) + .files(findJavaFiles(src.resolve("javax/lang/model/element/Extra2.java" + .replace("/", src.getFileSystem().getSeparator())))) + .run() + .writeAll() + .getOutputLines(Task.OutputKind.DIRECT) + .stream() + .filter(l -> l.contains("parsing")) + .collect(Collectors.toList()); + + boolean parsesExtra2 = log.stream() + .anyMatch(l -> l.contains("Extra2.java")); + boolean parsesExtra = log.stream() + .anyMatch(l -> l.contains("Extra.java")); + + if (!parsesExtra2 || parsesExtra) { + throw new AssertionError("Unexpected output: " + log); + } + } + + @Test + public void testComplexMSPAndPatch(Path base) throws Exception { + //note: avoiding use of java.base, as that gets special handling on some places: + Path src1 = base.resolve("src1"); + Path src1ma = src1.resolve("ma"); + tb.writeJavaFiles(src1ma, + "module ma { exports ma; }", + "package ma; public class C1 { public static void method() { } }", + "package ma.impl; public class C2 { }"); + Path src1mb = src1.resolve("mb"); + tb.writeJavaFiles(src1mb, + "module mb { requires ma; }", + "package mb.impl; public class C2 { public static void method() { } }"); + Path src1mc = src1.resolve("mc"); + tb.writeJavaFiles(src1mc, + "module mc { }"); + Path classes1 = base.resolve("classes1"); + tb.createDirectories(classes1); + tb.cleanDirectory(classes1); + + new JavacTask(tb) + .options("--module-source-path", src1.toString()) + .files(findJavaFiles(src1)) + .outdir(classes1) + .run() + .writeAll(); + + //patching: + Path src2 = base.resolve("src2"); + Path src2ma = src2.resolve("ma"); + tb.writeJavaFiles(src2ma, + "package ma.impl; public class C2 { public static void extra() { ma.C1.method(); } }", + "package ma.impl; public class C3 { public void test() { C2.extra(); } }"); + Path src2mb = src2.resolve("mb"); + tb.writeJavaFiles(src2mb, + "package mb.impl; public class C3 { public void test() { C2.method(); ma.C1.method(); ma.impl.C2.extra(); } }"); + Path src2mc = src2.resolve("mc"); + tb.writeJavaFiles(src2mc, + "package mc.impl; public class C2 { public static void test() { } }", + //will require --add-reads ma: + "package mc.impl; public class C3 { public static void test() { ma.impl.C2.extra(); } }"); + Path src2mt = src2.resolve("mt"); + tb.writeJavaFiles(src2mt, + "module mt { requires ma; requires mb; }", + "package mt.impl; public class C2 { public static void test() { mb.impl.C2.method(); ma.impl.C2.extra(); } }", + "package mt.impl; public class C3 { public static void test() { C2.test(); mc.impl.C2.test(); } }"); + Path classes2 = base.resolve("classes2"); + tb.createDirectories(classes2); + tb.cleanDirectory(classes2); + + Thread.sleep(2000); //ensure newer timestamps on classfiles: + + new JavacTask(tb) + .options("--module-path", classes1.toString(), + "--patch-module", "ma=" + src2ma.toString(), + "--patch-module", "mb=" + src2mb.toString(), + "--add-exports", "ma/ma.impl=mb", + "--patch-module", "mc=" + src2mc.toString(), + "--add-reads", "mc=ma", + "--add-exports", "ma/ma.impl=mc", + "--add-exports", "ma/ma.impl=mt", + "--add-exports", "mb/mb.impl=mt", + "--add-exports", "mc/mc.impl=mt", + "--add-reads", "mt=mc", + "--module-source-path", src2.toString()) + .outdir(classes2) + .files(findJavaFiles(src2)) + .run() + .writeAll(); + + //incremental compilation (C2 mustn't be compiled, C3 must): + tb.writeJavaFiles(src2ma, + "package ma.impl; public class C3 { public void test() { ma.C1.method(); C2.extra(); } }"); + tb.writeJavaFiles(src2mt, + "package mt.impl; public class C3 { public static void test() { mc.impl.C2.test(); C2.test(); } }"); + + List log = new JavacTask(tb) + .options("--module-path", classes1.toString(), + "--patch-module", "ma=" + src2ma.toString(), + "--patch-module", "mb=" + src2mb.toString(), + "--add-exports", "ma/ma.impl=mb", + "--patch-module", "mc=" + src2mc.toString(), + "--add-reads", "mc=ma", + "--add-exports", "ma/ma.impl=mc", + "--add-exports", "ma/ma.impl=mt", + "--add-exports", "mb/mb.impl=mt", + "--add-exports", "mc/mc.impl=mt", + "--add-reads", "mt=mc", + "--module-source-path", src2.toString(), + "--add-modules", "mc", + "-verbose") + .outdir(classes2) + .files(src2ma.resolve("ma").resolve("impl").resolve("C3.java"), + src2mt.resolve("mt").resolve("impl").resolve("C3.java")) + .run() + .writeAll() + .getOutputLines(Task.OutputKind.DIRECT) + .stream() + .filter(l -> l.contains("parsing")) + .collect(Collectors.toList()); + + boolean parsesC3 = log.stream() + .anyMatch(l -> l.contains("C3.java")); + boolean parsesC2 = log.stream() + .anyMatch(l -> l.contains("C2.java")); + + if (!parsesC3 || parsesC2) { + throw new AssertionError("Unexpected output: " + log); + } + } + + private void checkFileExists(Path dir, String path) { + Path toCheck = dir.resolve(path.replace("/", dir.getFileSystem().getSeparator())); + + if (!Files.exists(toCheck)) { + throw new AssertionError(toCheck.toString() + " does not exist!"); + } + } }