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 * @summary simple tests of module provides 27 * @bug 8168854 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 ModuleTestBase 33 * @run main ProvidesTest 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.JavacTask; 42 import toolbox.Task; 43 import toolbox.Task.Expect; 44 45 public class ProvidesTest extends ModuleTestBase { 46 public static void main(String... args) throws Exception { 47 ProvidesTest t = new ProvidesTest(); 48 t.runTests(); 49 } 50 51 @Test 52 public void testSimple(Path base) throws Exception { 53 Path src = base.resolve("src"); 54 tb.writeJavaFiles(src, 55 "module m { provides p1.C1 with p2.C2; }", 56 "package p1; public class C1 { }", 57 "package p2; public class C2 extends p1.C1 { }"); 58 Path classes = base.resolve("classes"); 59 Files.createDirectories(classes); 60 61 new JavacTask(tb) 62 .outdir(classes) 63 .files(findJavaFiles(src)) 64 .run(Task.Expect.SUCCESS) 65 .writeAll(); 66 } 67 68 @Test 69 public void testMulti(Path base) throws Exception { 70 Path src = base.resolve("src"); 71 tb.writeJavaFiles(src.resolve("m1"), 72 "module m1 { exports p1; }", 73 "package p1; public class C1 { }"); 74 tb.writeJavaFiles(src.resolve("m2"), 75 "module m2 { requires m1; provides p1.C1 with p2.C2; }", 76 "package p2; public class C2 extends p1.C1 { }"); 77 Path modules = base.resolve("modules"); 78 Files.createDirectories(modules); 79 80 new JavacTask(tb) 81 .options("--module-source-path", src.toString()) 82 .outdir(modules) 83 .files(findJavaFiles(src)) 84 .run(Task.Expect.SUCCESS) 85 .writeAll(); 86 87 } 88 89 @Test 90 public void testMissingWith(Path base) throws Exception { 91 Path src = base.resolve("src"); 92 tb.writeJavaFiles(src, 93 "module m { provides p.C; }", 94 "package p; public class C { }"); 95 Path classes = base.resolve("classes"); 96 Files.createDirectories(classes); 97 98 String log = new JavacTask(tb) 99 .options("-XDrawDiagnostics") 100 .outdir(classes) 101 .files(findJavaFiles(src)) 102 .run(Task.Expect.FAIL) 103 .writeAll() 104 .getOutput(Task.OutputKind.DIRECT); 105 106 if (!log.contains("module-info.java:1:24: compiler.err.expected: 'with'")) 107 throw new Exception("expected output not found"); 108 109 } 110 111 @Test 112 public void testDuplicateProvides(Path base) throws Exception { 113 Path src = base.resolve("src"); 114 tb.writeJavaFiles(src, 115 "module m { provides p1.C1 with p2.C2; provides p1.C1 with p2.C2; }", 116 "package p1; public class C1 { }", 117 "package p2; public class C2 extends p1.C1 { }"); 118 Path classes = base.resolve("classes"); 119 Files.createDirectories(classes); 120 121 new JavacTask(tb) 122 .options("-XDrawDiagnostic") 123 .outdir(classes) 124 .files(findJavaFiles(src)) 125 .run(Task.Expect.FAIL) 126 .writeAll(); 127 } 128 129 @Test 130 public void testMissingService(Path base) throws Exception { 131 Path src = base.resolve("src"); 132 tb.writeJavaFiles(src, 133 "module m { provides p.Missing with p.C; }", 134 "package p; public class C extends p.Missing { }"); 135 136 List<String> output = new JavacTask(tb) 137 .options("-XDrawDiagnostics") 138 .outdir(Files.createDirectories(base.resolve("classes"))) 139 .files(findJavaFiles(src)) 140 .run(Task.Expect.FAIL) 141 .writeAll() 142 .getOutputLines(Task.OutputKind.DIRECT); 143 144 List<String> expected = Arrays.asList( 145 "C.java:1:36: compiler.err.cant.resolve.location: kindname.class, Missing, , , (compiler.misc.location: kindname.package, p, null)", 146 "module-info.java:1:22: compiler.err.cant.resolve.location: kindname.class, Missing, , , (compiler.misc.location: kindname.package, p, null)", 147 "2 errors"); 148 if (!output.containsAll(expected)) { 149 throw new Exception("Expected output not found"); 150 } 151 } 152 153 @Test 154 public void testProvidesFromAnotherModule(Path base) throws Exception { 155 Path modules = base.resolve("modules"); 156 tb.writeJavaFiles(modules.resolve("M"), 157 "module M { exports p; }", 158 "package p; public class Service { }"); 159 tb.writeJavaFiles(modules.resolve("L"), 160 "module L { requires M; provides p.Service with p.Service; }"); 161 162 List<String> output = new JavacTask(tb) 163 .options("-XDrawDiagnostics", 164 "--module-source-path", modules.toString()) 165 .outdir(Files.createDirectories(base.resolve("classes"))) 166 .files(findJavaFiles(modules)) 167 .run(Task.Expect.FAIL) 168 .writeAll() 169 .getOutputLines(Task.OutputKind.DIRECT); 170 List<String> expected = Arrays.asList( 171 "module-info.java:1:24: compiler.err.service.implementation.not.in.right.module: M", 172 "1 error"); 173 if (!output.containsAll(expected)) { 174 throw new Exception("Expected output not found"); 175 } 176 177 } 178 179 @Test 180 public void testServiceIsNotImplemented(Path base) throws Exception { 181 Path src = base.resolve("src"); 182 tb.writeJavaFiles(src, 183 "module m { provides p.A with p.B; }", 184 "package p; public class A { }", 185 "package p; public class B { }"); 186 187 List<String> output = new JavacTask(tb) 188 .options("-XDrawDiagnostics") 189 .outdir(Files.createDirectories(base.resolve("classes"))) 190 .files(findJavaFiles(src)) 191 .run(Task.Expect.FAIL) 192 .writeAll() 193 .getOutputLines(Task.OutputKind.DIRECT); 194 195 List<String> expected = Arrays.asList( 196 "module-info.java:1:31: compiler.err.service.implementation.must.be.subtype.of.service.interface", 197 "module-info.java:1:12: compiler.warn.service.provided.but.not.exported.or.used: p.A", 198 "1 error", 199 "1 warning"); 200 if (!output.containsAll(expected)) { 201 throw new Exception("Expected output not found"); 202 } 203 } 204 205 @Test 206 public void testMissingImplementation(Path base) throws Exception { 207 Path src = base.resolve("src"); 208 tb.writeJavaFiles(src, 209 "module m { provides p.C with p.Impl; }", 210 "package p; public class C { }"); 211 212 List<String> output = new JavacTask(tb) 213 .options("-XDrawDiagnostics") 214 .outdir(Files.createDirectories(base.resolve("classes"))) 215 .files(findJavaFiles(src)) 216 .run(Task.Expect.FAIL) 217 .writeAll() 218 .getOutputLines(Task.OutputKind.DIRECT); 219 220 List<String> expected = Arrays.asList("module-info.java:1:31: compiler.err.cant.resolve.location: kindname.class, Impl, , , (compiler.misc.location: kindname.package, p, null)", 221 "1 error"); 222 if (!output.containsAll(expected)) { 223 throw new Exception("Expected output not found"); 224 } 225 } 226 227 @Test 228 public void testSeveralImplementations(Path base) throws Exception { 229 Path src = base.resolve("src"); 230 tb.writeJavaFiles(src, 231 "module m { provides p.C with p.Impl1; provides p.C with p.Impl2; }", 232 "package p; public class C { }", 233 "package p; public class Impl1 extends p.C { }", 234 "package p; public class Impl2 extends p.C { }"); 235 236 new JavacTask(tb) 237 .outdir(Files.createDirectories(base.resolve("classes"))) 238 .files(findJavaFiles(src)) 239 .run(Task.Expect.SUCCESS) 240 .writeAll(); 241 } 242 243 @Test 244 public void testOneImplementationsForServices(Path base) throws Exception { 245 Path src = base.resolve("src"); 246 tb.writeJavaFiles(src, 247 "module m { provides p.Service1 with p.Impl; provides p.Service2 with p.Impl; }", 248 "package p; public interface Service1 { }", 249 "package p; public abstract class Service2 { }", 250 "package p; public class Impl extends p.Service2 implements p.Service1 { }"); 251 252 new JavacTask(tb) 253 .outdir(Files.createDirectories(base.resolve("classes"))) 254 .files(findJavaFiles(src)) 255 .run(Task.Expect.SUCCESS) 256 .writeAll(); 257 } 258 259 @Test 260 public void testAbstractImplementation(Path base) throws Exception { 261 Path src = base.resolve("src"); 262 tb.writeJavaFiles(src, 263 "module m { provides p1.C1 with p2.C2; }", 264 "package p1; public class C1 { }", 265 "package p2; public abstract class C2 extends p1.C1 { }"); 266 267 List<String> output = new JavacTask(tb) 268 .options("-XDrawDiagnostics") 269 .outdir(Files.createDirectories(base.resolve("classes"))) 270 .files(findJavaFiles(src)) 271 .run(Task.Expect.FAIL) 272 .writeAll() 273 .getOutputLines(Task.OutputKind.DIRECT); 274 275 List<String> expected = Arrays.asList( 276 "module-info.java:1:34: compiler.err.service.implementation.is.abstract: p2.C2"); 277 if (!output.containsAll(expected)) { 278 throw new Exception("Expected output not found"); 279 } 280 } 281 282 @Test 283 public void testInterfaceImplementation(Path base) throws Exception { 284 Path src = base.resolve("src"); 285 tb.writeJavaFiles(src, 286 "module m { provides p1.Service with p2.Impl; }", 287 "package p1; public interface Service { }", 288 "package p2; public interface Impl extends p1.Service { }"); 289 290 List<String> output = new JavacTask(tb) 291 .options("-XDrawDiagnostics") 292 .outdir(Files.createDirectories(base.resolve("classes"))) 293 .files(findJavaFiles(src)) 294 .run(Task.Expect.FAIL) 295 .writeAll() 296 .getOutputLines(Task.OutputKind.DIRECT); 297 298 List<String> expected = Arrays.asList( 299 "module-info.java:1:39: compiler.err.service.implementation.is.abstract: p2.Impl"); 300 if (!output.containsAll(expected)) { 301 throw new Exception("Expected output not found"); 302 } 303 } 304 305 @Test 306 public void testProtectedImplementation(Path base) throws Exception { 307 Path src = base.resolve("src"); 308 tb.writeJavaFiles(src, 309 "module m { provides p1.C1 with p2.C2; }", 310 "package p1; public class C1 { }", 311 "package p2; class C2 extends p1.C1 { }"); 312 313 List<String> output = new JavacTask(tb) 314 .options("-XDrawDiagnostics") 315 .outdir(Files.createDirectories(base.resolve("classes"))) 316 .files(findJavaFiles(src)) 317 .run(Task.Expect.FAIL) 318 .writeAll() 319 .getOutputLines(Task.OutputKind.DIRECT); 320 321 List<String> expected = Arrays.asList("module-info.java:1:34: compiler.err.not.def.public.cant.access: p2.C2, p2", 322 "1 error"); 323 if (!output.containsAll(expected)) { 324 throw new Exception("Expected output not found"); 325 } 326 } 327 328 @Test 329 public void testNoNoArgConstructor(Path base) throws Exception { 330 Path src = base.resolve("src"); 331 tb.writeJavaFiles(src, 332 "module m { uses p1.C1; provides p1.C1 with p2.C2; }", 333 "package p1; public class C1 { }", 334 "package p2; public class C2 extends p1.C1 { public C2(String str) { } }"); 335 336 List<String> output = new JavacTask(tb) 337 .options("-XDrawDiagnostics") 338 .outdir(Files.createDirectories(base.resolve("classes"))) 339 .files(findJavaFiles(src)) 340 .run(Task.Expect.FAIL) 341 .writeAll() 342 .getOutputLines(Task.OutputKind.DIRECT); 343 344 List<String> expected = Arrays.asList( 345 "module-info.java:1:46: compiler.err.service.implementation.doesnt.have.a.no.args.constructor: p2.C2"); 346 if (!output.containsAll(expected)) { 347 throw new Exception("Expected output not found"); 348 } 349 } 350 351 @Test 352 public void testPrivateNoArgConstructor(Path base) throws Exception { 353 Path src = base.resolve("src"); 354 tb.writeJavaFiles(src, 355 "module m { uses p1.C1; provides p1.C1 with p2.C2; }", 356 "package p1; public class C1 { }", 357 "package p2; public class C2 extends p1.C1 { private C2() { } }"); 358 359 List<String> output = new JavacTask(tb) 360 .options("-XDrawDiagnostics") 361 .outdir(Files.createDirectories(base.resolve("classes"))) 362 .files(findJavaFiles(src)) 363 .run(Task.Expect.FAIL) 364 .writeAll() 365 .getOutputLines(Task.OutputKind.DIRECT); 366 367 List<String> expected = Arrays.asList( 368 "module-info.java:1:46: compiler.err.service.implementation.no.args.constructor.not.public: p2.C2"); 369 if (!output.containsAll(expected)) { 370 throw new Exception("Expected output not found"); 371 } 372 } 373 374 @Test 375 public void testServiceIndirectlyImplemented(Path base) throws Exception { 376 Path src = base.resolve("src"); 377 tb.writeJavaFiles(src, 378 "module m { provides p1.C1 with p2.C3; }", 379 "package p1; public class C1 { }", 380 "package p2; public class C2 extends p1.C1 { }", 381 "package p2; public class C3 extends p2.C2 { }"); 382 383 new JavacTask(tb) 384 .outdir(Files.createDirectories(base.resolve("classes"))) 385 .files(findJavaFiles(src)) 386 .run(Task.Expect.SUCCESS) 387 .writeAll(); 388 } 389 390 @Test 391 public void testServiceImplementationInnerClass(Path base) throws Exception { 392 Path src = base.resolve("src"); 393 tb.writeJavaFiles(src, 394 "module m { provides p1.C1 with p2.C2.Inner; }", 395 "package p1; public class C1 { }", 396 "package p2; public class C2 { public class Inner extends p1.C1 { } }"); 397 398 List<String> output = new JavacTask(tb) 399 .options("-XDrawDiagnostics") 400 .outdir(Files.createDirectories(base.resolve("classes"))) 401 .files(findJavaFiles(src)) 402 .run(Task.Expect.FAIL) 403 .writeAll() 404 .getOutputLines(Task.OutputKind.DIRECT); 405 406 List<String> expected = Arrays.asList( 407 "module-info.java:1:37: compiler.err.service.implementation.is.inner: p2.C2.Inner"); 408 if (!output.containsAll(expected)) { 409 throw new Exception("Expected output not found"); 410 } 411 } 412 413 @Test 414 public void testServiceDefinitionInnerClass(Path base) throws Exception { 415 Path src = base.resolve("src"); 416 tb.writeJavaFiles(src, 417 "module m { provides p1.C1.InnerDefinition with p2.C2; }", 418 "package p1; public class C1 { public class InnerDefinition { } }", 419 "package p2; public class C2 extends p1.C1.InnerDefinition { public C2() { new p1.C1().super(); } }"); 420 421 new JavacTask(tb) 422 .options("-XDrawDiagnostics") 423 .outdir(Files.createDirectories(base.resolve("classes"))) 424 .files(findJavaFiles(src)) 425 .run(Expect.SUCCESS) 426 .writeAll(); 427 } 428 429 @Test 430 public void testFactory(Path base) throws Exception { 431 Path src = base.resolve("src"); 432 tb.writeJavaFiles(src, 433 "module m { exports p1; provides p1.C1 with p2.C2; }", 434 "package p1; public interface C1 { }", 435 "package p2; public class C2 { public static p1.C1 provider() { return null; } }"); 436 437 new JavacTask(tb) 438 .options("-XDrawDiagnostics") 439 .outdir(Files.createDirectories(base.resolve("classes"))) 440 .files(findJavaFiles(src)) 441 .run() 442 .writeAll() 443 .getOutput(Task.OutputKind.DIRECT); 444 445 List<String> output; 446 List<String> expected; 447 448 tb.writeJavaFiles(src, 449 "package p2; public class C2 { public p1.C1 provider() { return null; } }"); 450 451 output = new JavacTask(tb) 452 .options("-XDrawDiagnostics") 453 .outdir(Files.createDirectories(base.resolve("classes"))) 454 .files(findJavaFiles(src)) 455 .run(Task.Expect.FAIL) 456 .writeAll() 457 .getOutputLines(Task.OutputKind.DIRECT); 458 459 expected = Arrays.asList("module-info.java:1:46: compiler.err.service.implementation.must.be.subtype.of.service.interface", 460 "1 error"); 461 462 if (!expected.equals(output)) { 463 throw new Exception("Expected output not found. Output: " + output); 464 } 465 466 tb.writeJavaFiles(src, 467 "package p2; public class C2 { static p1.C1 provider() { return null; } }"); 468 469 output = new JavacTask(tb) 470 .options("-XDrawDiagnostics") 471 .outdir(Files.createDirectories(base.resolve("classes"))) 472 .files(findJavaFiles(src)) 473 .run(Task.Expect.FAIL) 474 .writeAll() 475 .getOutputLines(Task.OutputKind.DIRECT); 476 477 expected = Arrays.asList("module-info.java:1:46: compiler.err.service.implementation.must.be.subtype.of.service.interface", 478 "1 error"); 479 480 if (!expected.equals(output)) { 481 throw new Exception("Expected output not found. Output: " + output); 482 } 483 484 tb.writeJavaFiles(src, 485 "package p2; public class C2 { public static Object provider() { return null; } }"); 486 487 output = new JavacTask(tb) 488 .options("-XDrawDiagnostics") 489 .outdir(Files.createDirectories(base.resolve("classes"))) 490 .files(findJavaFiles(src)) 491 .run(Task.Expect.FAIL) 492 .writeAll() 493 .getOutputLines(Task.OutputKind.DIRECT); 494 495 expected = Arrays.asList("module-info.java:1:46: compiler.err.service.implementation.provider.return.must.be.subtype.of.service.interface", 496 "1 error"); 497 498 if (!expected.equals(output)) { 499 throw new Exception("Expected output not found. Output: " + output); 500 } 501 502 tb.writeJavaFiles(src, 503 "package p2; public class C2 { public static p1.C1 provider = new p1.C1() {}; }"); 504 505 output = new JavacTask(tb) 506 .options("-XDrawDiagnostics") 507 .outdir(Files.createDirectories(base.resolve("classes"))) 508 .files(findJavaFiles(src)) 509 .run(Task.Expect.FAIL) 510 .writeAll() 511 .getOutputLines(Task.OutputKind.DIRECT); 512 513 expected = Arrays.asList("module-info.java:1:46: compiler.err.service.implementation.must.be.subtype.of.service.interface", 514 "1 error"); 515 516 if (!expected.equals(output)) { 517 throw new Exception("Expected output not found. Output: " + output); 518 } 519 } 520 }