ProvidesTest.java revision 3822:d8766c39123a
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
36import java.nio.file.Files;
37import java.nio.file.Path;
38import java.util.Arrays;
39import java.util.List;
40
41import toolbox.JavacTask;
42import toolbox.Task;
43import toolbox.Task.Expect;
44
45public 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("m1x"),
72                "module m1x { exports p1; }",
73                "package p1; public class C1 { }");
74        tb.writeJavaFiles(src.resolve("m2x"),
75                "module m2x { requires m1x; 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}
521