1 /*
2 * Copyright (c) 2014, 2025, 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 8142968 8299504
27 * @modules java.base/jdk.internal.access
28 * java.base/jdk.internal.module
29 * @library /test/lib
30 * @build ConfigurationTest
31 * jdk.test.lib.util.ModuleUtils
32 * @run junit ConfigurationTest
33 * @summary Basic tests for java.lang.module.Configuration
34 */
35
36 import java.io.IOException;
37 import java.io.OutputStream;
38 import java.lang.module.Configuration;
39 import java.lang.module.FindException;
40 import java.lang.module.ModuleDescriptor;
41 import java.lang.module.ModuleDescriptor.Requires;
42 import java.lang.module.ModuleFinder;
43 import java.lang.module.ResolutionException;
44 import java.lang.module.ResolvedModule;
45 import java.nio.file.Files;
46 import java.nio.file.Path;
47 import java.nio.file.Paths;
48 import java.util.List;
49 import java.util.Set;
50 import java.util.stream.Stream;
51 import jdk.internal.access.SharedSecrets;
52 import jdk.internal.module.ModuleTarget;
53
54 import jdk.test.lib.util.ModuleInfoWriter;
55 import jdk.test.lib.util.ModuleUtils;
56
57 import org.junit.jupiter.api.Test;
58 import org.junit.jupiter.params.ParameterizedTest;
59 import org.junit.jupiter.params.provider.MethodSource;
60 import org.junit.jupiter.params.provider.CsvSource;
61 import static org.junit.jupiter.api.Assertions.*;
62
63 class ConfigurationTest {
64
65 /**
66 * Creates a "non-strict" builder for building a module. This allows the
67 * test the create ModuleDescriptor objects that do not require java.base.
68 */
69 private static ModuleDescriptor.Builder newBuilder(String mn) {
70 return SharedSecrets.getJavaLangModuleAccess()
71 .newModuleBuilder(mn, false, Set.of());
72 }
73
74 /**
75 * Basic test of resolver
76 * m1 requires m2, m2 requires m3
77 */
78 @Test
79 void testBasic() {
80 ModuleDescriptor descriptor1 = newBuilder("m1")
81 .requires("m2")
82 .build();
83
84 ModuleDescriptor descriptor2 = newBuilder("m2")
85 .requires("m3")
86 .build();
87
88 ModuleDescriptor descriptor3 = newBuilder("m3")
89 .build();
90
91 ModuleFinder finder
92 = ModuleUtils.finderOf(descriptor1, descriptor2, descriptor3);
93
94 Configuration cf = resolve(finder, "m1");
95
96 assertTrue(cf.modules().size() == 3);
97
98 assertTrue(cf.findModule("m1").isPresent());
99 assertTrue(cf.findModule("m2").isPresent());
100 assertTrue(cf.findModule("m3").isPresent());
101
102 assertTrue(cf.parents().size() == 1);
103 assertTrue(cf.parents().get(0) == Configuration.empty());
104
105 ResolvedModule m1 = cf.findModule("m1").get();
106 ResolvedModule m2 = cf.findModule("m2").get();
107 ResolvedModule m3 = cf.findModule("m3").get();
108
109 // m1 reads m2
110 assertTrue(m1.reads().size() == 1);
111 assertTrue(m1.reads().contains(m2));
112
113 // m2 reads m3
114 assertTrue(m2.reads().size() == 1);
115 assertTrue(m2.reads().contains(m3));
116
117 // m3 reads nothing
118 assertTrue(m3.reads().size() == 0);
119
120 // toString
121 assertTrue(cf.toString().contains("m1"));
122 assertTrue(cf.toString().contains("m2"));
123 assertTrue(cf.toString().contains("m3"));
124 }
125
126
127 /**
128 * Basic test of "requires transitive":
129 * m1 requires m2, m2 requires transitive m3
130 */
131 @Test
132 void testRequiresTransitive1() {
133 // m1 requires m2, m2 requires transitive m3
134 ModuleDescriptor descriptor1 = newBuilder("m1")
135 .requires("m2")
136 .build();
137
138 ModuleDescriptor descriptor2 = newBuilder("m2")
139 .requires(Set.of(Requires.Modifier.TRANSITIVE), "m3")
140 .build();
141
142 ModuleDescriptor descriptor3 = newBuilder("m3")
143 .build();
144
145 ModuleFinder finder
146 = ModuleUtils.finderOf(descriptor1, descriptor2, descriptor3);
147
148 Configuration cf = resolve(finder, "m1");
149
150 assertTrue(cf.modules().size() == 3);
151
152 assertTrue(cf.findModule("m1").isPresent());
153 assertTrue(cf.findModule("m2").isPresent());
154 assertTrue(cf.findModule("m3").isPresent());
155
156 assertTrue(cf.parents().size() == 1);
157 assertTrue(cf.parents().get(0) == Configuration.empty());
158
159 ResolvedModule m1 = cf.findModule("m1").get();
160 ResolvedModule m2 = cf.findModule("m2").get();
161 ResolvedModule m3 = cf.findModule("m3").get();
162
163 // m1 reads m2 and m3
164 assertTrue(m1.reads().size() == 2);
165 assertTrue(m1.reads().contains(m2));
166 assertTrue(m1.reads().contains(m3));
167
168 // m2 reads m3
169 assertTrue(m2.reads().size() == 1);
170 assertTrue(m2.reads().contains(m3));
171
172 // m3 reads nothing
173 assertTrue(m3.reads().size() == 0);
174 }
175
176
177 /**
178 * Basic test of "requires transitive" with configurations.
179 *
180 * The test consists of three configurations:
181 * - Configuration cf1: m1, m2 requires transitive m1
182 * - Configuration cf2: m3 requires m2
183 */
184 @Test
185 void testRequiresTransitive2() {
186
187 // cf1: m1 and m2, m2 requires transitive m1
188
189 ModuleDescriptor descriptor1 = newBuilder("m1")
190 .build();
191
192 ModuleDescriptor descriptor2 = newBuilder("m2")
193 .requires(Set.of(Requires.Modifier.TRANSITIVE), "m1")
194 .build();
195
196 ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1, descriptor2);
197
198 Configuration cf1 = resolve(finder1, "m2");
199
200 assertTrue(cf1.modules().size() == 2);
201 assertTrue(cf1.findModule("m1").isPresent());
202 assertTrue(cf1.findModule("m2").isPresent());
203 assertTrue(cf1.parents().size() == 1);
204 assertTrue(cf1.parents().get(0) == Configuration.empty());
205
206 ResolvedModule m1 = cf1.findModule("m1").get();
207 ResolvedModule m2 = cf1.findModule("m2").get();
208
209 assertTrue(m1.reads().size() == 0);
210 assertTrue(m2.reads().size() == 1);
211 assertTrue(m2.reads().contains(m1));
212
213
214 // cf2: m3, m3 requires m2
215
216 ModuleDescriptor descriptor3 = newBuilder("m3")
217 .requires("m2")
218 .build();
219
220 ModuleFinder finder2 = ModuleUtils.finderOf(descriptor3);
221
222 Configuration cf2 = resolve(cf1, finder2, "m3");
223
224 assertTrue(cf2.modules().size() == 1);
225 assertTrue(cf2.findModule("m1").isPresent()); // in parent
226 assertTrue(cf2.findModule("m2").isPresent()); // in parent
227 assertTrue(cf2.findModule("m3").isPresent());
228 assertTrue(cf2.parents().size() == 1);
229 assertTrue(cf2.parents().get(0) == cf1);
230
231 ResolvedModule m3 = cf2.findModule("m3").get();
232 assertTrue(m3.configuration() == cf2);
233 assertTrue(m3.reads().size() == 2);
234 assertTrue(m3.reads().contains(m1));
235 assertTrue(m3.reads().contains(m2));
236 }
237
238
239 /**
240 * Basic test of "requires transitive" with configurations.
241 *
242 * The test consists of three configurations:
243 * - Configuration cf1: m1
244 * - Configuration cf2: m2 requires transitive m1, m3 requires m2
245 */
246 @Test
247 void testRequiresTransitive3() {
248
249 // cf1: m1
250
251 ModuleDescriptor descriptor1 = newBuilder("m1").build();
252
253 ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1);
254
255 Configuration cf1 = resolve(finder1, "m1");
256
257 assertTrue(cf1.modules().size() == 1);
258 assertTrue(cf1.findModule("m1").isPresent());
259 assertTrue(cf1.parents().size() == 1);
260 assertTrue(cf1.parents().get(0) == Configuration.empty());
261
262 ResolvedModule m1 = cf1.findModule("m1").get();
263 assertTrue(m1.reads().size() == 0);
264
265
266 // cf2: m2, m3: m2 requires transitive m1, m3 requires m2
267
268 ModuleDescriptor descriptor2 = newBuilder("m2")
269 .requires(Set.of(Requires.Modifier.TRANSITIVE), "m1")
270 .build();
271
272 ModuleDescriptor descriptor3 = newBuilder("m3")
273 .requires("m2")
274 .build();
275
276 ModuleFinder finder2 = ModuleUtils.finderOf(descriptor2, descriptor3);
277
278 Configuration cf2 = resolve(cf1, finder2, "m3");
279
280 assertTrue(cf2.modules().size() == 2);
281 assertTrue(cf2.findModule("m1").isPresent()); // in parent
282 assertTrue(cf2.findModule("m2").isPresent());
283 assertTrue(cf2.findModule("m3").isPresent());
284 assertTrue(cf2.parents().size() == 1);
285 assertTrue(cf2.parents().get(0) == cf1);
286
287 ResolvedModule m2 = cf2.findModule("m2").get();
288 ResolvedModule m3 = cf2.findModule("m3").get();
289
290 assertTrue(m2.configuration() == cf2);
291 assertTrue(m2.reads().size() == 1);
292 assertTrue(m2.reads().contains(m1));
293
294 assertTrue(m3.configuration() == cf2);
295 assertTrue(m3.reads().size() == 2);
296 assertTrue(m3.reads().contains(m1));
297 assertTrue(m3.reads().contains(m2));
298 }
299
300
301 /**
302 * Basic test of "requires transitive" with configurations.
303 *
304 * The test consists of three configurations:
305 * - Configuration cf1: m1
306 * - Configuration cf2: m2 requires transitive m1
307 * - Configuraiton cf3: m3 requires m2
308 */
309 @Test
310 void testRequiresTransitive4() {
311
312 // cf1: m1
313
314 ModuleDescriptor descriptor1 = newBuilder("m1").build();
315
316 ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1);
317
318 Configuration cf1 = resolve(finder1, "m1");
319
320 assertTrue(cf1.modules().size() == 1);
321 assertTrue(cf1.findModule("m1").isPresent());
322 assertTrue(cf1.parents().size() == 1);
323 assertTrue(cf1.parents().get(0) == Configuration.empty());
324
325 ResolvedModule m1 = cf1.findModule("m1").get();
326 assertTrue(m1.reads().size() == 0);
327
328
329 // cf2: m2 requires transitive m1
330
331 ModuleDescriptor descriptor2 = newBuilder("m2")
332 .requires(Set.of(Requires.Modifier.TRANSITIVE), "m1")
333 .build();
334
335 ModuleFinder finder2 = ModuleUtils.finderOf(descriptor2);
336
337 Configuration cf2 = resolve(cf1, finder2, "m2");
338
339 assertTrue(cf2.modules().size() == 1);
340 assertTrue(cf2.findModule("m1").isPresent()); // in parent
341 assertTrue(cf2.findModule("m2").isPresent());
342 assertTrue(cf2.parents().size() == 1);
343 assertTrue(cf2.parents().get(0) == cf1);
344
345 ResolvedModule m2 = cf2.findModule("m2").get();
346
347 assertTrue(m2.configuration() == cf2);
348 assertTrue(m2.reads().size() == 1);
349 assertTrue(m2.reads().contains(m1));
350
351
352 // cf3: m3 requires m2
353
354 ModuleDescriptor descriptor3 = newBuilder("m3")
355 .requires("m2")
356 .build();
357
358 ModuleFinder finder3 = ModuleUtils.finderOf(descriptor3);
359
360 Configuration cf3 = resolve(cf2, finder3, "m3");
361
362 assertTrue(cf3.modules().size() == 1);
363 assertTrue(cf3.findModule("m1").isPresent()); // in parent
364 assertTrue(cf3.findModule("m2").isPresent()); // in parent
365 assertTrue(cf3.findModule("m3").isPresent());
366 assertTrue(cf3.parents().size() == 1);
367 assertTrue(cf3.parents().get(0) == cf2);
368
369 ResolvedModule m3 = cf3.findModule("m3").get();
370
371 assertTrue(m3.configuration() == cf3);
372 assertTrue(m3.reads().size() == 2);
373 assertTrue(m3.reads().contains(m1));
374 assertTrue(m3.reads().contains(m2));
375 }
376
377
378 /**
379 * Basic test of "requires transitive" with configurations.
380 *
381 * The test consists of two configurations:
382 * - Configuration cf1: m1, m2 requires transitive m1
383 * - Configuration cf2: m3 requires transitive m2, m4 requires m3
384 */
385 @Test
386 void testRequiresTransitive5() {
387
388 // cf1: m1, m2 requires transitive m1
389
390 ModuleDescriptor descriptor1 = newBuilder("m1")
391 .build();
392
393 ModuleDescriptor descriptor2 = newBuilder("m2")
394 .requires(Set.of(Requires.Modifier.TRANSITIVE), "m1")
395 .build();
396
397 ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1, descriptor2);
398
399 Configuration cf1 = resolve(finder1, "m2");
400
401 assertTrue(cf1.modules().size() == 2);
402 assertTrue(cf1.findModule("m1").isPresent());
403 assertTrue(cf1.findModule("m2").isPresent());
404 assertTrue(cf1.parents().size() == 1);
405 assertTrue(cf1.parents().get(0) == Configuration.empty());
406
407 ResolvedModule m1 = cf1.findModule("m1").get();
408 ResolvedModule m2 = cf1.findModule("m2").get();
409
410 assertTrue(m1.configuration() == cf1);
411 assertTrue(m1.reads().size() == 0);
412
413 assertTrue(m2.configuration() == cf1);
414 assertTrue(m2.reads().size() == 1);
415 assertTrue(m2.reads().contains(m1));
416
417
418 // cf2: m3 requires transitive m2, m4 requires m3
419
420 ModuleDescriptor descriptor3 = newBuilder("m3")
421 .requires(Set.of(Requires.Modifier.TRANSITIVE), "m2")
422 .build();
423
424 ModuleDescriptor descriptor4 = newBuilder("m4")
425 .requires("m3")
426 .build();
427
428
429 ModuleFinder finder2 = ModuleUtils.finderOf(descriptor3, descriptor4);
430
431 Configuration cf2 = resolve(cf1, finder2, "m3", "m4");
432
433 assertTrue(cf2.modules().size() == 2);
434 assertTrue(cf2.findModule("m1").isPresent()); // in parent
435 assertTrue(cf2.findModule("m2").isPresent()); // in parent
436 assertTrue(cf2.findModule("m3").isPresent());
437 assertTrue(cf2.findModule("m4").isPresent());
438 assertTrue(cf2.parents().size() == 1);
439 assertTrue(cf2.parents().get(0) == cf1);
440
441 ResolvedModule m3 = cf2.findModule("m3").get();
442 ResolvedModule m4 = cf2.findModule("m4").get();
443
444 assertTrue(m3.configuration() == cf2);
445 assertTrue(m3.reads().size() == 2);
446 assertTrue(m3.reads().contains(m1));
447 assertTrue(m3.reads().contains(m2));
448
449 assertTrue(m4.configuration() == cf2);
450 assertTrue(m4.reads().size() == 3);
451 assertTrue(m4.reads().contains(m1));
452 assertTrue(m4.reads().contains(m2));
453 assertTrue(m4.reads().contains(m3));
454 }
455
456
457 /**
458 * Basic test of "requires static":
459 * m1 requires static m2
460 * m2 is not observable
461 * resolve m1
462 */
463 @Test
464 void testRequiresStatic1() {
465 ModuleDescriptor descriptor1 = newBuilder("m1")
466 .requires(Set.of(Requires.Modifier.STATIC), "m2")
467 .build();
468
469 ModuleFinder finder = ModuleUtils.finderOf(descriptor1);
470
471 Configuration cf = resolve(finder, "m1");
472
473 assertTrue(cf.modules().size() == 1);
474
475 ResolvedModule m1 = cf.findModule("m1").get();
476 assertTrue(m1.reads().size() == 0);
477 }
478
479
480 /**
481 * Basic test of "requires static":
482 * m1 requires static m2
483 * m2
484 * resolve m1
485 */
486 @Test
487 void testRequiresStatic2() {
488 ModuleDescriptor descriptor1 = newBuilder("m1")
489 .requires(Set.of(Requires.Modifier.STATIC), "m2")
490 .build();
491
492 ModuleDescriptor descriptor2 = newBuilder("m2")
493 .build();
494
495 ModuleFinder finder = ModuleUtils.finderOf(descriptor1, descriptor2);
496
497 Configuration cf = resolve(finder, "m1");
498
499 assertTrue(cf.modules().size() == 1);
500
501 ResolvedModule m1 = cf.findModule("m1").get();
502 assertTrue(m1.reads().size() == 0);
503 }
504
505
506 /**
507 * Basic test of "requires static":
508 * m1 requires static m2
509 * m2
510 * resolve m1, m2
511 */
512 @Test
513 void testRequiresStatic3() {
514 ModuleDescriptor descriptor1 = newBuilder("m1")
515 .requires(Set.of(Requires.Modifier.STATIC), "m2")
516 .build();
517
518 ModuleDescriptor descriptor2 = newBuilder("m2")
519 .build();
520
521 ModuleFinder finder = ModuleUtils.finderOf(descriptor1, descriptor2);
522
523 Configuration cf = resolve(finder, "m1", "m2");
524
525 assertTrue(cf.modules().size() == 2);
526
527 ResolvedModule m1 = cf.findModule("m1").get();
528 ResolvedModule m2 = cf.findModule("m2").get();
529
530 assertTrue(m1.reads().size() == 1);
531 assertTrue(m1.reads().contains(m2));
532
533 assertTrue(m2.reads().size() == 0);
534 }
535
536
537 /**
538 * Basic test of "requires static":
539 * m1 requires m2, m3
540 * m2 requires static m2
541 * m3
542 */
543 @Test
544 void testRequiresStatic4() {
545 ModuleDescriptor descriptor1 = newBuilder("m1")
546 .requires("m2")
547 .requires("m3")
548 .build();
549
550 ModuleDescriptor descriptor2 = newBuilder("m2")
551 .requires(Set.of(Requires.Modifier.STATIC), "m3")
552 .build();
553
554 ModuleDescriptor descriptor3 = newBuilder("m3")
555 .build();
556
557 ModuleFinder finder
558 = ModuleUtils.finderOf(descriptor1, descriptor2, descriptor3);
559
560 Configuration cf = resolve(finder, "m1");
561
562 assertTrue(cf.modules().size() == 3);
563
564 ResolvedModule m1 = cf.findModule("m1").get();
565 ResolvedModule m2 = cf.findModule("m2").get();
566 ResolvedModule m3 = cf.findModule("m3").get();
567
568 assertTrue(m1.reads().size() == 2);
569 assertTrue(m1.reads().contains(m2));
570 assertTrue(m1.reads().contains(m3));
571
572 assertTrue(m2.reads().size() == 1);
573 assertTrue(m2.reads().contains(m3));
574
575 assertTrue(m3.reads().size() == 0);
576 }
577
578
579 /**
580 * Basic test of "requires static":
581 * The test consists of three configurations:
582 * - Configuration cf1: m1, m2
583 * - Configuration cf2: m3 requires m1, requires static m2
584 */
585 @Test
586 void testRequiresStatic5() {
587 ModuleDescriptor descriptor1 = newBuilder("m1")
588 .build();
589
590 ModuleDescriptor descriptor2 = newBuilder("m2")
591 .build();
592
593 ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1, descriptor2);
594
595 Configuration cf1 = resolve(finder1, "m1", "m2");
596
597 assertTrue(cf1.modules().size() == 2);
598 assertTrue(cf1.findModule("m1").isPresent());
599 assertTrue(cf1.findModule("m2").isPresent());
600
601 ModuleDescriptor descriptor3 = newBuilder("m3")
602 .requires("m1")
603 .requires(Set.of(Requires.Modifier.STATIC), "m2")
604 .build();
605
606 ModuleFinder finder2 = ModuleUtils.finderOf(descriptor3);
607
608 Configuration cf2 = resolve(cf1, finder2, "m3");
609
610 assertTrue(cf2.modules().size() == 1);
611 assertTrue(cf2.findModule("m3").isPresent());
612
613 ResolvedModule m1 = cf1.findModule("m1").get();
614 ResolvedModule m2 = cf1.findModule("m2").get();
615 ResolvedModule m3 = cf2.findModule("m3").get();
616
617 assertTrue(m3.reads().size() == 2);
618 assertTrue(m3.reads().contains(m1));
619 assertTrue(m3.reads().contains(m2));
620 }
621
622
623 /**
624 * Basic test of "requires static":
625 * The test consists of three configurations:
626 * - Configuration cf1: m1
627 * - Configuration cf2: m3 requires m1, requires static m2
628 */
629 @Test
630 void testRequiresStatic6() {
631 ModuleDescriptor descriptor1 = newBuilder("m1")
632 .build();
633
634 ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1);
635
636 Configuration cf1 = resolve(finder1, "m1");
637
638 assertTrue(cf1.modules().size() == 1);
639 assertTrue(cf1.findModule("m1").isPresent());
640
641 ModuleDescriptor descriptor3 = newBuilder("m3")
642 .requires("m1")
643 .requires(Set.of(Requires.Modifier.STATIC), "m2")
644 .build();
645
646 ModuleFinder finder2 = ModuleUtils.finderOf(descriptor3);
647
648 Configuration cf2 = resolve(cf1, finder2, "m3");
649
650 assertTrue(cf2.modules().size() == 1);
651 assertTrue(cf2.findModule("m3").isPresent());
652
653 ResolvedModule m1 = cf1.findModule("m1").get();
654 ResolvedModule m3 = cf2.findModule("m3").get();
655
656 assertTrue(m3.reads().size() == 1);
657 assertTrue(m3.reads().contains(m1));
658 }
659
660
661 /**
662 * Basic test of "requires static":
663 * (m1 not observable)
664 * m2 requires transitive static m1
665 * m3 requires m2
666 */
667 @Test
668 void testRequiresStatic7() {
669 ModuleDescriptor descriptor1 = null; // not observable
670
671 ModuleDescriptor descriptor2 = newBuilder("m2")
672 .requires(Set.of(Requires.Modifier.TRANSITIVE,
673 Requires.Modifier.STATIC),
674 "m1")
675 .build();
676
677 ModuleDescriptor descriptor3 = newBuilder("m3")
678 .requires("m2")
679 .build();
680
681 ModuleFinder finder = ModuleUtils.finderOf(descriptor2, descriptor3);
682
683 Configuration cf = resolve(finder, "m3");
684
685 assertTrue(cf.modules().size() == 2);
686 assertTrue(cf.findModule("m2").isPresent());
687 assertTrue(cf.findModule("m3").isPresent());
688 ResolvedModule m2 = cf.findModule("m2").get();
689 ResolvedModule m3 = cf.findModule("m3").get();
690 assertTrue(m2.reads().isEmpty());
691 assertTrue(m3.reads().size() == 1);
692 assertTrue(m3.reads().contains(m2));
693 }
694
695
696 /**
697 * Basic test of "requires static":
698 * - Configuration cf1: m2 requires transitive static m1
699 * - Configuration cf2: m3 requires m2
700 */
701 @Test
702 void testRequiresStatic8() {
703 ModuleDescriptor descriptor1 = null; // not observable
704
705 ModuleDescriptor descriptor2 = newBuilder("m2")
706 .requires(Set.of(Requires.Modifier.TRANSITIVE,
707 Requires.Modifier.STATIC),
708 "m1")
709 .build();
710
711 ModuleFinder finder1 = ModuleUtils.finderOf(descriptor2);
712
713 Configuration cf1 = resolve(finder1, "m2");
714
715 assertTrue(cf1.modules().size() == 1);
716 assertTrue(cf1.findModule("m2").isPresent());
717 ResolvedModule m2 = cf1.findModule("m2").get();
718 assertTrue(m2.reads().isEmpty());
719
720 ModuleDescriptor descriptor3 = newBuilder("m3")
721 .requires("m2")
722 .build();
723
724 ModuleFinder finder2 = ModuleUtils.finderOf(descriptor3);
725
726 Configuration cf2 = resolve(cf1, finder2, "m3");
727
728 assertTrue(cf2.modules().size() == 1);
729 assertTrue(cf2.findModule("m3").isPresent());
730 ResolvedModule m3 = cf2.findModule("m3").get();
731 assertTrue(m3.reads().size() == 1);
732 assertTrue(m3.reads().contains(m2));
733 }
734
735
736 /**
737 * Basic test of binding services
738 * m1 uses p.S
739 * m2 provides p.S
740 */
741 @Test
742 void testServiceBinding1() {
743 ModuleDescriptor descriptor1 = newBuilder("m1")
744 .exports("p")
745 .uses("p.S")
746 .build();
747
748 ModuleDescriptor descriptor2 = newBuilder("m2")
749 .requires("m1")
750 .provides("p.S", List.of("q.T"))
751 .build();
752
753 ModuleFinder finder = ModuleUtils.finderOf(descriptor1, descriptor2);
754
755 Configuration cf = resolveAndBind(finder, "m1");
756
757 assertTrue(cf.modules().size() == 2);
758 assertTrue(cf.findModule("m1").isPresent());
759 assertTrue(cf.findModule("m2").isPresent());
760 assertTrue(cf.parents().size() == 1);
761 assertTrue(cf.parents().get(0) == Configuration.empty());
762
763 ResolvedModule m1 = cf.findModule("m1").get();
764 ResolvedModule m2 = cf.findModule("m2").get();
765
766 assertTrue(m1.configuration() == cf);
767 assertTrue(m1.reads().size() == 0);
768
769 assertTrue(m2.configuration() == cf);
770 assertTrue(m2.reads().size() == 1);
771 assertTrue(m2.reads().contains(m1));
772 }
773
774
775 /**
776 * Basic test of binding services
777 * m1 uses p.S1
778 * m2 provides p.S1, m2 uses p.S2
779 * m3 provides p.S2
780 */
781 @Test
782 void testServiceBinding2() {
783 ModuleDescriptor descriptor1 = newBuilder("m1")
784 .exports("p")
785 .uses("p.S1")
786 .build();
787
788 ModuleDescriptor descriptor2 = newBuilder("m2")
789 .requires("m1")
790 .uses("p.S2")
791 .provides("p.S1", List.of("q.Service1Impl"))
792 .build();
793
794 ModuleDescriptor descriptor3 = newBuilder("m3")
795 .requires("m1")
796 .provides("p.S2", List.of("q.Service2Impl"))
797 .build();
798
799 ModuleFinder finder
800 = ModuleUtils.finderOf(descriptor1, descriptor2, descriptor3);
801
802 Configuration cf = resolveAndBind(finder, "m1");
803
804 assertTrue(cf.modules().size() == 3);
805 assertTrue(cf.findModule("m1").isPresent());
806 assertTrue(cf.findModule("m2").isPresent());
807 assertTrue(cf.findModule("m3").isPresent());
808 assertTrue(cf.parents().size() == 1);
809 assertTrue(cf.parents().get(0) == Configuration.empty());
810
811 ResolvedModule m1 = cf.findModule("m1").get();
812 ResolvedModule m2 = cf.findModule("m2").get();
813 ResolvedModule m3 = cf.findModule("m3").get();
814
815 assertTrue(m1.configuration() == cf);
816 assertTrue(m1.reads().size() == 0);
817
818 assertTrue(m2.configuration() == cf);
819 assertTrue(m2.reads().size() == 1);
820 assertTrue(m2.reads().contains(m1));
821
822 assertTrue(m3.configuration() == cf);
823 assertTrue(m3.reads().size() == 1);
824 assertTrue(m3.reads().contains(m1));
825 }
826
827
828 /**
829 * Basic test of binding services with configurations.
830 *
831 * The test consists of two configurations:
832 * - Configuration cf1: m1 uses p.S
833 * - Configuration cf2: m2 provides p.S
834 */
835 @Test
836 void testServiceBindingWithConfigurations1() {
837 ModuleDescriptor descriptor1 = newBuilder("m1")
838 .exports("p")
839 .uses("p.S")
840 .build();
841
842 ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1);
843
844 Configuration cf1 = resolve(finder1, "m1");
845
846 assertTrue(cf1.modules().size() == 1);
847 assertTrue(cf1.findModule("m1").isPresent());
848
849 ModuleDescriptor descriptor2 = newBuilder("m2")
850 .requires("m1")
851 .provides("p.S", List.of("q.T"))
852 .build();
853
854 ModuleFinder finder2 = ModuleUtils.finderOf(descriptor2);
855
856 Configuration cf2 = resolveAndBind(cf1, finder2); // no roots
857
858 assertTrue(cf2.parents().size() == 1);
859 assertTrue(cf2.parents().get(0) == cf1);
860
861 assertTrue(cf2.modules().size() == 1);
862 assertTrue(cf2.findModule("m2").isPresent());
863
864 ResolvedModule m1 = cf1.findModule("m1").get();
865 ResolvedModule m2 = cf2.findModule("m2").get();
866
867 assertTrue(m2.reads().size() == 1);
868 assertTrue(m2.reads().contains(m1));
869 }
870
871
872 /**
873 * Basic test of binding services with configurations.
874 *
875 * The test consists of two configurations:
876 * - Configuration cf1: m1 uses p.S && provides p.S,
877 * m2 provides p.S
878 * - Configuration cf2: m3 provides p.S
879 * m4 provides p.S
880 */
881 @Test
882 void testServiceBindingWithConfigurations2() {
883 ModuleDescriptor descriptor1 = newBuilder("m1")
884 .exports("p")
885 .uses("p.S")
886 .provides("p.S", List.of("p1.ServiceImpl"))
887 .build();
888
889 ModuleDescriptor descriptor2 = newBuilder("m2")
890 .requires("m1")
891 .provides("p.S", List.of("p2.ServiceImpl"))
892 .build();
893
894 ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1, descriptor2);
895
896 Configuration cf1 = resolveAndBind(finder1, "m1");
897
898 assertTrue(cf1.modules().size() == 2);
899 assertTrue(cf1.findModule("m1").isPresent());
900 assertTrue(cf1.findModule("m2").isPresent());
901
902
903 ModuleDescriptor descriptor3 = newBuilder("m3")
904 .requires("m1")
905 .provides("p.S", List.of("p3.ServiceImpl"))
906 .build();
907
908 ModuleDescriptor descriptor4 = newBuilder("m4")
909 .requires("m1")
910 .provides("p.S", List.of("p4.ServiceImpl"))
911 .build();
912
913 ModuleFinder finder2 = ModuleUtils.finderOf(descriptor3, descriptor4);
914
915 Configuration cf2 = resolveAndBind(cf1, finder2); // no roots
916
917 assertTrue(cf2.parents().size() == 1);
918 assertTrue(cf2.parents().get(0) == cf1);
919
920 assertTrue(cf2.modules().size() == 2);
921 assertTrue(cf2.findModule("m3").isPresent());
922 assertTrue(cf2.findModule("m4").isPresent());
923
924 ResolvedModule m1 = cf2.findModule("m1").get(); // should find in parent
925 ResolvedModule m2 = cf2.findModule("m2").get();
926 ResolvedModule m3 = cf2.findModule("m3").get();
927 ResolvedModule m4 = cf2.findModule("m4").get();
928
929 assertTrue(m1.reads().size() == 0);
930
931 assertTrue(m2.reads().size() == 1);
932 assertTrue(m2.reads().contains(m1));
933
934 assertTrue(m3.reads().size() == 1);
935 assertTrue(m3.reads().contains(m1));
936
937 assertTrue(m4.reads().size() == 1);
938 assertTrue(m4.reads().contains(m1));
939 }
940
941
942 /**
943 * Basic test of binding services with configurations.
944 *
945 * Configuration cf1: p@1.0 provides p.S
946 * Test configuration cf2: m1 uses p.S, p@2.0 provides p.S
947 * Test configuration cf2: m1 uses p.S
948 */
949 @Test
950 void testServiceBindingWithConfigurations3() {
951 ModuleDescriptor service = newBuilder("s")
952 .exports("p")
953 .build();
954
955 ModuleDescriptor provider_v1 = newBuilder("p")
956 .version("1.0")
957 .requires("s")
958 .provides("p.S", List.of("q.T"))
959 .build();
960
961 ModuleFinder finder1 = ModuleUtils.finderOf(service, provider_v1);
962
963 Configuration cf1 = resolve(finder1, "p");
964
965 assertTrue(cf1.modules().size() == 2);
966 assertTrue(cf1.findModule("s").isPresent());
967 assertTrue(cf1.findModule("p").isPresent());
968
969 // p@1.0 in cf1
970 ResolvedModule p = cf1.findModule("p").get();
971 assertEquals(provider_v1, p.reference().descriptor());
972
973
974 ModuleDescriptor descriptor1 = newBuilder("m1")
975 .requires("s")
976 .uses("p.S")
977 .build();
978
979 ModuleDescriptor provider_v2 = newBuilder("p")
980 .version("2.0")
981 .requires("s")
982 .provides("p.S", List.of("q.T"))
983 .build();
984
985 ModuleFinder finder2 = ModuleUtils.finderOf(descriptor1, provider_v2);
986
987
988 // finder2 is the before ModuleFinder and so p@2.0 should be located
989
990 Configuration cf2 = resolveAndBind(cf1, finder2, "m1");
991
992 assertTrue(cf2.parents().size() == 1);
993 assertTrue(cf2.parents().get(0) == cf1);
994 assertTrue(cf2.modules().size() == 2);
995
996 // p should be found in cf2
997 p = cf2.findModule("p").get();
998 assertTrue(p.configuration() == cf2);
999 assertEquals(provider_v2, p.reference().descriptor());
1000
1001
1002 // finder2 is the after ModuleFinder and so p@2.0 should not be located
1003 // as module p is in parent configuration.
1004
1005 cf2 = resolveAndBind(cf1, ModuleFinder.of(), finder2, "m1");
1006
1007 assertTrue(cf2.parents().size() == 1);
1008 assertTrue(cf2.parents().get(0) == cf1);
1009 assertTrue(cf2.modules().size() == 1);
1010
1011 // p should be found in cf1
1012 p = cf2.findModule("p").get();
1013 assertTrue(p.configuration() == cf1);
1014 assertEquals(provider_v1, p.reference().descriptor());
1015 }
1016
1017
1018 /**
1019 * Basic test with two module finders.
1020 *
1021 * Module m2 can be found by both the before and after finders.
1022 */
1023 @Test
1024 void testWithTwoFinders1() {
1025 ModuleDescriptor descriptor1 = newBuilder("m1")
1026 .requires("m2")
1027 .build();
1028
1029 ModuleDescriptor descriptor2_v1 = newBuilder("m2")
1030 .version("1.0")
1031 .build();
1032
1033 ModuleDescriptor descriptor2_v2 = newBuilder("m2")
1034 .version("2.0")
1035 .build();
1036
1037 ModuleFinder finder1 = ModuleUtils.finderOf(descriptor2_v1);
1038 ModuleFinder finder2 = ModuleUtils.finderOf(descriptor1, descriptor2_v2);
1039
1040 Configuration cf = resolve(finder1, finder2, "m1");
1041
1042 assertTrue(cf.modules().size() == 2);
1043 assertTrue(cf.findModule("m1").isPresent());
1044 assertTrue(cf.findModule("m2").isPresent());
1045
1046 ResolvedModule m1 = cf.findModule("m1").get();
1047 ResolvedModule m2 = cf.findModule("m2").get();
1048
1049 assertEquals(descriptor1, m1.reference().descriptor());
1050 assertEquals(descriptor2_v1, m2.reference().descriptor());
1051 }
1052
1053
1054 /**
1055 * Basic test with two modules finders and service binding.
1056 *
1057 * The before and after ModuleFinders both locate a service provider module
1058 * named "m2" that provide implementations of the same service type.
1059 */
1060 @Test
1061 void testWithTwoFinders2() {
1062 ModuleDescriptor descriptor1 = newBuilder("m1")
1063 .exports("p")
1064 .uses("p.S")
1065 .build();
1066
1067 ModuleDescriptor descriptor2_v1 = newBuilder("m2")
1068 .requires("m1")
1069 .provides("p.S", List.of("q.T"))
1070 .build();
1071
1072 ModuleDescriptor descriptor2_v2 = newBuilder("m2")
1073 .requires("m1")
1074 .provides("p.S", List.of("q.T"))
1075 .build();
1076
1077 ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1, descriptor2_v1);
1078 ModuleFinder finder2 = ModuleUtils.finderOf(descriptor2_v2);
1079
1080 Configuration cf = resolveAndBind(finder1, finder2, "m1");
1081
1082 assertTrue(cf.modules().size() == 2);
1083 assertTrue(cf.findModule("m1").isPresent());
1084 assertTrue(cf.findModule("m2").isPresent());
1085
1086 ResolvedModule m1 = cf.findModule("m1").get();
1087 ResolvedModule m2 = cf.findModule("m2").get();
1088
1089 assertEquals(descriptor1, m1.reference().descriptor());
1090 assertEquals(descriptor2_v1, m2.reference().descriptor());
1091 }
1092
1093
1094 /**
1095 * Basic test for resolving a module that is located in the parent
1096 * configuration.
1097 */
1098 @Test
1099 void testResolvedInParent1() {
1100 ModuleDescriptor descriptor1 = newBuilder("m1")
1101 .build();
1102
1103 ModuleFinder finder = ModuleUtils.finderOf(descriptor1);
1104
1105 Configuration cf1 = resolve(finder, "m1");
1106
1107 assertTrue(cf1.modules().size() == 1);
1108 assertTrue(cf1.findModule("m1").isPresent());
1109
1110 Configuration cf2 = resolve(cf1, finder, "m1");
1111
1112 assertTrue(cf2.modules().size() == 1);
1113 }
1114
1115
1116 /**
1117 * Basic test for resolving a module that has a dependency on a module
1118 * in the parent configuration.
1119 */
1120 @Test
1121 void testResolvedInParent2() {
1122 ModuleDescriptor descriptor1 = newBuilder("m1").build();
1123
1124 ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1);
1125
1126 Configuration cf1 = resolve(finder1, "m1");
1127
1128 assertTrue(cf1.modules().size() == 1);
1129 assertTrue(cf1.findModule("m1").isPresent());
1130
1131
1132 ModuleDescriptor descriptor2 = newBuilder("m2")
1133 .requires("m1")
1134 .build();
1135
1136 ModuleFinder finder2 = ModuleUtils.finderOf(descriptor2);
1137
1138 Configuration cf2 = resolve(cf1, ModuleFinder.of(), finder2, "m2");
1139
1140 assertTrue(cf2.modules().size() == 1);
1141 assertTrue(cf2.findModule("m2").isPresent());
1142
1143 ResolvedModule m1 = cf2.findModule("m1").get(); // find in parent
1144 ResolvedModule m2 = cf2.findModule("m2").get();
1145
1146 assertTrue(m1.reads().size() == 0);
1147 assertTrue(m2.reads().size() == 1);
1148 assertTrue(m2.reads().contains(m1));
1149 }
1150
1151
1152 /**
1153 * Basic test of resolving a module that depends on modules in two parent
1154 * configurations.
1155 *
1156 * The test consists of three configurations:
1157 * - Configuration cf1: m1
1158 * - Configuration cf2: m2
1159 * - Configuration cf3(cf1,cf2): m3 requires m1, m2
1160 */
1161 @Test
1162 void testResolvedInMultipleParents1() {
1163 // Configuration cf1: m1
1164 ModuleDescriptor descriptor1 = newBuilder("m1").build();
1165 Configuration cf1 = resolve(ModuleUtils.finderOf(descriptor1), "m1");
1166 assertEquals(List.of(Configuration.empty()), cf1.parents());
1167 assertTrue(cf1.findModule("m1").isPresent());
1168 ResolvedModule m1 = cf1.findModule("m1").get();
1169 assertTrue(m1.configuration() == cf1);
1170
1171 // Configuration cf2: m2
1172 ModuleDescriptor descriptor2 = newBuilder("m2").build();
1173 Configuration cf2 = resolve(ModuleUtils.finderOf(descriptor2), "m2");
1174 assertEquals(List.of(Configuration.empty()), cf2.parents());
1175 assertTrue(cf2.findModule("m2").isPresent());
1176 ResolvedModule m2 = cf2.findModule("m2").get();
1177 assertTrue(m2.configuration() == cf2);
1178
1179 // Configuration cf3(cf1,cf2): m3 requires m1 and m2
1180 ModuleDescriptor descriptor3 = newBuilder("m3")
1181 .requires("m1")
1182 .requires("m2")
1183 .build();
1184 ModuleFinder finder = ModuleUtils.finderOf(descriptor3);
1185 Configuration cf3 = Configuration.resolve(
1186 finder,
1187 List.of(cf1, cf2), // parents
1188 ModuleFinder.of(),
1189 Set.of("m3"));
1190 assertEquals(List.of(cf1, cf2), cf3.parents());
1191 assertTrue(cf3.findModule("m3").isPresent());
1192 ResolvedModule m3 = cf3.findModule("m3").get();
1193 assertTrue(m3.configuration() == cf3);
1194
1195 // check readability
1196 assertTrue(m1.reads().isEmpty());
1197 assertTrue(m2.reads().isEmpty());
1198 assertEquals(Set.of(m1, m2), m3.reads());
1199 }
1200
1201
1202 /**
1203 * Basic test of resolving a module that depends on modules in three parent
1204 * configurations arranged in a diamond (two direct parents).
1205 *
1206 * The test consists of four configurations:
1207 * - Configuration cf1: m1
1208 * - Configuration cf2(cf1): m2 requires m1
1209 * - Configuration cf3(cf3): m3 requires m1
1210 * - Configuration cf4(cf2,cf3): m4 requires m1,m2,m3
1211 */
1212 @Test
1213 void testResolvedInMultipleParents2() {
1214 // Configuration cf1: m1
1215 ModuleDescriptor descriptor1 = newBuilder("m1").build();
1216 Configuration cf1 = resolve(ModuleUtils.finderOf(descriptor1), "m1");
1217 assertEquals( List.of(Configuration.empty()), cf1.parents());
1218 assertTrue(cf1.findModule("m1").isPresent());
1219 ResolvedModule m1 = cf1.findModule("m1").get();
1220 assertTrue(m1.configuration() == cf1);
1221
1222 // Configuration cf2(cf1): m2 requires m1
1223 ModuleDescriptor descriptor2 = newBuilder("m2")
1224 .requires("m1")
1225 .build();
1226 Configuration cf2 = Configuration.resolve(
1227 ModuleUtils.finderOf(descriptor2),
1228 List.of(cf1), // parents
1229 ModuleFinder.of(),
1230 Set.of("m2"));
1231 assertEquals(List.of(cf1), cf2.parents());
1232 assertTrue(cf2.findModule("m2").isPresent());
1233 ResolvedModule m2 = cf2.findModule("m2").get();
1234 assertTrue(m2.configuration() == cf2);
1235
1236 // Configuration cf3(cf1): m3 requires m1
1237 ModuleDescriptor descriptor3 = newBuilder("m3")
1238 .requires("m1")
1239 .build();
1240 Configuration cf3 = Configuration.resolve(
1241 ModuleUtils.finderOf(descriptor3),
1242 List.of(cf1), // parents
1243 ModuleFinder.of(),
1244 Set.of("m3"));
1245 assertEquals(List.of(cf1), cf3.parents());
1246 assertTrue(cf3.findModule("m3").isPresent());
1247 ResolvedModule m3 = cf3.findModule("m3").get();
1248 assertTrue(m3.configuration() == cf3);
1249
1250 // Configuration cf4(cf2,cf3): m4 requires m1,m2,m3
1251 ModuleDescriptor descriptor4 = newBuilder("m4")
1252 .requires("m1")
1253 .requires("m2")
1254 .requires("m3")
1255 .build();
1256 Configuration cf4 = Configuration.resolve(
1257 ModuleUtils.finderOf(descriptor4),
1258 List.of(cf2, cf3), // parents
1259 ModuleFinder.of(),
1260 Set.of("m4"));
1261 assertEquals(List.of(cf2, cf3), cf4.parents());
1262 assertTrue(cf4.findModule("m4").isPresent());
1263 ResolvedModule m4 = cf4.findModule("m4").get();
1264 assertTrue(m4.configuration() == cf4);
1265
1266 // check readability
1267 assertTrue(m1.reads().isEmpty());
1268 assertEquals(Set.of(m1), m2.reads());
1269 assertEquals(Set.of(m1), m3.reads());
1270 assertEquals(Set.of(m1, m2, m3), m4.reads());
1271 }
1272
1273
1274 /**
1275 * Basic test of resolving a module that depends on modules in three parent
1276 * configurations arranged in a diamond (two direct parents).
1277 *
1278 * The test consists of four configurations:
1279 * - Configuration cf1: m1@1
1280 * - Configuration cf2: m1@2, m2@2
1281 * - Configuration cf3: m1@3, m2@3, m3@3
1282 * - Configuration cf4(cf1,cf2,cf3): m4 requires m1,m2,m3
1283 */
1284 @Test
1285 void testResolvedInMultipleParents3() {
1286 ModuleDescriptor descriptor1, descriptor2, descriptor3;
1287
1288 // Configuration cf1: m1@1
1289 descriptor1 = newBuilder("m1").version("1").build();
1290 Configuration cf1 = resolve(ModuleUtils.finderOf(descriptor1), "m1");
1291 assertEquals(List.of(Configuration.empty()), cf1.parents());
1292
1293 // Configuration cf2: m1@2, m2@2
1294 descriptor1 = newBuilder("m1").version("2").build();
1295 descriptor2 = newBuilder("m2").version("2").build();
1296 Configuration cf2 = resolve(
1297 ModuleUtils.finderOf(descriptor1, descriptor2),
1298 "m1", "m2");
1299 assertEquals(List.of(Configuration.empty()), cf2.parents());
1300
1301 // Configuration cf3: m1@3, m2@3, m3@3
1302 descriptor1 = newBuilder("m1").version("3").build();
1303 descriptor2 = newBuilder("m2").version("3").build();
1304 descriptor3 = newBuilder("m3").version("3").build();
1305 Configuration cf3 = resolve(
1306 ModuleUtils.finderOf(descriptor1, descriptor2, descriptor3),
1307 "m1", "m2", "m3");
1308 assertEquals(List.of(Configuration.empty()), cf3.parents());
1309
1310 // Configuration cf4(cf1,cf2,cf3): m4 requires m1,m2,m3
1311 ModuleDescriptor descriptor4 = newBuilder("m4")
1312 .requires("m1")
1313 .requires("m2")
1314 .requires("m3")
1315 .build();
1316 Configuration cf4 = Configuration.resolve(
1317 ModuleUtils.finderOf(descriptor4),
1318 List.of(cf1, cf2, cf3), // parents
1319 ModuleFinder.of(),
1320 Set.of("m4"));
1321 assertEquals(List.of(cf1, cf2, cf3), cf4.parents());
1322
1323 assertTrue(cf1.findModule("m1").isPresent());
1324 assertTrue(cf2.findModule("m1").isPresent());
1325 assertTrue(cf2.findModule("m2").isPresent());
1326 assertTrue(cf3.findModule("m1").isPresent());
1327 assertTrue(cf3.findModule("m2").isPresent());
1328 assertTrue(cf3.findModule("m3").isPresent());
1329 assertTrue(cf4.findModule("m4").isPresent());
1330
1331 ResolvedModule m1_1 = cf1.findModule("m1").get();
1332 ResolvedModule m1_2 = cf2.findModule("m1").get();
1333 ResolvedModule m2_2 = cf2.findModule("m2").get();
1334 ResolvedModule m1_3 = cf3.findModule("m1").get();
1335 ResolvedModule m2_3 = cf3.findModule("m2").get();
1336 ResolvedModule m3_3 = cf3.findModule("m3").get();
1337 ResolvedModule m4 = cf4.findModule("m4").get();
1338
1339 assertTrue(m1_1.configuration() == cf1);
1340 assertTrue(m1_2.configuration() == cf2);
1341 assertTrue(m2_2.configuration() == cf2);
1342 assertTrue(m1_3.configuration() == cf3);
1343 assertTrue(m2_3.configuration() == cf3);
1344 assertTrue(m3_3.configuration() == cf3);
1345 assertTrue(m4.configuration() == cf4);
1346
1347 // check readability
1348 assertTrue(m1_1.reads().isEmpty());
1349 assertTrue(m1_2.reads().isEmpty());
1350 assertTrue(m2_2.reads().isEmpty());
1351 assertTrue(m1_3.reads().isEmpty());
1352 assertTrue(m2_3.reads().isEmpty());
1353 assertTrue(m3_3.reads().isEmpty());
1354 assertEquals(Set.of(m1_1, m2_2, m3_3), m4.reads());
1355 }
1356
1357
1358 /**
1359 * Basic test of using the beforeFinder to override a module in a parent
1360 * configuration.
1361 */
1362 @Test
1363 void testOverriding1() {
1364 ModuleDescriptor descriptor1 = newBuilder("m1").build();
1365
1366 ModuleFinder finder = ModuleUtils.finderOf(descriptor1);
1367
1368 Configuration cf1 = resolve(finder, "m1");
1369 assertTrue(cf1.modules().size() == 1);
1370 assertTrue(cf1.findModule("m1").isPresent());
1371
1372 Configuration cf2 = resolve(cf1, finder, "m1");
1373 assertTrue(cf2.modules().size() == 1);
1374 assertTrue(cf2.findModule("m1").isPresent());
1375 }
1376
1377 /**
1378 * Basic test of using the beforeFinder to override a module in a parent
1379 * configuration.
1380 */
1381 @Test
1382 void testOverriding2() {
1383 ModuleDescriptor descriptor1 = newBuilder("m1").build();
1384 Configuration cf1 = resolve(ModuleUtils.finderOf(descriptor1), "m1");
1385 assertTrue(cf1.modules().size() == 1);
1386 assertTrue(cf1.findModule("m1").isPresent());
1387
1388 ModuleDescriptor descriptor2 = newBuilder("m2").build();
1389 Configuration cf2 = resolve(ModuleUtils.finderOf(descriptor2), "m2");
1390 assertTrue(cf2.modules().size() == 1);
1391 assertTrue(cf2.findModule("m2").isPresent());
1392
1393 ModuleDescriptor descriptor3 = newBuilder("m3").build();
1394 Configuration cf3 = resolve(ModuleUtils.finderOf(descriptor3), "m3");
1395 assertTrue(cf3.modules().size() == 1);
1396 assertTrue(cf3.findModule("m3").isPresent());
1397
1398 // override m2, m1 and m3 should be found in parent configurations
1399 ModuleFinder finder = ModuleUtils.finderOf(descriptor2);
1400 Configuration cf4 = Configuration.resolve(
1401 finder,
1402 List.of(cf1, cf2, cf3),
1403 ModuleFinder.of(),
1404 Set.of("m1", "m2", "m3"));
1405 assertTrue(cf4.modules().size() == 1);
1406 assertTrue(cf4.findModule("m2").isPresent());
1407 ResolvedModule m2 = cf4.findModule("m2").get();
1408 assertTrue(m2.configuration() == cf4);
1409 }
1410
1411
1412 /**
1413 * Basic test of using the beforeFinder to override a module in the parent
1414 * configuration but where implied readability in the picture so that the
1415 * module in the parent is read.
1416 *
1417 * The test consists of two configurations:
1418 * - Configuration cf1: m1, m2 requires transitive m1
1419 * - Configuration cf2: m1, m3 requires m2
1420 */
1421 @Test
1422 void testOverriding3() {
1423 ModuleDescriptor descriptor1 = newBuilder("m1")
1424 .build();
1425
1426 ModuleDescriptor descriptor2 = newBuilder("m2")
1427 .requires(Set.of(Requires.Modifier.TRANSITIVE), "m1")
1428 .build();
1429
1430 ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1, descriptor2);
1431
1432 Configuration cf1 = resolve(finder1, "m2");
1433
1434 assertTrue(cf1.modules().size() == 2);
1435 assertTrue(cf1.findModule("m1").isPresent());
1436 assertTrue(cf1.findModule("m2").isPresent());
1437
1438 // cf2: m3 requires m2, m1
1439
1440 ModuleDescriptor descriptor3 = newBuilder("m3")
1441 .requires("m2")
1442 .build();
1443
1444 ModuleFinder finder2 = ModuleUtils.finderOf(descriptor1, descriptor3);
1445
1446 Configuration cf2 = resolve(cf1, finder2, "m1", "m3");
1447
1448 assertTrue(cf2.parents().size() == 1);
1449 assertTrue(cf2.parents().get(0) == cf1);
1450
1451 assertTrue(cf2.modules().size() == 2);
1452 assertTrue(cf2.findModule("m1").isPresent());
1453 assertTrue(cf2.findModule("m3").isPresent());
1454
1455 ResolvedModule m1_1 = cf1.findModule("m1").get();
1456 ResolvedModule m1_2 = cf2.findModule("m1").get();
1457 ResolvedModule m2 = cf1.findModule("m2").get();
1458 ResolvedModule m3 = cf2.findModule("m3").get();
1459
1460 assertTrue(m1_1.configuration() == cf1);
1461 assertTrue(m1_2.configuration() == cf2);
1462 assertTrue(m3.configuration() == cf2);
1463
1464
1465 // check that m3 reads cf1/m1 and cf2/m2
1466 assertTrue(m3.reads().size() == 2);
1467 assertTrue(m3.reads().contains(m1_1));
1468 assertTrue(m3.reads().contains(m2));
1469 }
1470
1471
1472 /**
1473 * Root module not found
1474 */
1475 @Test
1476 void testRootNotFound() {
1477 assertThrows(FindException.class, () -> resolve(ModuleFinder.of(), "m1"));
1478 }
1479
1480
1481 /**
1482 * Direct dependency not found
1483 */
1484 @Test
1485 void testDirectDependencyNotFound() {
1486 ModuleDescriptor descriptor1 = newBuilder("m1").requires("m2").build();
1487 ModuleFinder finder = ModuleUtils.finderOf(descriptor1);
1488 assertThrows(FindException.class, () -> resolve(finder, "m1"));
1489 }
1490
1491
1492 /**
1493 * Transitive dependency not found
1494 */
1495 @Test
1496 void testTransitiveDependencyNotFound() {
1497 ModuleDescriptor descriptor1 = newBuilder("m1").requires("m2").build();
1498 ModuleDescriptor descriptor2 = newBuilder("m2").requires("m3").build();
1499 ModuleFinder finder = ModuleUtils.finderOf(descriptor1, descriptor2);
1500 assertThrows(FindException.class, () -> resolve(finder, "m1"));
1501 }
1502
1503
1504 /**
1505 * Service provider dependency not found
1506 */
1507 @Test
1508 void testServiceProviderDependencyNotFound() {
1509
1510 // service provider dependency (on m3) not found
1511
1512 ModuleDescriptor descriptor1 = newBuilder("m1")
1513 .exports("p")
1514 .uses("p.S")
1515 .build();
1516
1517 ModuleDescriptor descriptor2 = newBuilder("m2")
1518 .requires("m1")
1519 .requires("m3")
1520 .provides("p.S", List.of("q.T"))
1521 .build();
1522
1523 ModuleFinder finder = ModuleUtils.finderOf(descriptor1, descriptor2);
1524
1525 // should throw ResolutionException because m3 is not found
1526 assertThrows(FindException.class, () -> resolveAndBind(finder, "m1"));
1527 }
1528
1529
1530 /**
1531 * Simple cycle.
1532 */
1533 @Test
1534 void testSimpleCycle() {
1535 ModuleDescriptor descriptor1 = newBuilder("m1").requires("m2").build();
1536 ModuleDescriptor descriptor2 = newBuilder("m2").requires("m3").build();
1537 ModuleDescriptor descriptor3 = newBuilder("m3").requires("m1").build();
1538 ModuleFinder finder = ModuleUtils.finderOf(descriptor1, descriptor2, descriptor3);
1539 assertThrows(ResolutionException.class, () -> resolve(finder, "m1"));
1540 }
1541
1542 /**
1543 * Basic test for detecting cycles involving a service provider module
1544 */
1545 @Test
1546 void testCycleInProvider() {
1547 ModuleDescriptor descriptor1 = newBuilder("m1")
1548 .exports("p")
1549 .uses("p.S")
1550 .build();
1551 ModuleDescriptor descriptor2 = newBuilder("m2")
1552 .requires("m1")
1553 .requires("m3")
1554 .provides("p.S", List.of("q.T"))
1555 .build();
1556 ModuleDescriptor descriptor3 = newBuilder("m3")
1557 .requires("m2")
1558 .build();
1559
1560 ModuleFinder finder
1561 = ModuleUtils.finderOf(descriptor1, descriptor2, descriptor3);
1562
1563 // should throw ResolutionException because of the m2 <--> m3 cycle
1564 assertThrows(ResolutionException.class, () -> resolveAndBind(finder, "m1"));
1565 }
1566
1567
1568 /**
1569 * Basic test to detect reading a module with the same name as itself
1570 *
1571 * The test consists of three configurations:
1572 * - Configuration cf1: m1, m2 requires transitive m1
1573 * - Configuration cf2: m1 requires m2
1574 */
1575 @Test
1576 void testReadModuleWithSameNameAsSelf() {
1577 ModuleDescriptor descriptor1_v1 = newBuilder("m1")
1578 .build();
1579
1580 ModuleDescriptor descriptor2 = newBuilder("m2")
1581 .requires(Set.of(Requires.Modifier.TRANSITIVE), "m1")
1582 .build();
1583
1584 ModuleDescriptor descriptor1_v2 = newBuilder("m1")
1585 .requires("m2")
1586 .build();
1587
1588 ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1_v1, descriptor2);
1589 Configuration cf1 = resolve(finder1, "m2");
1590 assertTrue(cf1.modules().size() == 2);
1591
1592 // resolve should throw ResolutionException
1593 ModuleFinder finder2 = ModuleUtils.finderOf(descriptor1_v2);
1594 assertThrows(ResolutionException.class, () -> resolve(cf1, finder2, "m1"));
1595 }
1596
1597
1598 /**
1599 * Basic test to detect reading two modules with the same name
1600 *
1601 * The test consists of three configurations:
1602 * - Configuration cf1: m1, m2 requires transitive m1
1603 * - Configuration cf2: m1, m3 requires transitive m1
1604 * - Configuration cf3(cf1,cf2): m4 requires m2, m3
1605 */
1606 @Test
1607 void testReadTwoModuleWithSameName() {
1608 ModuleDescriptor descriptor1 = newBuilder("m1")
1609 .build();
1610
1611 ModuleDescriptor descriptor2 = newBuilder("m2")
1612 .requires(Set.of(Requires.Modifier.TRANSITIVE), "m1")
1613 .build();
1614
1615 ModuleDescriptor descriptor3 = newBuilder("m3")
1616 .requires(Set.of(Requires.Modifier.TRANSITIVE), "m1")
1617 .build();
1618
1619 ModuleDescriptor descriptor4 = newBuilder("m4")
1620 .requires("m2")
1621 .requires("m3")
1622 .build();
1623
1624 ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1, descriptor2);
1625 Configuration cf1 = resolve(finder1, "m2");
1626 assertTrue(cf1.modules().size() == 2);
1627
1628 ModuleFinder finder2 = ModuleUtils.finderOf(descriptor1, descriptor3);
1629 Configuration cf2 = resolve(finder2, "m3");
1630 assertTrue(cf2.modules().size() == 2);
1631
1632 // should throw ResolutionException as m4 will read modules named "m1".
1633 ModuleFinder finder3 = ModuleUtils.finderOf(descriptor4);
1634 assertThrows(ResolutionException.class,
1635 () -> Configuration.resolve(finder3,
1636 List.of(cf1, cf2),
1637 ModuleFinder.of(),
1638 Set.of("m4")));
1639 }
1640
1641
1642 /**
1643 * Test two modules exporting package p to a module that reads both.
1644 */
1645 @Test
1646 void testPackageSuppliedByTwoOthers() {
1647 ModuleDescriptor descriptor1 = newBuilder("m1")
1648 .requires("m2")
1649 .requires("m3")
1650 .build();
1651
1652 ModuleDescriptor descriptor2 = newBuilder("m2")
1653 .exports("p")
1654 .build();
1655
1656 ModuleDescriptor descriptor3 = newBuilder("m3")
1657 .exports("p", Set.of("m1"))
1658 .build();
1659
1660 ModuleFinder finder
1661 = ModuleUtils.finderOf(descriptor1, descriptor2, descriptor3);
1662
1663 // m2 and m3 export package p to module m1
1664 assertThrows(ResolutionException.class, () -> resolve(finder, "m1"));
1665 }
1666
1667
1668 /**
1669 * Test the scenario where a module contains a package p and reads
1670 * a module that exports package p.
1671 */
1672 @Test
1673 void testPackageSuppliedBySelfAndOther() {
1674 ModuleDescriptor descriptor1 = newBuilder("m1")
1675 .requires("m2")
1676 .packages(Set.of("p"))
1677 .build();
1678
1679 ModuleDescriptor descriptor2 = newBuilder("m2")
1680 .exports("p")
1681 .build();
1682
1683 ModuleFinder finder = ModuleUtils.finderOf(descriptor1, descriptor2);
1684
1685 // m1 contains package p, module m2 exports package p to m1
1686 assertThrows(ResolutionException.class, () -> resolve(finder, "m1"));
1687 }
1688
1689
1690 /**
1691 * Test the scenario where a module contains a package p and reads
1692 * a module that also contains a package p.
1693 */
1694 @Test
1695 void testContainsPackageInSelfAndOther() {
1696 ModuleDescriptor descriptor1 = newBuilder("m1")
1697 .requires("m2")
1698 .packages(Set.of("p"))
1699 .build();
1700
1701 ModuleDescriptor descriptor2 = newBuilder("m2")
1702 .packages(Set.of("p"))
1703 .build();
1704
1705 ModuleFinder finder = ModuleUtils.finderOf(descriptor1, descriptor2);
1706
1707 Configuration cf = resolve(finder, "m1");
1708
1709 assertTrue(cf.modules().size() == 2);
1710 assertTrue(cf.findModule("m1").isPresent());
1711 assertTrue(cf.findModule("m2").isPresent());
1712
1713 // m1 reads m2, m2 reads nothing
1714 ResolvedModule m1 = cf.findModule("m1").get();
1715 ResolvedModule m2 = cf.findModule("m2").get();
1716 assertTrue(m1.reads().size() == 1);
1717 assertTrue(m1.reads().contains(m2));
1718 assertTrue(m2.reads().size() == 0);
1719 }
1720
1721
1722 /**
1723 * Test the scenario where a module that exports a package that is also
1724 * exported by a module that it reads in a parent layer.
1725 */
1726 @Test
1727 void testExportSamePackageAsBootLayer() {
1728 ModuleDescriptor descriptor = newBuilder("m1")
1729 .requires("java.base")
1730 .exports("java.lang")
1731 .build();
1732
1733 ModuleFinder finder = ModuleUtils.finderOf(descriptor);
1734
1735 Configuration bootConfiguration = ModuleLayer.boot().configuration();
1736
1737 // m1 contains package java.lang, java.base exports package java.lang to m1
1738 assertThrows(ResolutionException.class, () -> resolve(bootConfiguration, finder, "m1"));
1739 }
1740
1741
1742 /**
1743 * Test "uses p.S" where p is contained in the same module.
1744 */
1745 @Test
1746 void testContainsService1() {
1747 ModuleDescriptor descriptor1 = newBuilder("m1")
1748 .packages(Set.of("p"))
1749 .uses("p.S")
1750 .build();
1751
1752 ModuleFinder finder = ModuleUtils.finderOf(descriptor1);
1753
1754 Configuration cf = resolve(finder, "m1");
1755
1756 assertTrue(cf.modules().size() == 1);
1757 assertTrue(cf.findModule("m1").isPresent());
1758 }
1759
1760
1761 /**
1762 * Test "uses p.S" where p is contained in a different module.
1763 */
1764 @Test
1765 void testContainsService2() {
1766 ModuleDescriptor descriptor1 = newBuilder("m1")
1767 .packages(Set.of("p"))
1768 .build();
1769
1770 ModuleDescriptor descriptor2 = newBuilder("m2")
1771 .requires("m1")
1772 .uses("p.S")
1773 .build();
1774
1775 ModuleFinder finder = ModuleUtils.finderOf(descriptor1, descriptor2);
1776
1777 // m2 does not read a module that exports p
1778 assertThrows(ResolutionException.class, () -> resolve(finder, "m2"));
1779 }
1780
1781
1782 /**
1783 * Test "provides p.S" where p is contained in the same module.
1784 */
1785 @Test
1786 void testContainsService3() {
1787 ModuleDescriptor descriptor1 = newBuilder("m1")
1788 .packages(Set.of("p", "q"))
1789 .provides("p.S", List.of("q.S1"))
1790 .build();
1791
1792 ModuleFinder finder = ModuleUtils.finderOf(descriptor1);
1793
1794 Configuration cf = resolve(finder, "m1");
1795
1796 assertTrue(cf.modules().size() == 1);
1797 assertTrue(cf.findModule("m1").isPresent());
1798 }
1799
1800
1801 /**
1802 * Test "provides p.S" where p is contained in a different module.
1803 */
1804 @Test
1805 void testContainsService4() {
1806 ModuleDescriptor descriptor1 = newBuilder("m1")
1807 .packages(Set.of("p"))
1808 .build();
1809
1810 ModuleDescriptor descriptor2 = newBuilder("m2")
1811 .requires("m1")
1812 .provides("p.S", List.of("q.S1"))
1813 .build();
1814
1815 ModuleFinder finder = ModuleUtils.finderOf(descriptor1, descriptor2);
1816
1817 // m2 does not read a module that exports p
1818 assertThrows(ResolutionException.class, () -> resolve(finder, "m2"));
1819 }
1820
1821 /**
1822 * Test uses optional service.
1823 *
1824 * module m1 { requires static m2; uses p.S; }
1825 */
1826 @Test
1827 void testUsesOptionalService1() {
1828 ModuleDescriptor descriptor1 = newBuilder("m1")
1829 .requires(Set.of(Requires.Modifier.STATIC), "m2")
1830 .uses("p.S")
1831 .build();
1832 ModuleFinder finder = ModuleUtils.finderOf(descriptor1);
1833 Configuration cf = resolve(finder, "m1");
1834 assertTrue(cf.modules().size() == 1);
1835 assertTrue(cf.findModule("m1").isPresent());
1836 }
1837
1838 /**
1839 * Test uses optional service.
1840 *
1841 * module m1 { requires m2; uses p.S; }
1842 * module m2 { requires static transitive m3; }
1843 */
1844 @Test
1845 void testUsesOptionalService2() {
1846 ModuleDescriptor descriptor1 = newBuilder("m1")
1847 .requires("m2")
1848 .uses("p.S")
1849 .build();
1850 ModuleDescriptor descriptor2 = newBuilder("m2")
1851 .requires(Set.of(Requires.Modifier.STATIC, Requires.Modifier.TRANSITIVE), "m3")
1852 .build();
1853 ModuleFinder finder = ModuleUtils.finderOf(descriptor1, descriptor2);
1854 Configuration cf = resolve(finder, "m1");
1855 assertTrue(cf.modules().size() == 2);
1856 assertTrue(cf.findModule("m1").isPresent());
1857 assertTrue(cf.findModule("m2").isPresent());
1858 }
1859
1860 /**
1861 * Test uses optional service.
1862 *
1863 * module m1 { requires m2; uses p.S; }
1864 * module m2 { requires transitive m3; }
1865 * module m3 { requires static transitive m4; }
1866 */
1867 @Test
1868 void testUsesOptionalService3() {
1869 ModuleDescriptor descriptor1 = newBuilder("m1")
1870 .requires("m2")
1871 .uses("p.S")
1872 .build();
1873 ModuleDescriptor descriptor2 = newBuilder("m2")
1874 .requires(Set.of(Requires.Modifier.TRANSITIVE), "m3")
1875 .build();
1876 ModuleDescriptor descriptor3 = newBuilder("m3")
1877 .requires(Set.of(Requires.Modifier.STATIC, Requires.Modifier.TRANSITIVE), "m4")
1878 .build();
1879 ModuleFinder finder = ModuleUtils.finderOf(descriptor1, descriptor2, descriptor3);
1880 Configuration cf = resolve(finder, "m1");
1881 assertTrue(cf.modules().size() == 3);
1882 assertTrue(cf.findModule("m1").isPresent());
1883 assertTrue(cf.findModule("m2").isPresent());
1884 assertTrue(cf.findModule("m3").isPresent());
1885 }
1886
1887 /**
1888 * Test provides optional service.
1889 *
1890 * module m1 { requires static m2; provides p.S with q.P; }
1891 */
1892 @Test
1893 void testProvidesOptionalService1() {
1894 ModuleDescriptor descriptor1 = newBuilder("m1")
1895 .requires(Set.of(Requires.Modifier.STATIC), "m2")
1896 .provides("p.S", List.of("q.P"))
1897 .build();
1898 ModuleFinder finder = ModuleUtils.finderOf(descriptor1);
1899 Configuration cf = resolve(finder, "m1");
1900 assertTrue(cf.modules().size() == 1);
1901 assertTrue(cf.findModule("m1").isPresent());
1902 }
1903
1904 /**
1905 * Test provides optional service.
1906 *
1907 * module m1 { requires m2; provides p.S with q.P; }
1908 * module m2 { requires static transitive m3; }
1909 */
1910 @Test
1911 void testProvidesOptionalService2() {
1912 ModuleDescriptor descriptor1 = newBuilder("m1")
1913 .requires("m2")
1914 .provides("p.S", List.of("q.P"))
1915 .build();
1916 ModuleDescriptor descriptor2 = newBuilder("m2")
1917 .requires(Set.of(Requires.Modifier.STATIC, Requires.Modifier.TRANSITIVE), "m3")
1918 .build();
1919 ModuleFinder finder = ModuleUtils.finderOf(descriptor1, descriptor2);
1920 Configuration cf = resolve(finder, "m1");
1921 assertTrue(cf.modules().size() == 2);
1922 assertTrue(cf.findModule("m1").isPresent());
1923 assertTrue(cf.findModule("m2").isPresent());
1924 }
1925
1926 /**
1927 * Test provides optional service.
1928 *
1929 * module m1 { requires m2; provides p.S with q.P; }
1930 * module m2 { requires transitive m3; }
1931 * module m3 { requires static transitive m4; }
1932 */
1933 @Test
1934 void testProvidesOptionalService3() {
1935 ModuleDescriptor descriptor1 = newBuilder("m1")
1936 .requires("m2")
1937 .provides("p.S", List.of("q.P"))
1938 .build();
1939 ModuleDescriptor descriptor2 = newBuilder("m2")
1940 .requires(Set.of(Requires.Modifier.TRANSITIVE), "m3")
1941 .build();
1942 ModuleDescriptor descriptor3 = newBuilder("m3")
1943 .requires(Set.of(Requires.Modifier.STATIC, Requires.Modifier.TRANSITIVE), "m4")
1944 .build();
1945 ModuleFinder finder = ModuleUtils.finderOf(descriptor1, descriptor2, descriptor3);
1946 Configuration cf = resolve(finder, "m1");
1947 assertTrue(cf.modules().size() == 3);
1948 assertTrue(cf.findModule("m1").isPresent());
1949 assertTrue(cf.findModule("m2").isPresent());
1950 assertTrue(cf.findModule("m3").isPresent());
1951 }
1952
1953 /**
1954 * Test "uses p.S" where p is not exported to the module.
1955 */
1956 @Test
1957 void testServiceTypePackageNotExported1() {
1958 ModuleDescriptor descriptor1 = newBuilder("m1")
1959 .uses("p.S")
1960 .build();
1961 ModuleFinder finder = ModuleUtils.finderOf(descriptor1);
1962
1963 // m1 does not read a module that exports p to m1
1964 assertThrows(ResolutionException.class, () -> resolve(finder, "m1"));
1965 }
1966
1967 /**
1968 * Test "uses p.S" where p is not exported to the module.
1969 *
1970 * module m1 { requires m2; uses p.S; }
1971 * module m2 { contains p; }
1972 */
1973 @Test
1974 void testServiceTypePackageNotExported2() {
1975 ModuleDescriptor descriptor1 = newBuilder("m1")
1976 .requires("m2")
1977 .uses("p.S")
1978 .build();
1979 ModuleDescriptor descriptor2 = newBuilder("m2")
1980 .packages(Set.of("p"))
1981 .build();
1982 ModuleFinder finder = ModuleUtils.finderOf(descriptor1, descriptor2);
1983
1984 // m1 does not read a module that exports p to m1
1985 assertThrows(ResolutionException.class, () -> resolve(finder, "m1"));
1986 }
1987
1988
1989 /**
1990 * Test the empty configuration.
1991 */
1992 @Test
1993 void testEmptyConfiguration() {
1994 Configuration cf = Configuration.empty();
1995
1996 assertTrue(cf.parents().isEmpty());
1997
1998 assertTrue(cf.modules().isEmpty());
1999 assertFalse(cf.findModule("java.base").isPresent());
2000 }
2001
2002 /**
2003 * Test creating a configuration containing platform specific modules.
2004 */
2005 @ParameterizedTest
2006 @CsvSource({",", "linux-aarch64,", "linux-aarch64,linux-aarch64"})
2007 void testPlatformMatch(String targetPlatform1, String targetPlatform2) throws IOException {
2008 ModuleDescriptor base = ModuleDescriptor.newModule("java.base").build();
2009 Path system = writeModule(base, null);
2010
2011 ModuleDescriptor descriptor1 = ModuleDescriptor.newModule("m1")
2012 .requires("m2")
2013 .build();
2014 Path dir1 = writeModule(descriptor1, targetPlatform1);
2015
2016 ModuleDescriptor descriptor2 = ModuleDescriptor.newModule("m2").build();
2017 Path dir2 = writeModule(descriptor2, targetPlatform2);
2018
2019 ModuleFinder finder = ModuleFinder.of(system, dir1, dir2);
2020
2021 Configuration cf = resolve(finder, "m1");
2022
2023 assertTrue(cf.modules().size() == 3);
2024 assertTrue(cf.findModule("java.base").isPresent());
2025 assertTrue(cf.findModule("m1").isPresent());
2026 assertTrue(cf.findModule("m2").isPresent());
2027 }
2028
2029 /**
2030 * Test attempting to create a configuration with modules for different platforms.
2031 */
2032 @ParameterizedTest
2033 @CsvSource({"linux-x64,linux-aarch64", "linux-x64,windows-x64"})
2034 void testPlatformMisMatch(String targetPlatform1, String targetPlatform2) throws IOException {
2035 assertThrows(FindException.class,
2036 () -> testPlatformMatch(targetPlatform1, targetPlatform2));
2037 }
2038
2039 // no parents
2040
2041 @Test
2042 void testResolveRequiresWithNoParents() {
2043 ModuleFinder empty = ModuleFinder.of();
2044 assertThrows(IllegalArgumentException.class,
2045 () -> Configuration.resolve(empty, List.of(), empty, Set.of()));
2046 }
2047
2048 @Test
2049 void testResolveRequiresAndUsesWithNoParents() {
2050 ModuleFinder empty = ModuleFinder.of();
2051 assertThrows(IllegalArgumentException.class,
2052 () -> Configuration.resolveAndBind(empty, List.of(), empty, Set.of()));
2053 }
2054
2055
2056 // parents with modules for specific platforms
2057 @ParameterizedTest
2058 @CsvSource({",", "linux-aarch64,", "linux-aarch64,linux-aarch64"})
2059 void testResolveRequiresWithCompatibleParents(String targetPlatform1,
2060 String targetPlatform2) throws IOException {
2061 ModuleDescriptor base = ModuleDescriptor.newModule("java.base").build();
2062 Path system = writeModule(base, null);
2063
2064 ModuleDescriptor descriptor1 = ModuleDescriptor.newModule("m1").build();
2065 Path dir1 = writeModule(descriptor1, targetPlatform1);
2066
2067 ModuleDescriptor descriptor2 = ModuleDescriptor.newModule("m2").build();
2068 Path dir2 = writeModule(descriptor2, targetPlatform2);
2069
2070 ModuleFinder finder1 = ModuleFinder.of(system, dir1);
2071 Configuration cf1 = resolve(finder1, "m1");
2072
2073 ModuleFinder finder2 = ModuleFinder.of(system, dir2);
2074 Configuration cf2 = resolve(finder2, "m2");
2075
2076 Configuration cf3 = Configuration.resolve(ModuleFinder.of(),
2077 List.of(cf1, cf2),
2078 ModuleFinder.of(),
2079 Set.of());
2080 assertTrue(cf3.parents().size() == 2);
2081 }
2082
2083
2084 @ParameterizedTest
2085 @CsvSource({"linux-x64,linux-aarch64", "linux-x64,windows-x64"})
2086 void testResolveRequiresWithConflictingParents(String targetPlatform1,
2087 String targetPlatform2) throws IOException {
2088 assertThrows(IllegalArgumentException.class,
2089 () -> testResolveRequiresWithCompatibleParents(targetPlatform1, targetPlatform2));
2090 }
2091
2092
2093 // null handling
2094
2095 @Test
2096 void testResolveRequiresWithNull1() {
2097 assertThrows(NullPointerException.class,
2098 () -> resolve((ModuleFinder) null, ModuleFinder.of()));
2099 }
2100
2101 @Test
2102 void testResolveRequiresWithNull2() {
2103 assertThrows(NullPointerException.class,
2104 () -> resolve(ModuleFinder.of(), (ModuleFinder) null));
2105 }
2106
2107 @Test
2108 void testResolveRequiresWithNull3() {
2109 Configuration empty = Configuration.empty();
2110 assertThrows(NullPointerException.class,
2111 () -> Configuration.resolve(null, List.of(empty), ModuleFinder.of(), Set.of()));
2112 }
2113
2114 @Test
2115 void testResolveRequiresWithNull4() {
2116 ModuleFinder empty = ModuleFinder.of();
2117 assertThrows(NullPointerException.class,
2118 () -> Configuration.resolve(empty, null, empty, Set.of()));
2119 }
2120
2121 @Test
2122 void testResolveRequiresWithNull5() {
2123 Configuration cf = ModuleLayer.boot().configuration();
2124 assertThrows(NullPointerException.class,
2125 () -> Configuration.resolve(ModuleFinder.of(), List.of(cf), null, Set.of()));
2126 }
2127
2128 @Test
2129 void testResolveRequiresWithNull6() {
2130 ModuleFinder empty = ModuleFinder.of();
2131 Configuration cf = ModuleLayer.boot().configuration();
2132 assertThrows(NullPointerException.class,
2133 () -> Configuration.resolve(empty, List.of(cf), empty, null));
2134 }
2135
2136 @Test
2137 void testResolveRequiresAndUsesWithNull1() {
2138 assertThrows(NullPointerException.class,
2139 () -> resolveAndBind((ModuleFinder) null, ModuleFinder.of()));
2140 }
2141
2142 @Test
2143 void testResolveRequiresAndUsesWithNull2() {
2144 assertThrows(NullPointerException.class,
2145 () -> resolveAndBind(ModuleFinder.of(), (ModuleFinder) null));
2146 }
2147
2148 @Test
2149 void testResolveRequiresAndUsesWithNull3() {
2150 Configuration empty = Configuration.empty();
2151 assertThrows(NullPointerException.class,
2152 () -> Configuration.resolveAndBind(null, List.of(empty), ModuleFinder.of(), Set.of()));
2153 }
2154
2155 @Test
2156 void testResolveRequiresAndUsesWithNull4() {
2157 ModuleFinder empty = ModuleFinder.of();
2158 assertThrows(NullPointerException.class,
2159 () -> Configuration.resolveAndBind(empty, null, empty, Set.of()));
2160 }
2161
2162 @Test
2163 void testResolveRequiresAndUsesWithNull5() {
2164 Configuration cf = ModuleLayer.boot().configuration();
2165 assertThrows(NullPointerException.class,
2166 () -> Configuration.resolveAndBind(ModuleFinder.of(), List.of(cf), null, Set.of()));
2167 }
2168
2169 @Test
2170 void testResolveRequiresAndUsesWithNull6() {
2171 ModuleFinder empty = ModuleFinder.of();
2172 Configuration cf = ModuleLayer.boot().configuration();
2173 assertThrows(NullPointerException.class,
2174 () -> Configuration.resolveAndBind(empty, List.of(cf), empty, null));
2175 }
2176
2177 @Test
2178 void testFindModuleWithNull() {
2179 assertThrows(NullPointerException.class, () -> Configuration.empty().findModule(null));
2180 }
2181
2182 // unmodifiable collections
2183
2184 static Stream<Configuration> configurations() {
2185 return Stream.of(
2186 Configuration.empty(),
2187 ModuleLayer.boot().configuration(),
2188 resolve(ModuleFinder.of())
2189 );
2190 }
2191
2192 @ParameterizedTest
2193 @MethodSource("configurations")
2194 void testUnmodifiableParents(Configuration cf) {
2195 assertThrows(UnsupportedOperationException.class,
2196 () -> cf.parents().add(Configuration.empty()));
2197 assertThrows(UnsupportedOperationException.class,
2198 () -> cf.parents().remove(Configuration.empty()));
2199 }
2200
2201 @ParameterizedTest
2202 @MethodSource("configurations")
2203 void testUnmodifiableModules(Configuration cf) {
2204 ResolvedModule module = ModuleLayer.boot()
2205 .configuration()
2206 .findModule("java.base")
2207 .orElseThrow();
2208 assertThrows(UnsupportedOperationException.class,
2209 () -> cf.modules().add(module));
2210 assertThrows(UnsupportedOperationException.class,
2211 () -> cf.modules().remove(module));
2212 }
2213
2214 /**
2215 * Invokes parent.resolve(...)
2216 */
2217 private static Configuration resolve(Configuration parent,
2218 ModuleFinder before,
2219 ModuleFinder after,
2220 String... roots) {
2221 return parent.resolve(before, after, Set.of(roots));
2222 }
2223
2224 private static Configuration resolve(Configuration parent,
2225 ModuleFinder before,
2226 String... roots) {
2227 return resolve(parent, before, ModuleFinder.of(), roots);
2228 }
2229
2230 private static Configuration resolve(ModuleFinder before,
2231 ModuleFinder after,
2232 String... roots) {
2233 return resolve(Configuration.empty(), before, after, roots);
2234 }
2235
2236 private static Configuration resolve(ModuleFinder before,
2237 String... roots) {
2238 return resolve(Configuration.empty(), before, roots);
2239 }
2240
2241
2242 /**
2243 * Invokes parent.resolveAndBind(...)
2244 */
2245 private static Configuration resolveAndBind(Configuration parent,
2246 ModuleFinder before,
2247 ModuleFinder after,
2248 String... roots) {
2249 return parent.resolveAndBind(before, after, Set.of(roots));
2250 }
2251
2252 private static Configuration resolveAndBind(Configuration parent,
2253 ModuleFinder before,
2254 String... roots) {
2255 return resolveAndBind(parent, before, ModuleFinder.of(), roots);
2256 }
2257
2258 private static Configuration resolveAndBind(ModuleFinder before,
2259 ModuleFinder after,
2260 String... roots) {
2261 return resolveAndBind(Configuration.empty(), before, after, roots);
2262 }
2263
2264 private static Configuration resolveAndBind(ModuleFinder before,
2265 String... roots) {
2266 return resolveAndBind(Configuration.empty(), before, roots);
2267 }
2268
2269
2270 /**
2271 * Writes a module-info.class. If {@code targetPlatform} is not null then
2272 * it includes the ModuleTarget class file attribute with the target platform.
2273 */
2274 private static Path writeModule(ModuleDescriptor descriptor, String targetPlatform)
2275 throws IOException
2276 {
2277 ModuleTarget target;
2278 if (targetPlatform != null) {
2279 target = new ModuleTarget(targetPlatform);
2280 } else {
2281 target = null;
2282 }
2283 String name = descriptor.name();
2284 Path dir = Files.createTempDirectory(Paths.get(""), name);
2285 Path mi = dir.resolve("module-info.class");
2286 try (OutputStream out = Files.newOutputStream(mi)) {
2287 ModuleInfoWriter.write(descriptor, target, out);
2288 }
2289 return dir;
2290 }
2291 }