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