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