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 8158123 8161906 8162713 27 * @summary tests for module declarations 28 * @library /tools/lib 29 * @modules 30 * jdk.compiler/com.sun.tools.javac.api 31 * jdk.compiler/com.sun.tools.javac.main 32 * jdk.jdeps/com.sun.tools.javap 33 * @build toolbox.ToolBox toolbox.JavacTask ModuleTestBase 34 * @run main ModuleInfoTest 35 */ 36 37 import java.io.IOException; 38 import java.nio.file.Files; 39 import java.nio.file.Path; 40 import java.util.Arrays; 41 42 import toolbox.JavacTask; 43 import toolbox.Task; 44 import toolbox.ToolBox; 45 46 public class ModuleInfoTest extends ModuleTestBase { 47 48 public static void main(String... args) throws Exception { 49 ModuleInfoTest t = new ModuleInfoTest(); 50 t.runTests(); 51 } 52 53 /** 54 * Check error message if module declaration not in module-info.java. 55 */ 56 @Test 57 public void testModuleDeclNotInModuleJava(Path base) throws Exception { 58 Path src = base.resolve("src"); 59 tb.writeFile(src.resolve("M.java"), "module M { }"); 60 String log = new JavacTask(tb) 61 .options("-XDrawDiagnostics") 62 .files(findJavaFiles(src)) 63 .run(Task.Expect.FAIL) 64 .writeAll() 65 .getOutput(Task.OutputKind.DIRECT); 66 67 if (!log.contains("M.java:1:1: compiler.err.module.decl.sb.in.module-info.java")) 68 throw new Exception("expected output not found"); 69 } 70 71 /** 72 * Verify that a package private class can be put in module-info.java. 73 */ 74 @Test 75 public void testNotModuleDeclInModuleJava_1(Path base) throws Exception { 76 Path src = base.resolve("src"); 77 tb.writeFile(src.resolve("module-info.java"), "class C { }"); 78 new JavacTask(tb) 79 .options("-XDrawDiagnostics") 80 .files(findJavaFiles(src)) 81 .run() 82 .writeAll(); 83 } 84 85 /** 86 * Verify that a public class cannot be put in module-info.java. 87 */ 88 @Test 89 public void testNotModuleDeclInModuleJava_2(Path base) throws Exception { 90 Path src = base.resolve("src"); 91 tb.writeFile(src.resolve("module-info.java"), "public class C { }"); 92 String log = new JavacTask(tb) 93 .options("-XDrawDiagnostics") 94 .files(findJavaFiles(src)) 95 .run(Task.Expect.FAIL) 96 .writeAll() 97 .getOutput(Task.OutputKind.DIRECT); 98 99 if (!log.contains("module-info.java:1:8: compiler.err.class.public.should.be.in.file: C")) 100 throw new Exception("expected output not found"); 101 } 102 103 /** 104 * Verify that only one module decl can be put in module-info.java. 105 */ 106 @Test 107 public void testSingleModuleDecl(Path base) throws Exception { 108 Path src = base.resolve("src"); 109 tb.writeJavaFiles(src, "module M1 { } /*...*/ module M2 { }"); 110 String log = new JavacTask(tb) 111 .options("-XDrawDiagnostics") 112 .files(findJavaFiles(src)) 113 .run(Task.Expect.FAIL) 114 .writeAll() 115 .getOutput(Task.OutputKind.DIRECT); 116 117 if (!log.contains("module-info.java:1:14: compiler.err.expected: token.end-of-input")) 118 throw new Exception("expected output not found"); 119 } 120 121 /** 122 * Verify that missing requires are reported. 123 */ 124 @Test 125 public void testRequiresNotFound(Path base) throws Exception { 126 Path src = base.resolve("src"); 127 tb.writeJavaFiles(src, "module M1 { requires M2; }"); 128 String log = new JavacTask(tb) 129 .options("-XDrawDiagnostics") 130 .files(findJavaFiles(src)) 131 .run(Task.Expect.FAIL) 132 .writeAll() 133 .getOutput(Task.OutputKind.DIRECT); 134 135 if (!log.contains("module-info.java:1:22: compiler.err.module.not.found: M2")) 136 throw new Exception("expected output not found"); 137 } 138 139 /** 140 * Verify that missing exports are reported. 141 */ 142 @Test 143 public void testExportsNotFound(Path base) throws Exception { 144 Path src = base.resolve("src"); 145 tb.writeJavaFiles(src, "module M1 { exports p to M2; }"); 146 String log = new JavacTask(tb) 147 .options("-XDrawDiagnostics") 148 .files(findJavaFiles(src)) 149 .run(Task.Expect.FAIL) 150 .writeAll() 151 .getOutput(Task.OutputKind.DIRECT); 152 153 if (!log.contains("module-info.java:1:26: compiler.err.module.not.found: M2")) 154 throw new Exception("expected output not found"); 155 } 156 157 /** 158 * Verify that a simple loop is detected. 159 */ 160 @Test 161 public void testRequiresSelf(Path base) throws Exception { 162 Path src = base.resolve("src"); 163 tb.writeJavaFiles(src, "module M { requires M; }"); 164 String log = new JavacTask(tb) 165 .options("-XDrawDiagnostics") 166 .files(findJavaFiles(src)) 167 .run(Task.Expect.FAIL) 168 .writeAll() 169 .getOutput(Task.OutputKind.DIRECT); 170 171 if (!log.contains("module-info.java:1:21: compiler.err.cyclic.requires: M")) 172 throw new Exception("expected output not found"); 173 } 174 175 /** 176 * Verify that a multi-module loop is detected. 177 */ 178 @Test 179 public void testRequiresLoop(Path base) throws Exception { 180 Path src = base.resolve("src"); 181 Path src_m1 = src.resolve("m1"); 182 tb.writeFile(src_m1.resolve("module-info.java"), "module m1 { requires m2; }"); 183 Path src_m2 = src.resolve("m2"); 184 tb.writeFile(src_m2.resolve("module-info.java"), "module m2 { requires m3; }"); 185 Path src_m3 = src.resolve("m3"); 186 tb.writeFile(src_m3.resolve("module-info.java"), "module m3 { requires m1; }"); 187 188 Path classes = base.resolve("classes"); 189 Files.createDirectories(classes); 190 191 String log = new JavacTask(tb) 192 .options("-XDrawDiagnostics", "--module-source-path", src.toString()) 193 .outdir(classes) 194 .files(findJavaFiles(src)) 195 .run(Task.Expect.FAIL) 196 .writeAll() 197 .getOutput(Task.OutputKind.DIRECT); 198 199 if (!log.contains("module-info.java:1:22: compiler.err.cyclic.requires: m3")) 200 throw new Exception("expected output not found"); 201 } 202 203 /** 204 * Verify that a multi-module loop is detected. 205 */ 206 @Test 207 public void testRequiresTransitiveLoop(Path base) throws Exception { 208 Path src = base.resolve("src"); 209 Path src_m1 = src.resolve("m1"); 210 tb.writeFile(src_m1.resolve("module-info.java"), "module m1 { requires m2; }"); 211 Path src_m2 = src.resolve("m2"); 212 tb.writeFile(src_m2.resolve("module-info.java"), "module m2 { requires transitive m3; }"); 213 Path src_m3 = src.resolve("m3"); 214 tb.writeFile(src_m3.resolve("module-info.java"), "module m3 { requires m1; }"); 215 216 Path classes = base.resolve("classes"); 217 Files.createDirectories(classes); 218 219 String log = new JavacTask(tb) 220 .options("-XDrawDiagnostics", "--module-source-path", src.toString()) 221 .outdir(classes) 222 .files(findJavaFiles(src)) 223 .run(Task.Expect.FAIL) 224 .writeAll() 225 .getOutput(Task.OutputKind.DIRECT); 226 227 if (!log.contains("module-info.java:1:33: compiler.err.cyclic.requires: m3")) 228 throw new Exception("expected output not found"); 229 } 230 231 /** 232 * Verify that duplicate requires are detected. 233 */ 234 @Test 235 public void testDuplicateRequires(Path base) throws Exception { 236 Path src = base.resolve("src"); 237 Path src_m1 = src.resolve("m1"); 238 tb.writeFile(src_m1.resolve("module-info.java"), "module m1 { }"); 239 Path src_m2 = src.resolve("m2"); 240 tb.writeFile(src_m2.resolve("module-info.java"), "module m2 { requires m1; requires m1; }"); 241 242 Path classes = base.resolve("classes"); 243 Files.createDirectories(classes); 244 245 String log = new JavacTask(tb) 246 .options("-XDrawDiagnostics", "--module-source-path", src.toString()) 247 .outdir(classes) 248 .files(findJavaFiles(src)) 249 .run(Task.Expect.FAIL) 250 .writeAll() 251 .getOutput(Task.OutputKind.DIRECT); 252 253 if (!log.contains("module-info.java:1:35: compiler.err.duplicate.requires: m1")) 254 throw new Exception("expected output not found"); 255 } 256 257 /** 258 * Verify that duplicate requires are detected. 259 */ 260 @Test 261 public void testDuplicateRequiresTransitiveStatic(Path base) throws Exception { 262 Path src = base.resolve("src"); 263 Path src_m1 = src.resolve("m1"); 264 tb.writeFile(src_m1.resolve("module-info.java"), "module m1 { }"); 265 Path src_m2 = src.resolve("m2"); 266 tb.writeFile(src_m2.resolve("module-info.java"), "module m2 { requires transitive m1; requires static m1; }"); 267 268 Path classes = base.resolve("classes"); 269 Files.createDirectories(classes); 270 271 String log = new JavacTask(tb) 272 .options("-XDrawDiagnostics", "--module-source-path", src.toString()) 273 .outdir(classes) 274 .files(findJavaFiles(src)) 275 .run(Task.Expect.FAIL) 276 .writeAll() 277 .getOutput(Task.OutputKind.DIRECT); 278 279 if (!log.contains("module-info.java:1:53: compiler.err.duplicate.requires: m1")) 280 throw new Exception("expected output not found"); 281 } 282 283 /** 284 * Verify that duplicate exported packages are detected correctly. 285 */ 286 @Test 287 public void testConflictingExports_packages(Path base) throws Exception { 288 verifyConflictingExports_packages(base, 289 "exports p; exports q;", 290 null); 291 verifyConflictingExports_packages(base, 292 "exports p; exports p;", 293 "module-info.java:1:32: compiler.err.conflicting.exports: p"); 294 verifyConflictingExports_packages(base, 295 "exports p; opens p;", 296 null); 297 verifyConflictingExports_packages(base, 298 "exports p; exports p to m2;", 299 "module-info.java:1:32: compiler.err.conflicting.exports: p"); 300 verifyConflictingExports_packages(base, 301 "exports p; opens p to m2;", 302 null); 303 verifyConflictingExports_packages(base, 304 "opens p; exports p;", 305 null); 306 verifyConflictingExports_packages(base, 307 "opens p; opens p;", 308 "module-info.java:1:28: compiler.err.conflicting.opens: p"); 309 verifyConflictingExports_packages(base, 310 "opens p; exports p to m2;", 311 null); 312 verifyConflictingExports_packages(base, 313 "opens p; opens p to m2;", 314 "module-info.java:1:28: compiler.err.conflicting.opens: p"); 315 verifyConflictingExports_packages(base, 316 "exports p to m2; exports p;", 317 "module-info.java:1:38: compiler.err.conflicting.exports: p"); 318 verifyConflictingExports_packages(base, 319 "exports p to m2; opens p;", 320 null); 321 verifyConflictingExports_packages(base, 322 "exports p to m2; exports p to m2;", 323 "module-info.java:1:43: compiler.err.conflicting.exports.to.module: m2"); 324 verifyConflictingExports_packages(base, 325 "exports p to m2; opens p to m2;", 326 null); 327 verifyConflictingExports_packages(base, 328 "opens p to m2; exports p;", 329 null); 330 verifyConflictingExports_packages(base, 331 "opens p to m2; opens p;", 332 "module-info.java:1:34: compiler.err.conflicting.opens: p"); 333 verifyConflictingExports_packages(base, 334 "opens p to m2; exports p to m2;", 335 null); 336 verifyConflictingExports_packages(base, 337 "opens p to m2; opens p to m2;", 338 "module-info.java:1:34: compiler.err.conflicting.opens: p"); 339 verifyConflictingExports_packages(base, 340 "exports p to m2; exports p to m3;", 341 "module-info.java:1:38: compiler.err.conflicting.exports: p"); 342 verifyConflictingExports_packages(base, 343 "exports p to m2; opens p to m3;", 344 null); 345 verifyConflictingExports_packages(base, 346 "opens p to m2; exports p to m3;", 347 null); 348 verifyConflictingExports_packages(base, 349 "opens p to m2; opens p to m3;", 350 "module-info.java:1:34: compiler.err.conflicting.opens: p"); 351 } 352 353 private void verifyConflictingExports_packages(Path base, String code, String expected) throws Exception { 354 Files.createDirectories(base); 355 tb.cleanDirectory(base); 356 357 Path src = base.resolve("src"); 358 tb.writeJavaFiles(src.resolve("m1"), 359 "module m1 { " + code + " }", 360 "package p; public class P {}", 361 "package q; public class Q {}"); 362 tb.writeJavaFiles(src.resolve("m2"), 363 "module m2 { requires m1; }"); 364 tb.writeJavaFiles(src.resolve("m3"), 365 "module m3 { requires m1; }"); 366 367 Path classes = base.resolve("classes"); 368 Files.createDirectories(classes); 369 370 String log = new JavacTask(tb) 371 .options("-XDrawDiagnostics", 372 "--module-source-path", src.toString()) 373 .outdir(classes) 374 .files(findJavaFiles(src)) 375 .run(expected != null ? Task.Expect.FAIL : Task.Expect.SUCCESS) 376 .writeAll() 377 .getOutput(Task.OutputKind.DIRECT); 378 379 if (expected != null && !log.contains(expected)) 380 throw new Exception("expected output not found, actual output: " + log); 381 } 382 383 /** 384 * Verify that duplicate exported packages are detected. 385 */ 386 @Test 387 public void testConflictingExports_modules(Path base) throws Exception { 388 Path src = base.resolve("src"); 389 Path src_m1 = src.resolve("m1"); 390 tb.writeFile(src_m1.resolve("module-info.java"), "module m1 { }"); 391 Path src_m2 = src.resolve("m2"); 392 tb.writeFile(src_m2.resolve("module-info.java"), "module m2 { exports p to m1, m1; }"); 393 394 Path classes = base.resolve("classes"); 395 Files.createDirectories(classes); 396 397 String log = new JavacTask(tb) 398 .options("-XDrawDiagnostics", "--module-source-path", src.toString()) 399 .outdir(classes) 400 .files(findJavaFiles(src)) 401 .run(Task.Expect.FAIL) 402 .writeAll() 403 .getOutput(Task.OutputKind.DIRECT); 404 405 if (!log.contains("module-info.java:1:30: compiler.err.conflicting.exports.to.module: m1")) 406 throw new Exception("expected output not found"); 407 } 408 409 /** 410 * Verify that annotations are not permitted at 411 * any of the module names or the package names. 412 */ 413 @Test 414 public void testAnnotations(Path base) throws Exception { 415 Path src = base.resolve("src"); 416 Path src_m1 = src.resolve("m1.sub"); 417 Path classes = base.resolve("classes"); 418 Files.createDirectories(classes); 419 420 String code = "module @m1.@sub { " + 421 "requires @p1.@p2; " + 422 "exports @p1.@p2; " + 423 "exports @p1.@p2 to @m2.@sub; " + 424 "exports @p1.@p2 to @m2.@sub, @m3.@sub; " + 425 "uses @p1.@Interface; " + 426 "provides @p1.@Interface with @p2.@Concrete; " + 427 "}"; 428 String[] splittedCode = code.split("@"); 429 int length = splittedCode.length; 430 String anno = "@Anno "; 431 432 for (int i = 1; i < length; i++) { 433 String preAnno = String.join("", Arrays.copyOfRange(splittedCode, 0, i)); 434 String postAnno = String.join("", Arrays.copyOfRange(splittedCode, i, length)); 435 String moduleInfo = preAnno + anno + postAnno; 436 tb.writeFile(src_m1.resolve("module-info.java"), moduleInfo); 437 438 String log = new JavacTask(tb) 439 .options("-XDrawDiagnostics", "--module-source-path", src.toString()) 440 .outdir(classes) 441 .files(findJavaFiles(src)) 442 .run(Task.Expect.FAIL) 443 .writeAll() 444 .getOutput(Task.OutputKind.DIRECT); 445 446 String expect_prefix = "(?s)^module\\-info\\.java:\\d+:\\d+: "; 447 String expect_message = "compiler\\.err\\.expected: token\\.identifier"; 448 String expect_suffix = ".*"; 449 String expect = expect_prefix + expect_message + expect_suffix; 450 if (!log.matches(expect)) 451 throw new Exception("expected output not found for: " + moduleInfo + "; actual: " + log); 452 } 453 } 454 }