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 * @summary tests for --module-source-path 27 * @library /tools/lib 28 * @modules 29 * jdk.compiler/com.sun.tools.javac.api 30 * jdk.compiler/com.sun.tools.javac.main 31 * @build toolbox.ToolBox toolbox.JavacTask ModuleTestBase 32 * @run main ModuleSourcePathTest 33 */ 34 35import java.io.File; 36import java.io.IOException; 37import java.nio.file.Files; 38import java.nio.file.Path; 39import java.nio.file.Paths; 40import java.util.ArrayList; 41import java.util.Arrays; 42import java.util.List; 43import java.util.stream.Collectors; 44import java.util.stream.Stream; 45 46import javax.tools.JavaCompiler; 47import javax.tools.JavaFileManager.Location; 48import javax.tools.StandardJavaFileManager; 49import javax.tools.StandardLocation; 50import javax.tools.ToolProvider; 51 52import toolbox.JavacTask; 53import toolbox.Task; 54import toolbox.ToolBox; 55 56public class ModuleSourcePathTest extends ModuleTestBase { 57 58 public static final char PATH_SEP = File.pathSeparatorChar; 59 60 public static void main(String... args) throws Exception { 61 ModuleSourcePathTest t = new ModuleSourcePathTest(); 62 t.runTests(); 63 } 64 65 @Test 66 public void testSourcePathConflict(Path base) throws Exception { 67 Path sp = base.resolve("src"); 68 Path msp = base.resolve("srcmodules"); 69 70 String log = new JavacTask(tb, Task.Mode.CMDLINE) 71 .options("-XDrawDiagnostics", 72 "--source-path", sp.toString().replace('/', File.separatorChar), 73 "--module-source-path", msp.toString().replace('/', File.separatorChar), 74 "dummyClass") 75 .run(Task.Expect.FAIL) 76 .writeAll() 77 .getOutput(Task.OutputKind.DIRECT); 78 79 if (!log.contains("cannot specify both --source-path and --module-source-path")) 80 throw new Exception("expected diagnostic not found"); 81 } 82 83 @Test 84 public void testUnnormalizedPath1(Path base) throws Exception { 85 Path src = base.resolve("src"); 86 Path src_m1 = src.resolve("m1x"); 87 tb.writeJavaFiles(src_m1, "module m1x { }"); 88 Path modules = base.resolve("modules"); 89 Files.createDirectories(modules); 90 91 new JavacTask(tb, Task.Mode.CMDLINE) 92 .options("-XDrawDiagnostics", 93 "--module-source-path", src.toString()) 94 .outdir(modules) 95 .files(prefixAll(findJavaFiles(src), Paths.get("./"))) 96 .run() 97 .writeAll(); 98 } 99 100 @Test 101 public void testUnnormalizedPath2(Path base) throws Exception { 102 Path src = base.resolve("src"); 103 Path src_m1 = src.resolve("m1x"); 104 tb.writeJavaFiles(src_m1, "module m1x { }"); 105 Path modules = base.resolve("modules"); 106 Files.createDirectories(modules); 107 108 new JavacTask(tb, Task.Mode.CMDLINE) 109 .options("-XDrawDiagnostics", 110 "--module-source-path", "./" + src) 111 .outdir(modules) 112 .files(findJavaFiles(src)) 113 .run() 114 .writeAll(); 115 } 116 117 private Path[] prefixAll(Path[] paths, Path prefix) { 118 return Stream.of(paths) 119 .map(prefix::resolve) 120 .collect(Collectors.toList()) 121 .toArray(new Path[paths.length]); 122 } 123 124 @Test 125 public void regularBraces(Path base) throws Exception { 126 generateModules(base, "src1", "src2/inner_dir"); 127 128 final Path modules = base.resolve("modules"); 129 tb.createDirectories(modules); 130 131 new JavacTask(tb, Task.Mode.CMDLINE) 132 .options("-XDrawDiagnostics", 133 "--module-source-path", base + "/{src1,src2/inner_dir}") 134 .files(base.resolve("src1/m0x/pkg0/A.java"), base.resolve("src2/inner_dir/m1x/pkg1/A.java")) 135 .outdir(modules) 136 .run() 137 .writeAll(); 138 139 checkFiles(modules.resolve("m0x/pkg0/A.class"), 140 modules.resolve("m1x/pkg1/A.class"), 141 modules.resolve("m0x/module-info.class"), 142 modules.resolve("m1x/module-info.class")); 143 } 144 145 @Test 146 public void mismatchedBraces(Path base) throws Exception { 147 final List<String> sourcePaths = Arrays.asList( 148 "{", 149 "}", 150 "}{", 151 "./}", 152 ".././{./", 153 "src{}}", 154 "{{}{}}{}}", 155 "src/{a,b}/{", 156 "src/{a,{,{}}", 157 "{.,..{}/src", 158 "*}{", 159 "{}*}" 160 ); 161 for (String sourcepath : sourcePaths) { 162 String log = new JavacTask(tb, Task.Mode.CMDLINE) 163 .options("-XDrawDiagnostics", 164 "--module-source-path", sourcepath.replace('/', File.separatorChar)) 165 .run(Task.Expect.FAIL) 166 .writeAll() 167 .getOutput(Task.OutputKind.DIRECT); 168 169 if (!log.contains("- compiler.err.illegal.argument.for.option: --module-source-path, mismatched braces")) 170 throw new Exception("expected output for path [" + sourcepath + "] not found"); 171 } 172 } 173 174 @Test 175 public void deepBraces(Path base) throws Exception { 176 String[] modulePaths = {"src/src1", 177 "src/src2", 178 "src/src3", 179 "src/srcB/src1", 180 "src/srcB/src2/srcXX", 181 "src/srcB/src2/srcXY", 182 "src/srcC/src1", 183 "src/srcC/src2/srcXX", 184 "src/srcC/src2/srcXY"}; 185 generateModules(base, modulePaths); 186 187 final Path modules = base.resolve("modules"); 188 tb.createDirectories(modules); 189 190 new JavacTask(tb, Task.Mode.CMDLINE) 191 .options("-XDrawDiagnostics", 192 "--module-source-path", 193 base + "/{src/{{src1,src2,src3},{srcB,srcC}/{src1,src2/srcX{X,Y}/}},.}" 194 .replace('/', File.separatorChar)) 195 .files(findJavaFiles(base.resolve(modulePaths[modulePaths.length - 1]))) 196 .outdir(modules) 197 .run() 198 .writeAll(); 199 200 for (int i = 0; i < modulePaths.length; i++) { 201 checkFiles(modules.resolve("m" + i + "x/module-info.class")); 202 } 203 checkFiles(modules.resolve("m8x/pkg8/A.class")); 204 } 205 206 @Test 207 public void fileInPath(Path base) throws Exception { 208 Path src = base.resolve("src"); 209 tb.writeJavaFiles(src.resolve("kettle$"), "module kettle$ { }", "package electric; class Heater { }"); 210 tb.writeFile(base.resolve("dummy.txt"), ""); 211 212 final Path modules = base.resolve("modules"); 213 tb.createDirectories(modules); 214 215 new JavacTask(tb, Task.Mode.CMDLINE) 216 .options("-XDrawDiagnostics", 217 "--module-source-path", base + "/{dummy.txt,src}") 218 .files(src.resolve("kettle$/electric/Heater.java")) 219 .outdir(modules) 220 .run() 221 .writeAll(); 222 223 checkFiles(modules.resolve("kettle$/electric/Heater.class")); 224 checkFiles(modules.resolve("kettle$/module-info.class")); 225 } 226 227 @Test 228 public void noAlternative(Path base) throws Exception { 229 Path src = base.resolve("src"); 230 tb.writeJavaFiles(src.resolve("kettle$"), "module kettle$ { }", "package electric; class Heater { }"); 231 232 final Path modules = base.resolve("modules"); 233 tb.createDirectories(modules); 234 235 new JavacTask(tb, Task.Mode.CMDLINE) 236 .options("-XDrawDiagnostics", 237 "--module-source-path", base + "/{src}") 238 .files(src.resolve("kettle$/electric/Heater.java")) 239 .outdir(modules) 240 .run() 241 .writeAll(); 242 243 checkFiles(modules.resolve("kettle$/electric/Heater.class")); 244 checkFiles(modules.resolve("kettle$/module-info.class")); 245 } 246 247 @Test 248 public void noChoice(Path base) throws Exception { 249 tb.writeJavaFiles(base.resolve("kettle$"), "module kettle$ { }", "package electric; class Heater { }"); 250 251 final Path modules = base.resolve("modules"); 252 tb.createDirectories(modules); 253 254 new JavacTask(tb, Task.Mode.CMDLINE) 255 .options("-XDrawDiagnostics", 256 "--module-source-path", base + "/{}") 257 .files(base.resolve("kettle$/electric/Heater.java")) 258 .outdir(modules) 259 .run() 260 .writeAll(); 261 262 checkFiles(modules.resolve("kettle$/electric/Heater.class")); 263 checkFiles(modules.resolve("kettle$/module-info.class")); 264 } 265 266 @Test 267 public void nestedModules(Path src) throws Exception { 268 Path carModule = src.resolve("car"); 269 tb.writeJavaFiles(carModule, "module car { }", "package light; class Headlight { }"); 270 tb.writeJavaFiles(carModule.resolve("engine"), "module engine { }", "package flat; class Piston { }"); 271 272 final Path modules = src.resolve("modules"); 273 tb.createDirectories(modules); 274 275 new JavacTask(tb, Task.Mode.CMDLINE) 276 .options("-XDrawDiagnostics", 277 "--module-source-path", "{" + src + "," + src + "/car}") 278 .files(findJavaFiles(src)) 279 .outdir(modules) 280 .run() 281 .writeAll(); 282 checkFiles(modules.resolve("car/light/Headlight.class")); 283 checkFiles(modules.resolve("engine/flat/Piston.class")); 284 } 285 286 @Test 287 public void relativePaths(Path base) throws Exception { 288 Path src = base.resolve("src"); 289 tb.writeJavaFiles(src.resolve("kettle"), "module kettle { }", "package electric; class Heater { }"); 290 291 final Path modules = base.resolve("modules"); 292 tb.createDirectories(modules); 293 294 new JavacTask(tb, Task.Mode.CMDLINE) 295 .options("-XDrawDiagnostics", 296 "--module-source-path", base + "/src/./../src") 297 .files(src.resolve("kettle/electric/Heater.java")) 298 .outdir(modules) 299 .run() 300 .writeAll(); 301 checkFiles(modules.resolve("kettle/electric/Heater.class")); 302 checkFiles(modules.resolve("kettle/module-info.class")); 303 } 304 305 @Test 306 public void duplicatePaths(Path base) throws Exception { 307 Path src = base.resolve("src"); 308 tb.writeJavaFiles(src.resolve("m1x"), "module m1x { }", "package a; class A { }"); 309 310 final Path modules = base.resolve("modules"); 311 tb.createDirectories(modules); 312 313 new JavacTask(tb, Task.Mode.CMDLINE) 314 .options("-XDrawDiagnostics", 315 "--module-source-path", base + "/{src,src,src}") 316 .files(src.resolve("m1x/a/A.java")) 317 .outdir(modules) 318 .run() 319 .writeAll(); 320 321 checkFiles(modules.resolve("m1x/module-info.class")); 322 } 323 324 @Test 325 public void notExistentPaths(Path base) throws Exception { 326 tb.writeJavaFiles(base.resolve("m1x"), "module m1x { requires m0x; }", "package a; class A { }"); 327 328 final Path modules = base.resolve("modules"); 329 tb.createDirectories(modules); 330 331 String log = new JavacTask(tb, Task.Mode.CMDLINE) 332 .options("-XDrawDiagnostics", 333 "--module-source-path", base + "/not_exist" + PATH_SEP + base + "/{not_exist,}") 334 .files(base.resolve("m1x/a/A.java")) 335 .outdir(modules) 336 .run(Task.Expect.FAIL) 337 .writeAll() 338 .getOutput(Task.OutputKind.DIRECT); 339 if (!log.contains("compiler.err.module.not.found: m0x")) 340 throw new Exception("expected output for not existent module source path not found"); 341 } 342 343 @Test 344 public void notExistentPathShouldBeSkipped(Path base) throws Exception { 345 tb.writeJavaFiles(base.resolve("m1x"), "module m1x { }", "package a; class A { }"); 346 347 final Path modules = base.resolve("modules"); 348 tb.createDirectories(modules); 349 350 new JavacTask(tb, Task.Mode.CMDLINE) 351 .options("-XDrawDiagnostics", 352 "--module-source-path", base + "{/not_exist,/}") 353 .files(base.resolve("m1x/a/A.java")) 354 .outdir(modules) 355 .run() 356 .writeAll(); 357 358 checkFiles(modules.resolve("m1x/module-info.class")); 359 } 360 361 @Test 362 public void commas(Path base) throws Exception { 363 Path src = base.resolve("src"); 364 tb.writeJavaFiles(src.resolve("m1x"), "module m1x { }", "package a; class A { }"); 365 366 final Path modules = base.resolve("modules"); 367 tb.createDirectories(modules); 368 369 new JavacTask(tb, Task.Mode.CMDLINE) 370 .options("-XDrawDiagnostics", 371 "--module-source-path", base + "/{,{,,,,src,,,}}") 372 .files(src.resolve("m1x/a/A.java")) 373 .outdir(modules) 374 .run() 375 .writeAll(); 376 377 checkFiles(modules.resolve("m1x/module-info.class")); 378 } 379 380 @Test 381 public void asterisk(Path base) throws Exception { 382 tb.writeJavaFiles(base.resolve("kettle").resolve("classes"), "module kettle { }", 383 "package electric; class Heater { }"); 384 385 final Path modules = base.resolve("modules"); 386 tb.createDirectories(modules); 387 388 new JavacTask(tb, Task.Mode.CMDLINE) 389 .options("-XDrawDiagnostics", 390 "--module-source-path", base + "/*/classes/") 391 .files(base.resolve("kettle/classes/electric/Heater.java")) 392 .outdir(modules) 393 .run() 394 .writeAll(); 395 396 checkFiles(modules.resolve("kettle/electric/Heater.class")); 397 checkFiles(modules.resolve("kettle/module-info.class")); 398 } 399 400 @Test 401 public void asteriskInDifferentSets(Path base) throws Exception { 402 Path src = base.resolve("src"); 403 final Path module = src.resolve("kettle"); 404 tb.writeJavaFiles(module.resolve("classes"), "module kettle { }", "package electric; class Heater { }"); 405 tb.writeJavaFiles(module.resolve("gensrc"), "package model; class Java { }"); 406 tb.writeJavaFiles(module.resolve("special/classes"), "package gas; class Heater { }"); 407 408 final Path modules = base.resolve("modules"); 409 tb.createDirectories(modules); 410 411 new JavacTask(tb, Task.Mode.CMDLINE) 412 .options("-XDrawDiagnostics", 413 "--module-source-path", src + "{/*/gensrc/,/*/classes/}" + PATH_SEP 414 + src + "/*/special/classes") 415 .files(findJavaFiles(src)) 416 .outdir(modules) 417 .run() 418 .writeAll(); 419 420 checkFiles(modules.resolve("kettle/electric/Heater.class")); 421 checkFiles(modules.resolve("kettle/gas/Heater.class")); 422 checkFiles(modules.resolve("kettle/model/Java.class")); 423 checkFiles(modules.resolve("kettle/module-info.class")); 424 } 425 426 @Test 427 public void asteriskIllegalUse(Path base) throws Exception { 428 final List<String> sourcePaths = Arrays.asList( 429 "*", 430 "**", 431 "***", 432 "*.*", 433 ".*", 434 "*.", 435 "src/*/*/", 436 "{*,*}", 437 "src/module*/" 438 ); 439 for (String sourcepath : sourcePaths) { 440 String log = new JavacTask(tb, Task.Mode.CMDLINE) 441 .options("-XDrawDiagnostics", 442 "--module-source-path", sourcepath.replace('/', File.separatorChar)) 443 .run(Task.Expect.FAIL) 444 .writeAll() 445 .getOutput(Task.OutputKind.DIRECT); 446 447 if (!log.contains("- compiler.err.illegal.argument.for.option: --module-source-path, illegal use of *")) 448 throw new Exception("expected output for path [" + sourcepath + "] not found"); 449 } 450 } 451 452 @Test 453 public void setLocation(Path base) throws Exception { 454 Path src = base.resolve("src"); 455 tb.writeJavaFiles(src.resolve("m1x"), "module m1x { }", "package a; class A { }"); 456 Path modules = base.resolve("modules"); 457 tb.createDirectories(modules); 458 459 JavaCompiler c = ToolProvider.getSystemJavaCompiler(); 460 try (StandardJavaFileManager fm = c.getStandardFileManager(null, null, null)) { 461 fm.setLocationFromPaths(StandardLocation.MODULE_SOURCE_PATH, List.of(src)); 462 new JavacTask(tb) 463 .options("-XDrawDiagnostics") 464 .fileManager(fm) 465 .outdir(modules) 466 .files(findJavaFiles(src)) 467 .run() 468 .writeAll(); 469 470 checkFiles(modules.resolve("m1x/module-info.class"), modules.resolve("m1x/a/A.class")); 471 } 472 } 473 474 @Test 475 public void getLocation_valid(Path base) throws Exception { 476 Path src1 = base.resolve("src1"); 477 tb.writeJavaFiles(src1.resolve("m1x"), "module m1x { }", "package a; class A { }"); 478 Path src2 = base.resolve("src2"); 479 tb.writeJavaFiles(src1.resolve("m2x"), "module m2x { }", "package b; class B { }"); 480 481 JavaCompiler c = ToolProvider.getSystemJavaCompiler(); 482 try (StandardJavaFileManager fm = c.getStandardFileManager(null, null, null)) { 483 fm.setLocationFromPaths(StandardLocation.MODULE_SOURCE_PATH, List.of(src1, src2)); 484 checkLocation(fm.getLocationAsPaths(StandardLocation.MODULE_SOURCE_PATH), List.of(src1, src2)); 485 } 486 } 487 488 @Test 489 public void getLocation_ISA(Path base) throws Exception { 490 Path src1 = base.resolve("src1"); 491 tb.writeJavaFiles(src1.resolve("m1x"), "module m1x { }", "package a; class A { }"); 492 Path src2 = base.resolve("src2"); 493 tb.writeJavaFiles(src2.resolve("m2x").resolve("extra"), "module m2x { }", "package b; class B { }"); 494 Path modules = base.resolve("modules"); 495 tb.createDirectories(modules); 496 497 String FS = File.separator; 498 String PS = File.pathSeparator; 499 JavaCompiler c = ToolProvider.getSystemJavaCompiler(); 500 try (StandardJavaFileManager fm = c.getStandardFileManager(null, null, null)) { 501 fm.handleOption("--module-source-path", 502 List.of(src1 + PS + src2 + FS + "*" + FS + "extra").iterator()); 503 504 try { 505 Iterable<? extends Path> paths = fm.getLocationAsPaths(StandardLocation.MODULE_SOURCE_PATH); 506 out.println("result: " + asList(paths)); 507 throw new Exception("expected IllegalStateException not thrown"); 508 } catch (IllegalStateException e) { 509 out.println("Exception thrown, as expected: " + e); 510 } 511 512 // even if we can't do getLocation for the MODULE_SOURCE_PATH, we should be able 513 // to do getLocation for the modules, which will additionally confirm the option 514 // was effective as intended. 515 Location locn1 = fm.getLocationForModule(StandardLocation.MODULE_SOURCE_PATH, "m1x"); 516 checkLocation(fm.getLocationAsPaths(locn1), List.of(src1.resolve("m1x"))); 517 Location locn2 = fm.getLocationForModule(StandardLocation.MODULE_SOURCE_PATH, "m2x"); 518 checkLocation(fm.getLocationAsPaths(locn2), List.of(src2.resolve("m2x").resolve("extra"))); 519 } 520 } 521 522 private void generateModules(Path base, String... paths) throws IOException { 523 for (int i = 0; i < paths.length; i++) { 524 String moduleName = "m" + i + "x"; 525 String dependency = i > 0 ? "requires m" + (i - 1) + "x;" : ""; 526 tb.writeJavaFiles(base.resolve(paths[i]).resolve(moduleName), 527 "module " + moduleName + " { " + dependency + " }", 528 "package pkg" + i + "; class A { }"); 529 } 530 } 531 532 private void checkFiles(Path... files) throws Exception { 533 for (Path file : files) { 534 if (!Files.exists(file)) { 535 throw new Exception("File not found: " + file); 536 } 537 } 538 } 539 540 private void checkLocation(Iterable<? extends Path> locn, List<Path> ref) throws Exception { 541 List<Path> list = asList(locn); 542 if (!list.equals(ref)) { 543 out.println("expect: " + ref); 544 out.println(" found: " + list); 545 throw new Exception("location not as expected"); 546 } 547 } 548 549 private <T> List<T> asList(Iterable<? extends T> iter) { 550 List<T> list = new ArrayList<>(); 551 for (T item : iter) { 552 list.add(item); 553 } 554 return list; 555 } 556} 557