ModuleInfoTest.java revision 3965:c80dce0bcab4
1/* 2 * Copyright (c) 2015, 2017, 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 37import java.nio.file.Files; 38import java.nio.file.Path; 39import java.util.Arrays; 40 41import toolbox.JavacTask; 42import toolbox.Task; 43 44public class ModuleInfoTest extends ModuleTestBase { 45 46 public static void main(String... args) throws Exception { 47 ModuleInfoTest t = new ModuleInfoTest(); 48 t.runTests(); 49 } 50 51 /** 52 * Check error message if module declaration not in module-info.java. 53 */ 54 @Test 55 public void testModuleDeclNotInModuleJava(Path base) throws Exception { 56 Path src = base.resolve("src"); 57 tb.writeFile(src.resolve("M.java"), "module M { }"); 58 String log = new JavacTask(tb) 59 .options("-XDrawDiagnostics") 60 .files(findJavaFiles(src)) 61 .run(Task.Expect.FAIL) 62 .writeAll() 63 .getOutput(Task.OutputKind.DIRECT); 64 65 if (!log.contains("M.java:1:1: compiler.err.module.decl.sb.in.module-info.java")) 66 throw new Exception("expected output not found"); 67 } 68 69 /** 70 * Verify that a package private class can be put in module-info.java. 71 */ 72 @Test 73 public void testNotModuleDeclInModuleJava_1(Path base) throws Exception { 74 Path src = base.resolve("src"); 75 tb.writeFile(src.resolve("module-info.java"), "class C { }"); 76 new JavacTask(tb) 77 .options("-XDrawDiagnostics") 78 .files(findJavaFiles(src)) 79 .run() 80 .writeAll(); 81 } 82 83 /** 84 * Verify that a public class cannot be put in module-info.java. 85 */ 86 @Test 87 public void testNotModuleDeclInModuleJava_2(Path base) throws Exception { 88 Path src = base.resolve("src"); 89 tb.writeFile(src.resolve("module-info.java"), "public class C { }"); 90 String log = new JavacTask(tb) 91 .options("-XDrawDiagnostics") 92 .files(findJavaFiles(src)) 93 .run(Task.Expect.FAIL) 94 .writeAll() 95 .getOutput(Task.OutputKind.DIRECT); 96 97 if (!log.contains("module-info.java:1:8: compiler.err.class.public.should.be.in.file: kindname.class, C")) 98 throw new Exception("expected output not found"); 99 } 100 101 /** 102 * Verify that only one module decl can be put in module-info.java. 103 */ 104 @Test 105 public void testSingleModuleDecl(Path base) throws Exception { 106 Path src = base.resolve("src"); 107 tb.writeJavaFiles(src, "module M1 { } /*...*/ module M2 { }"); 108 String log = new JavacTask(tb) 109 .options("-XDrawDiagnostics") 110 .files(findJavaFiles(src)) 111 .run(Task.Expect.FAIL) 112 .writeAll() 113 .getOutput(Task.OutputKind.DIRECT); 114 115 if (!log.contains("module-info.java:1:14: compiler.err.expected: token.end-of-input")) 116 throw new Exception("expected output not found"); 117 } 118 119 /** 120 * Verify that missing requires are reported. 121 */ 122 @Test 123 public void testRequiresNotFound(Path base) throws Exception { 124 Path src = base.resolve("src"); 125 tb.writeJavaFiles(src, "module M1 { requires M2; }"); 126 String log = new JavacTask(tb) 127 .options("-XDrawDiagnostics") 128 .files(findJavaFiles(src)) 129 .run(Task.Expect.FAIL) 130 .writeAll() 131 .getOutput(Task.OutputKind.DIRECT); 132 133 if (!log.contains("module-info.java:1:22: compiler.err.module.not.found: M2")) 134 throw new Exception("expected output not found"); 135 } 136 137 /** 138 * Verify that missing exports targets are reported. 139 */ 140 @Test 141 public void testExportsNotFound(Path base) throws Exception { 142 Path src = base.resolve("src"); 143 tb.writeJavaFiles(src, 144 "module M { exports p to N; }", 145 "package p; public class C {}"); 146 String log = new JavacTask(tb) 147 .options("-XDrawDiagnostics", 148 "-Xlint:module") 149 .files(findJavaFiles(src)) 150 .run() 151 .writeAll() 152 .getOutput(Task.OutputKind.DIRECT); 153 154 if (!log.contains("module-info.java:1:25: compiler.warn.module.not.found: N")) 155 throw new Exception("expected output not found, actual output: " + log); 156 } 157 158 /** 159 * Verify that duplicated qualified missing exports targets are reported. 160 */ 161 @Test 162 public void testExportsNotFoundDuplicated(Path base) throws Exception { 163 Path src = base.resolve("src"); 164 tb.writeJavaFiles(src, 165 "module M { exports p to N, N; }", 166 "package p; public class C {}"); 167 String log = new JavacTask(tb) 168 .options("-XDrawDiagnostics", 169 "-Xlint:module") 170 .files(findJavaFiles(src)) 171 .run(Task.Expect.FAIL) 172 .writeAll() 173 .getOutput(Task.OutputKind.DIRECT); 174 175 if (!log.contains("module-info.java:1:28: compiler.err.conflicting.exports.to.module: N")) 176 throw new Exception("expected output not found, actual output: " + log); 177 } 178 179 /** 180 * Verify that missing exports target warning can be suppressed. 181 */ 182 @Test 183 public void testExportsNotFoundSuppress(Path base) throws Exception { 184 Path src = base.resolve("src"); 185 tb.writeJavaFiles(src, 186 "@SuppressWarnings(\"module\") module M { exports p to N; }", 187 "package p; public class C {}"); 188 String log = new JavacTask(tb) 189 .options("-XDrawDiagnostics", 190 "-Xlint:module") 191 .files(findJavaFiles(src)) 192 .run() 193 .writeAll() 194 .getOutput(Task.OutputKind.DIRECT); 195 196 if (!log.isEmpty()) 197 throw new Exception("expected output not found, actual output: " + log); 198 } 199 200 /** 201 * Verify that missing opens targets are reported. 202 */ 203 @Test 204 public void testOpensNotFound(Path base) throws Exception { 205 Path src = base.resolve("src"); 206 tb.writeJavaFiles(src, 207 "module M { opens p to N; }", 208 "package p; public class C {}"); 209 String log = new JavacTask(tb) 210 .options("-XDrawDiagnostics", 211 "-Xlint:module") 212 .files(findJavaFiles(src)) 213 .run() 214 .writeAll() 215 .getOutput(Task.OutputKind.DIRECT); 216 217 if (!log.contains("module-info.java:1:23: compiler.warn.module.not.found: N")) 218 throw new Exception("expected output not found, actual output: " + log); 219 } 220 221 /** 222 * Verify that duplicated qualified missing opens targets are reported. 223 */ 224 @Test 225 public void testOpensNotFoundDuplicated(Path base) throws Exception { 226 Path src = base.resolve("src"); 227 tb.writeJavaFiles(src, 228 "module M { opens p to N, N; }", 229 "package p; public class C {}"); 230 String log = new JavacTask(tb) 231 .options("-XDrawDiagnostics", 232 "-Xlint:module") 233 .files(findJavaFiles(src)) 234 .run(Task.Expect.FAIL) 235 .writeAll() 236 .getOutput(Task.OutputKind.DIRECT); 237 238 if (!log.contains("module-info.java:1:26: compiler.err.conflicting.opens.to.module: N")) 239 throw new Exception("expected output not found, actual output: " + log); 240 } 241 242 /** 243 * Verify that missing opens target warning can be suppressed. 244 */ 245 @Test 246 public void testOpensNotFoundSuppress(Path base) throws Exception { 247 Path src = base.resolve("src"); 248 tb.writeJavaFiles(src, 249 "@SuppressWarnings(\"module\") module M { opens p to N; }", 250 "package p; public class C {}"); 251 String log = new JavacTask(tb) 252 .options("-XDrawDiagnostics", 253 "-Xlint:module") 254 .files(findJavaFiles(src)) 255 .run() 256 .writeAll() 257 .getOutput(Task.OutputKind.DIRECT); 258 259 if (!log.isEmpty()) 260 throw new Exception("expected output not found, actual output: " + log); 261 } 262 263 /** 264 * Verify that a simple loop is detected. 265 */ 266 @Test 267 public void testRequiresSelf(Path base) throws Exception { 268 Path src = base.resolve("src"); 269 tb.writeJavaFiles(src, "module M { requires M; }"); 270 String log = new JavacTask(tb) 271 .options("-XDrawDiagnostics") 272 .files(findJavaFiles(src)) 273 .run(Task.Expect.FAIL) 274 .writeAll() 275 .getOutput(Task.OutputKind.DIRECT); 276 277 if (!log.contains("module-info.java:1:21: compiler.err.cyclic.requires: M")) 278 throw new Exception("expected output not found"); 279 } 280 281 /** 282 * Verify that a multi-module loop is detected. 283 */ 284 @Test 285 public void testRequiresLoop(Path base) throws Exception { 286 Path src = base.resolve("src"); 287 Path src_m1 = src.resolve("m1x"); 288 tb.writeFile(src_m1.resolve("module-info.java"), "module m1x { requires m2x; }"); 289 Path src_m2 = src.resolve("m2x"); 290 tb.writeFile(src_m2.resolve("module-info.java"), "module m2x { requires m3x; }"); 291 Path src_m3 = src.resolve("m3x"); 292 tb.writeFile(src_m3.resolve("module-info.java"), "module m3x { requires m1x; }"); 293 294 Path classes = base.resolve("classes"); 295 Files.createDirectories(classes); 296 297 String log = new JavacTask(tb) 298 .options("-XDrawDiagnostics", "--module-source-path", src.toString()) 299 .outdir(classes) 300 .files(findJavaFiles(src)) 301 .run(Task.Expect.FAIL) 302 .writeAll() 303 .getOutput(Task.OutputKind.DIRECT); 304 305 if (!log.contains("module-info.java:1:23: compiler.err.cyclic.requires: m3x")) 306 throw new Exception("expected output not found"); 307 } 308 309 /** 310 * Verify that a multi-module loop is detected. 311 */ 312 @Test 313 public void testRequiresTransitiveLoop(Path base) throws Exception { 314 Path src = base.resolve("src"); 315 Path src_m1 = src.resolve("m1x"); 316 tb.writeFile(src_m1.resolve("module-info.java"), "module m1x { requires m2x; }"); 317 Path src_m2 = src.resolve("m2x"); 318 tb.writeFile(src_m2.resolve("module-info.java"), "module m2x { requires transitive m3x; }"); 319 Path src_m3 = src.resolve("m3x"); 320 tb.writeFile(src_m3.resolve("module-info.java"), "module m3x { requires m1x; }"); 321 322 Path classes = base.resolve("classes"); 323 Files.createDirectories(classes); 324 325 String log = new JavacTask(tb) 326 .options("-XDrawDiagnostics", "--module-source-path", src.toString()) 327 .outdir(classes) 328 .files(findJavaFiles(src)) 329 .run(Task.Expect.FAIL) 330 .writeAll() 331 .getOutput(Task.OutputKind.DIRECT); 332 333 if (!log.contains("module-info.java:1:34: compiler.err.cyclic.requires: m3x")) 334 throw new Exception("expected output not found"); 335 } 336 337 /** 338 * Verify that duplicate requires are detected. 339 */ 340 @Test 341 public void testDuplicateRequires(Path base) throws Exception { 342 Path src = base.resolve("src"); 343 Path src_m1 = src.resolve("m1x"); 344 tb.writeFile(src_m1.resolve("module-info.java"), "module m1x { }"); 345 Path src_m2 = src.resolve("m2x"); 346 tb.writeFile(src_m2.resolve("module-info.java"), "module m2x { requires m1x; requires m1x; }"); 347 348 Path classes = base.resolve("classes"); 349 Files.createDirectories(classes); 350 351 String log = new JavacTask(tb) 352 .options("-XDrawDiagnostics", "--module-source-path", src.toString()) 353 .outdir(classes) 354 .files(findJavaFiles(src)) 355 .run(Task.Expect.FAIL) 356 .writeAll() 357 .getOutput(Task.OutputKind.DIRECT); 358 359 if (!log.contains("module-info.java:1:37: compiler.err.duplicate.requires: m1x")) 360 throw new Exception("expected output not found"); 361 } 362 363 /** 364 * Verify that duplicate requires are detected. 365 */ 366 @Test 367 public void testDuplicateRequiresTransitiveStatic(Path base) throws Exception { 368 Path src = base.resolve("src"); 369 Path src_m1 = src.resolve("m1x"); 370 tb.writeFile(src_m1.resolve("module-info.java"), "module m1x { }"); 371 Path src_m2 = src.resolve("m2x"); 372 tb.writeFile(src_m2.resolve("module-info.java"), "module m2x { requires transitive m1x; requires static m1x; }"); 373 374 Path classes = base.resolve("classes"); 375 Files.createDirectories(classes); 376 377 String log = new JavacTask(tb) 378 .options("-XDrawDiagnostics", "--module-source-path", src.toString()) 379 .outdir(classes) 380 .files(findJavaFiles(src)) 381 .run(Task.Expect.FAIL) 382 .writeAll() 383 .getOutput(Task.OutputKind.DIRECT); 384 385 if (!log.contains("module-info.java:1:55: compiler.err.duplicate.requires: m1x")) 386 throw new Exception("expected output not found"); 387 } 388 389 /** 390 * Verify that duplicate exported packages are detected correctly. 391 */ 392 @Test 393 public void testConflictingExports_packages(Path base) throws Exception { 394 verifyConflictingExports_packages(base, 395 "exports p; exports q;", 396 null); 397 verifyConflictingExports_packages(base, 398 "exports p; exports p;", 399 "module-info.java:1:33: compiler.err.conflicting.exports: p"); 400 verifyConflictingExports_packages(base, 401 "exports p; opens p;", 402 null); 403 verifyConflictingExports_packages(base, 404 "exports p; exports p to m2x;", 405 "module-info.java:1:33: compiler.err.conflicting.exports: p"); 406 verifyConflictingExports_packages(base, 407 "exports p; opens p to m2x;", 408 null); 409 verifyConflictingExports_packages(base, 410 "opens p; exports p;", 411 null); 412 verifyConflictingExports_packages(base, 413 "opens p; opens p;", 414 "module-info.java:1:29: compiler.err.conflicting.opens: p"); 415 verifyConflictingExports_packages(base, 416 "opens p; exports p to m2x;", 417 null); 418 verifyConflictingExports_packages(base, 419 "opens p; opens p to m2x;", 420 "module-info.java:1:29: compiler.err.conflicting.opens: p"); 421 verifyConflictingExports_packages(base, 422 "exports p to m2x; exports p;", 423 "module-info.java:1:40: compiler.err.conflicting.exports: p"); 424 verifyConflictingExports_packages(base, 425 "exports p to m2x; opens p;", 426 null); 427 verifyConflictingExports_packages(base, 428 "exports p to m2x; exports p to m2x;", 429 "module-info.java:1:45: compiler.err.conflicting.exports.to.module: m2x"); 430 verifyConflictingExports_packages(base, 431 "exports p to m2x; opens p to m2x;", 432 null); 433 verifyConflictingExports_packages(base, 434 "opens p to m2x; exports p;", 435 null); 436 verifyConflictingExports_packages(base, 437 "opens p to m2x; opens p;", 438 "module-info.java:1:36: compiler.err.conflicting.opens: p"); 439 verifyConflictingExports_packages(base, 440 "opens p to m2x; exports p to m2x;", 441 null); 442 verifyConflictingExports_packages(base, 443 "opens p to m2x; opens p to m2x;", 444 "module-info.java:1:36: compiler.err.conflicting.opens: p"); 445 verifyConflictingExports_packages(base, 446 "exports p to m2x; exports p to m3x;", 447 "module-info.java:1:40: compiler.err.conflicting.exports: p"); 448 verifyConflictingExports_packages(base, 449 "exports p to m2x; opens p to m3x;", 450 null); 451 verifyConflictingExports_packages(base, 452 "opens p to m2x; exports p to m3x;", 453 null); 454 verifyConflictingExports_packages(base, 455 "opens p to m2x; opens p to m3x;", 456 "module-info.java:1:36: compiler.err.conflicting.opens: p"); 457 } 458 459 private void verifyConflictingExports_packages(Path base, String code, String expected) throws Exception { 460 Files.createDirectories(base); 461 tb.cleanDirectory(base); 462 463 Path src = base.resolve("src"); 464 tb.writeJavaFiles(src.resolve("m1x"), 465 "module m1x { " + code + " }", 466 "package p; public class P {}", 467 "package q; public class Q {}"); 468 tb.writeJavaFiles(src.resolve("m2x"), 469 "module m2x { requires m1x; }"); 470 tb.writeJavaFiles(src.resolve("m3x"), 471 "module m3x { requires m1x; }"); 472 473 Path classes = base.resolve("classes"); 474 Files.createDirectories(classes); 475 476 String log = new JavacTask(tb) 477 .options("-XDrawDiagnostics", 478 "--module-source-path", src.toString()) 479 .outdir(classes) 480 .files(findJavaFiles(src)) 481 .run(expected != null ? Task.Expect.FAIL : Task.Expect.SUCCESS) 482 .writeAll() 483 .getOutput(Task.OutputKind.DIRECT); 484 485 if (expected != null && !log.contains(expected)) 486 throw new Exception("expected output not found, actual output: " + log); 487 } 488 489 /** 490 * Verify that duplicate exported packages are detected. 491 */ 492 @Test 493 public void testConflictingExports_modules(Path base) throws Exception { 494 Path src = base.resolve("src"); 495 Path src_m1 = src.resolve("m1x"); 496 tb.writeFile(src_m1.resolve("module-info.java"), "module m1x { }"); 497 Path src_m2 = src.resolve("m2x"); 498 tb.writeFile(src_m2.resolve("module-info.java"), "module m2x { exports p to m1x, m1x; }"); 499 500 Path classes = base.resolve("classes"); 501 Files.createDirectories(classes); 502 503 String log = new JavacTask(tb) 504 .options("-XDrawDiagnostics", "--module-source-path", src.toString()) 505 .outdir(classes) 506 .files(findJavaFiles(src)) 507 .run(Task.Expect.FAIL) 508 .writeAll() 509 .getOutput(Task.OutputKind.DIRECT); 510 511 if (!log.contains("module-info.java:1:32: compiler.err.conflicting.exports.to.module: m1x")) 512 throw new Exception("expected output not found"); 513 } 514 515 /** 516 * Verify that annotations are not permitted at 517 * any of the module names or the package names. 518 */ 519 @Test 520 public void testAnnotations(Path base) throws Exception { 521 Path src = base.resolve("src"); 522 Path src_m1 = src.resolve("m1x.sub"); 523 Path classes = base.resolve("classes"); 524 Files.createDirectories(classes); 525 526 String code = "module @m1.@sub { " + 527 "requires @p1.@p2; " + 528 "exports @p1.@p2; " + 529 "exports @p1.@p2 to @m2.@sub; " + 530 "exports @p1.@p2 to @m2.@sub, @m3.@sub; " + 531 "uses @p1.@Interface; " + 532 "provides @p1.@Interface with @p2.@Concrete; " + 533 "}"; 534 String[] splittedCode = code.split("@"); 535 int length = splittedCode.length; 536 String anno = "@Anno "; 537 538 for (int i = 1; i < length; i++) { 539 String preAnno = String.join("", Arrays.copyOfRange(splittedCode, 0, i)); 540 String postAnno = String.join("", Arrays.copyOfRange(splittedCode, i, length)); 541 String moduleInfo = preAnno + anno + postAnno; 542 tb.writeFile(src_m1.resolve("module-info.java"), moduleInfo); 543 544 String log = new JavacTask(tb) 545 .options("-XDrawDiagnostics", "--module-source-path", src.toString()) 546 .outdir(classes) 547 .files(findJavaFiles(src)) 548 .run(Task.Expect.FAIL) 549 .writeAll() 550 .getOutput(Task.OutputKind.DIRECT); 551 552 String expect_prefix = "(?s)^module\\-info\\.java:\\d+:\\d+: "; 553 String expect_message = "compiler\\.err\\.expected: token\\.identifier"; 554 String expect_suffix = ".*"; 555 String expect = expect_prefix + expect_message + expect_suffix; 556 if (!log.matches(expect)) 557 throw new Exception("expected output not found for: " + moduleInfo + "; actual: " + log); 558 } 559 } 560} 561