1 /*
   2  * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 
  24 /**
  25  * @test
  26  * @bug 8155026
  27  * @summary Test automatic modules
  28  * @library /tools/lib
  29  * @modules
  30  *      jdk.compiler/com.sun.tools.javac.api
  31  *      jdk.compiler/com.sun.tools.javac.main
  32  * @build toolbox.ToolBox toolbox.JavacTask toolbox.JarTask ModuleTestBase
  33  * @run main AutomaticModules
  34  */
  35 
  36 import java.nio.file.Files;
  37 import java.nio.file.Path;
  38 import java.util.Arrays;
  39 import java.util.List;
  40 
  41 import toolbox.JarTask;
  42 import toolbox.JavacTask;
  43 import toolbox.Task;
  44 
  45 public class AutomaticModules extends ModuleTestBase {
  46 
  47     public static void main(String... args) throws Exception {
  48         AutomaticModules t = new AutomaticModules();
  49         t.runTests();
  50     }
  51 
  52     @Test
  53     public void testSimple(Path base) throws Exception {
  54         Path legacySrc = base.resolve("legacy-src");
  55         tb.writeJavaFiles(legacySrc,
  56                           "package api; import java.awt.event.ActionListener; public abstract class Api implements ActionListener {}");
  57         Path legacyClasses = base.resolve("legacy-classes");
  58         Files.createDirectories(legacyClasses);
  59 
  60         String log = new JavacTask(tb)
  61                 .options()
  62                 .outdir(legacyClasses)
  63                 .files(findJavaFiles(legacySrc))
  64                 .run()
  65                 .writeAll()
  66                 .getOutput(Task.OutputKind.DIRECT);
  67 
  68         if (!log.isEmpty()) {
  69             throw new Exception("unexpected output: " + log);
  70         }
  71 
  72         Path modulePath = base.resolve("module-path");
  73 
  74         Files.createDirectories(modulePath);
  75 
  76         Path jar = modulePath.resolve("test-api-1.0.jar");
  77 
  78         new JarTask(tb, jar)
  79           .baseDir(legacyClasses)
  80           .files("api/Api.class")
  81           .run();
  82 
  83         Path moduleSrc = base.resolve("module-src");
  84         Path m1 = moduleSrc.resolve("m1");
  85 
  86         Path classes = base.resolve("classes");
  87 
  88         Files.createDirectories(classes);
  89 
  90         tb.writeJavaFiles(m1,
  91                           "module m1 { requires test.api; requires java.desktop; }",
  92                           "package impl; public class Impl { public void e(api.Api api) { api.actionPerformed(null); } }");
  93 
  94         new JavacTask(tb)
  95                 .options("-doe", "-modulesourcepath", moduleSrc.toString(), "-modulepath", modulePath.toString())
  96                 .outdir(classes)
  97                 .files(findJavaFiles(moduleSrc))
  98                 .run()
  99                 .writeAll();
 100     }
 101 
 102     @Test
 103     public void testUnnamedModule(Path base) throws Exception {
 104         Path legacySrc = base.resolve("legacy-src");
 105         tb.writeJavaFiles(legacySrc,
 106                           "package api; public abstract class Api { public void run(CharSequence str) { } private void run(base.Base base) { } }",
 107                           "package base; public interface Base { public void run(); }");
 108         Path legacyClasses = base.resolve("legacy-classes");
 109         Files.createDirectories(legacyClasses);
 110 
 111         String log = new JavacTask(tb)
 112                 .options()
 113                 .outdir(legacyClasses)
 114                 .files(findJavaFiles(legacySrc))
 115                 .run()
 116                 .writeAll()
 117                 .getOutput(Task.OutputKind.DIRECT);
 118 
 119         if (!log.isEmpty()) {
 120             throw new Exception("unexpected output: " + log);
 121         }
 122 
 123         Path modulePath = base.resolve("module-path");
 124 
 125         Files.createDirectories(modulePath);
 126 
 127         Path apiJar = modulePath.resolve("test-api-1.0.jar");
 128 
 129         new JarTask(tb, apiJar)
 130           .baseDir(legacyClasses)
 131           .files("api/Api.class")
 132           .run();
 133 
 134         Path baseJar = base.resolve("base.jar");
 135 
 136         new JarTask(tb, baseJar)
 137           .baseDir(legacyClasses)
 138           .files("base/Base.class")
 139           .run();
 140 
 141         Path moduleSrc = base.resolve("module-src");
 142         Path m1 = moduleSrc.resolve("m1");
 143 
 144         Path classes = base.resolve("classes");
 145 
 146         Files.createDirectories(classes);
 147 
 148         tb.writeJavaFiles(m1,
 149                           "module m1 { requires test.api; }",
 150                           "package impl; public class Impl { public void e(api.Api api) { api.run(\"\"); } }");
 151 
 152         new JavacTask(tb)
 153                 .options("-modulesourcepath", moduleSrc.toString(), "-modulepath", modulePath.toString(), "-classpath", baseJar.toString())
 154                 .outdir(classes)
 155                 .files(findJavaFiles(moduleSrc))
 156                 .run()
 157                 .writeAll();
 158     }
 159 
 160     @Test
 161     public void testModuleInfoFromClassFileDependsOnAutomatic(Path base) throws Exception {
 162         Path automaticSrc = base.resolve("automaticSrc");
 163         tb.writeJavaFiles(automaticSrc, "package api; public class Api {}");
 164         Path automaticClasses = base.resolve("automaticClasses");
 165         tb.createDirectories(automaticClasses);
 166 
 167         String automaticLog = new JavacTask(tb)
 168                                 .outdir(automaticClasses)
 169                                 .files(findJavaFiles(automaticSrc))
 170                                 .run()
 171                                 .writeAll()
 172                                 .getOutput(Task.OutputKind.DIRECT);
 173 
 174         if (!automaticLog.isEmpty())
 175             throw new Exception("expected output not found: " + automaticLog);
 176 
 177         Path modulePath = base.resolve("module-path");
 178 
 179         Files.createDirectories(modulePath);
 180 
 181         Path automaticJar = modulePath.resolve("automatic-1.0.jar");
 182 
 183         new JarTask(tb, automaticJar)
 184           .baseDir(automaticClasses)
 185           .files("api/Api.class")
 186           .run();
 187 
 188         Path depSrc = base.resolve("depSrc");
 189         Path depClasses = base.resolve("depClasses");
 190 
 191         Files.createDirectories(depSrc);
 192         Files.createDirectories(depClasses);
 193 
 194         tb.writeJavaFiles(depSrc,
 195                           "module m1 { requires public automatic; }",
 196                           "package dep; public class Dep { api.Api api; }");
 197 
 198         new JavacTask(tb)
 199                 .options("-modulepath", modulePath.toString())
 200                 .outdir(depClasses)
 201                 .files(findJavaFiles(depSrc))
 202                 .run()
 203                 .writeAll();
 204 
 205         Path moduleJar = modulePath.resolve("m1.jar");
 206 
 207         new JarTask(tb, moduleJar)
 208           .baseDir(depClasses)
 209           .files("module-info.class", "dep/Dep.class")
 210           .run();
 211 
 212         Path testSrc = base.resolve("testSrc");
 213         Path testClasses = base.resolve("testClasses");
 214 
 215         Files.createDirectories(testSrc);
 216         Files.createDirectories(testClasses);
 217 
 218         tb.writeJavaFiles(testSrc,
 219                           "module m2 { requires automatic; }",
 220                           "package test; public class Test { }");
 221 
 222         new JavacTask(tb)
 223                 .options("-modulepath", modulePath.toString())
 224                 .outdir(testClasses)
 225                 .files(findJavaFiles(testSrc))
 226                 .run()
 227                 .writeAll();
 228     }
 229 
 230     @Test
 231     void testAutomaticAndNamedModules(Path base) throws Exception {
 232         Path modulePath = base.resolve("module-path");
 233 
 234         Files.createDirectories(modulePath);
 235 
 236         for (char c : new char[] {'A', 'B'}) {
 237             Path automaticSrc = base.resolve("automaticSrc" + c);
 238             tb.writeJavaFiles(automaticSrc, "package api" + c + "; public class Api {}");
 239             Path automaticClasses = base.resolve("automaticClasses" + c);
 240             tb.createDirectories(automaticClasses);
 241 
 242             String automaticLog = new JavacTask(tb)
 243                                     .outdir(automaticClasses)
 244                                     .files(findJavaFiles(automaticSrc))
 245                                     .run()
 246                                     .writeAll()
 247                                     .getOutput(Task.OutputKind.DIRECT);
 248 
 249             if (!automaticLog.isEmpty())
 250                 throw new Exception("expected output not found: " + automaticLog);
 251 
 252             Path automaticJar = modulePath.resolve("automatic" + c + "-1.0.jar");
 253 
 254             new JarTask(tb, automaticJar)
 255               .baseDir(automaticClasses)
 256               .files("api" + c + "/Api.class")
 257               .run();
 258         }
 259 
 260         Path moduleSrc = base.resolve("module-src");
 261 
 262         tb.writeJavaFiles(moduleSrc.resolve("m1"),
 263                           "module m1 { requires automaticA; }",
 264                           "package impl; public class Impl { apiA.Api a; apiB.Api b; m2.M2 m;}");
 265 
 266         tb.writeJavaFiles(moduleSrc.resolve("m2"),
 267                           "module m2 { exports m2; }",
 268                           "package m2; public class M2 { }");
 269 
 270         Path classes = base.resolve("classes");
 271 
 272         Files.createDirectories(classes);
 273 
 274         List<String> log = new JavacTask(tb)
 275                 .options("-modulesourcepath", moduleSrc.toString(),
 276                          "-modulepath", modulePath.toString(),
 277                          "-addmods", "automaticB",
 278                          "-XDrawDiagnostics")
 279                 .outdir(classes)
 280                 .files(findJavaFiles(moduleSrc))
 281                 .run(Task.Expect.FAIL)
 282                 .writeAll()
 283                 .getOutputLines(Task.OutputKind.DIRECT);
 284 
 285         List<String> expected = Arrays.asList("Impl.java:1:61: compiler.err.not.def.access.package.cant.access: m2.M2, m2",
 286                                               "1 error");
 287 
 288         if (!expected.equals(log)) {
 289             throw new Exception("expected output not found: " + log);
 290         }
 291 
 292         log = new JavacTask(tb)
 293                 .options("-modulesourcepath", moduleSrc.toString(),
 294                          "-modulepath", modulePath.toString(),
 295                          "-XDrawDiagnostics")
 296                 .outdir(classes)
 297                 .files(findJavaFiles(moduleSrc))
 298                 .run(Task.Expect.FAIL)
 299                 .writeAll()
 300                 .getOutputLines(Task.OutputKind.DIRECT);
 301 
 302         expected = Arrays.asList("Impl.java:1:51: compiler.err.doesnt.exist: apiB",
 303                                  "Impl.java:1:61: compiler.err.not.def.access.package.cant.access: m2.M2, m2",
 304                                  "2 errors");
 305 
 306         if (!expected.equals(log)) {
 307             throw new Exception("expected output not found: " + log);
 308         }
 309     }
 310 }