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