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