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