1 /*
   2  * Copyright (c) 2016, 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  * @bug 8142968 8154956 8170987 8171412
  27  * @summary Test --add-modules and --limit-modules; also test the "enabled" modules.
  28  * @library /tools/lib
  29  * @modules
  30  *      jdk.compiler/com.sun.tools.javac.api
  31  *      jdk.compiler/com.sun.tools.javac.code
  32  *      jdk.compiler/com.sun.tools.javac.main
  33  *      jdk.compiler/com.sun.tools.javac.model
  34  *      jdk.compiler/com.sun.tools.javac.processing
  35  *      jdk.compiler/com.sun.tools.javac.util
  36  *      jdk.jdeps/com.sun.tools.javap
  37  * @build toolbox.ToolBox toolbox.JarTask toolbox.JavacTask toolbox.JavaTask ModuleTestBase
  38  * @run main AddLimitMods
  39  */
  40 
  41 import java.io.File;
  42 import java.nio.file.Files;
  43 import java.nio.file.Path;
  44 import java.util.AbstractMap.SimpleEntry;
  45 import java.util.ArrayList;
  46 import java.util.Arrays;
  47 import java.util.Collections;
  48 import java.util.HashSet;
  49 import java.util.LinkedHashMap;
  50 import java.util.List;
  51 import java.util.Map;
  52 import java.util.Map.Entry;
  53 import java.util.Objects;
  54 import java.util.Set;
  55 
  56 import javax.annotation.processing.AbstractProcessor;
  57 import javax.annotation.processing.RoundEnvironment;
  58 import javax.annotation.processing.SupportedAnnotationTypes;
  59 import javax.annotation.processing.SupportedOptions;
  60 import javax.lang.model.SourceVersion;
  61 import javax.lang.model.element.ModuleElement;
  62 import javax.lang.model.element.TypeElement;
  63 
  64 import com.sun.tools.javac.code.Symbol.ClassSymbol;
  65 import com.sun.tools.javac.code.Symtab;
  66 import com.sun.tools.javac.model.JavacElements;
  67 import com.sun.tools.javac.processing.JavacProcessingEnvironment;
  68 import com.sun.tools.javac.util.Context;
  69 
  70 import toolbox.JarTask;
  71 import toolbox.JavacTask;
  72 import toolbox.JavaTask;
  73 import toolbox.Task;
  74 
  75 public class AddLimitMods extends ModuleTestBase {
  76 
  77     public static void main(String... args) throws Exception {
  78         AddLimitMods t = new AddLimitMods();
  79         t.runTests();
  80     }
  81 
  82     @Test
  83     public void testManual(Path base) throws Exception {
  84         Path moduleSrc = base.resolve("module-src");
  85         Path m1 = moduleSrc.resolve("m1x");
  86 
  87         tb.writeJavaFiles(m1,
  88                           "module m1x { requires m2x; requires m3x; }");
  89 
  90         Path m2 = moduleSrc.resolve("m2x");
  91 
  92         tb.writeJavaFiles(m2,
  93                           "module m2x { requires m3x; exports m2x; }",
  94                           "package m2x; public class M2 {}");
  95 
  96         Path m3 = moduleSrc.resolve("m3x");
  97 
  98         tb.writeJavaFiles(m3,
  99                           "module m3x { exports m3x; }",
 100                           "package m3x; public class M3 {}");
 101 
 102         Path modulePath = base.resolve("module-path");
 103 
 104         Files.createDirectories(modulePath);
 105 
 106         new JavacTask(tb)
 107                 .options("--module-source-path", moduleSrc.toString())
 108                 .outdir(modulePath)
 109                 .files(findJavaFiles(m3))
 110                 .run()
 111                 .writeAll();
 112 
 113         new JavacTask(tb)
 114                 .options("--module-source-path", moduleSrc.toString())
 115                 .outdir(modulePath)
 116                 .files(findJavaFiles(m2))
 117                 .run()
 118                 .writeAll();
 119 
 120         //real test
 121         new JavacTask(tb)
 122                 .options("--module-path", modulePath.toString(),
 123                          "--should-stop:ifNoError=FLOW",
 124                          "--limit-modules", "java.base")
 125                 .outdir(modulePath)
 126                 .files(findJavaFiles(m1))
 127                 .run(Task.Expect.FAIL)
 128                 .writeAll();
 129 
 130         new JavacTask(tb)
 131                 .options("--module-path", modulePath.toString(),
 132                          "--should-stop:ifNoError=FLOW",
 133                          "--limit-modules", "java.base",
 134                          "--add-modules", "m2x")
 135                 .outdir(modulePath)
 136                 .files(findJavaFiles(m1))
 137                 .run(Task.Expect.FAIL)
 138                 .writeAll();
 139 
 140         new JavacTask(tb)
 141                 .options("--module-path", modulePath.toString(),
 142                          "--should-stop:ifNoError=FLOW",
 143                          "--limit-modules", "java.base",
 144                          "--add-modules", "m2x,m3x")
 145                 .outdir(modulePath)
 146                 .files(findJavaFiles(m1))
 147                 .run()
 148                 .writeAll();
 149 
 150         new JavacTask(tb)
 151                 .options("--module-path", modulePath.toString(),
 152                          "--should-stop:ifNoError=FLOW",
 153                          "--limit-modules", "m2x")
 154                 .outdir(modulePath)
 155                 .files(findJavaFiles(m1))
 156                 .run()
 157                 .writeAll();
 158 
 159         new JavacTask(tb)
 160                 .options("--module-path", modulePath.toString(),
 161                          "--should-stop:ifNoError=FLOW",
 162                          "--limit-modules", "m3x")
 163                 .outdir(modulePath)
 164                 .files(findJavaFiles(m1))
 165                 .run(Task.Expect.FAIL)
 166                 .writeAll();
 167 
 168         new JavacTask(tb)
 169                 .options("--module-path", modulePath.toString(),
 170                          "--should-stop:ifNoError=FLOW",
 171                          "--limit-modules", "m3x",
 172                          "--add-modules", "m2x")
 173                 .outdir(modulePath)
 174                 .files(findJavaFiles(m1))
 175                 .run()
 176                 .writeAll();
 177     }
 178 
 179     @Test
 180     public void testObservableForUnnamed(Path base) throws Exception {
 181         Path src = base.resolve("src");
 182 
 183         tb.writeJavaFiles(src,
 184                           "package test;\n" +
 185                           "@javax.annotation.Generated(\"test\")\n" +
 186                           "public class Test {\n" +
 187                           "    com.sun.tools.javac.Main m;\n" +
 188                           "    javax.xml.bind.JAXBException e;\n" +
 189                           "}\n");
 190 
 191         Path out = base.resolve("out");
 192 
 193         Files.createDirectories(out);
 194 
 195         for (Entry<String[], String> variant : variants) {
 196             System.err.println("running variant: options=" + Arrays.asList(variant.getKey()) + ", expected log: " + variant.getValue());
 197 
 198             List<String> options = new ArrayList<>();
 199             options.add("-XDrawDiagnostics");
 200             options.addAll(Arrays.asList(variant.getKey()));
 201 
 202             String log = new JavacTask(tb)
 203                     .options(options.toArray(new String[0]))
 204                     .outdir(out)
 205                     .files(findJavaFiles(src))
 206                     .run(variant.getValue() == null ? Task.Expect.SUCCESS : Task.Expect.FAIL)
 207                     .writeAll()
 208                     .getOutput(Task.OutputKind.DIRECT);
 209 
 210             log = log.replace(System.getProperty("line.separator"), "\n");
 211 
 212             if (variant.getValue() != null && !log.equals(variant.getValue())) {
 213                 throw new AssertionError();
 214             }
 215         }
 216     }
 217 
 218     private static final List<Entry<String[], String>> variants = Arrays.asList(
 219             new SimpleEntry<String[], String>(new String[] {},
 220                                               "Test.java:2:7: compiler.err.package.not.visible: javax.annotation, (compiler.misc.not.def.access.does.not.read.from.unnamed: javax.annotation, java.xml.ws.annotation)\n"
 221                                             + "Test.java:5:14: compiler.err.package.not.visible: javax.xml.bind, (compiler.misc.not.def.access.does.not.read.from.unnamed: javax.xml.bind, java.xml.bind)\n"
 222                                             + "2 errors\n"),
 223             new SimpleEntry<String[], String>(new String[] {"--add-modules", "java.xml.ws.annotation,java.xml.bind"},
 224                                               null),
 225             new SimpleEntry<String[], String>(new String[] {"--limit-modules", "java.xml.ws,jdk.compiler"},
 226                                               null),
 227             new SimpleEntry<String[], String>(new String[] {"--add-modules", "ALL-SYSTEM"},
 228                                               null)
 229     );
 230 
 231     @Test
 232     public void testAllModulePath(Path base) throws Exception {
 233         if (Files.isDirectory(base))
 234             tb.cleanDirectory(base);
 235 
 236         Path moduleSrc = base.resolve("module-src");
 237         Path m1 = moduleSrc.resolve("m1x");
 238 
 239         tb.writeJavaFiles(m1,
 240                           "module m1x { exports api; }",
 241                           "package api; public class Api { }");
 242 
 243         Path modulePath = base.resolve("module-path");
 244 
 245         Files.createDirectories(modulePath);
 246 
 247         new JavacTask(tb)
 248                 .options("--module-source-path", moduleSrc.toString())
 249                 .outdir(modulePath)
 250                 .files(findJavaFiles(moduleSrc))
 251                 .run()
 252                 .writeAll();
 253 
 254         Path cpSrc = base.resolve("cp-src");
 255         tb.writeJavaFiles(cpSrc, "package test; public class Test { api.Api api; }");
 256 
 257         Path cpOut = base.resolve("cp-out");
 258 
 259         Files.createDirectories(cpOut);
 260 
 261         new JavacTask(tb)
 262                 .options("--module-path", modulePath.toString())
 263                 .outdir(cpOut)
 264                 .files(findJavaFiles(cpSrc))
 265                 .run(Task.Expect.FAIL)
 266                 .writeAll();
 267 
 268         new JavacTask(tb)
 269                 .options("--module-path", modulePath.toString(),
 270                          "--add-modules", "ALL-MODULE-PATH")
 271                 .outdir(cpOut)
 272                 .files(findJavaFiles(cpSrc))
 273                 .run()
 274                 .writeAll();
 275 
 276         List<String> actual;
 277         List<String> expected = Arrays.asList(
 278                 "- compiler.err.addmods.all.module.path.invalid",
 279                 "1 error");
 280 
 281         actual = new JavacTask(tb)
 282                    .options("--module-source-path", moduleSrc.toString(),
 283                             "-XDrawDiagnostics",
 284                             "--add-modules", "ALL-MODULE-PATH")
 285                    .outdir(modulePath)
 286                    .files(findJavaFiles(moduleSrc))
 287                    .run(Task.Expect.FAIL)
 288                    .writeAll()
 289                    .getOutputLines(Task.OutputKind.DIRECT);
 290 
 291         if (!Objects.equals(actual, expected)) {
 292             throw new IllegalStateException("incorrect errors; actual=" + actual + "; expected=" + expected);
 293         }
 294 
 295         actual = new JavacTask(tb)
 296                    .options("--patch-module", "java.base=" + cpSrc.toString(),
 297                             "-XDrawDiagnostics",
 298                             "--add-modules", "ALL-MODULE-PATH")
 299                    .outdir(cpOut)
 300                    .files(findJavaFiles(cpSrc))
 301                    .run(Task.Expect.FAIL)
 302                    .writeAll()
 303                    .getOutputLines(Task.OutputKind.DIRECT);
 304 
 305         if (!Objects.equals(actual, expected)) {
 306             throw new IllegalStateException("incorrect errors; actual=" + actual + "; expected=" + expected);
 307         }
 308 
 309         actual = new JavacTask(tb, Task.Mode.CMDLINE)
 310                    .options("-source", "8", "-target", "8",
 311                             "-XDrawDiagnostics",
 312                             "--add-modules", "ALL-MODULE-PATH")
 313                    .outdir(cpOut)
 314                    .files(findJavaFiles(cpSrc))
 315                    .run(Task.Expect.FAIL)
 316                    .writeAll()
 317                    .getOutputLines(Task.OutputKind.DIRECT);
 318 
 319         if (!actual.contains("javac: option --add-modules not allowed with target 1.8")) {
 320             throw new IllegalStateException("incorrect errors; actual=" + actual);
 321         }
 322 
 323         tb.writeJavaFiles(cpSrc, "module m1x {}");
 324 
 325         actual = new JavacTask(tb)
 326                    .options("-XDrawDiagnostics",
 327                             "--add-modules", "ALL-MODULE-PATH")
 328                    .outdir(cpOut)
 329                    .files(findJavaFiles(cpSrc))
 330                    .run(Task.Expect.FAIL)
 331                    .writeAll()
 332                    .getOutputLines(Task.OutputKind.DIRECT);
 333 
 334         if (!Objects.equals(actual, expected)) {
 335             throw new IllegalStateException("incorrect errors; actual=" + actual + "; expected=" + expected);
 336         }
 337     }
 338 
 339     @Test
 340     public void testRuntime2Compile(Path base) throws Exception {
 341         Path classpathSrc = base.resolve("classpath-src");
 342         Path classpathOut = base.resolve("classpath-out");
 343 
 344         tb.writeJavaFiles(classpathSrc,
 345                           generateCheckAccessibleClass("cp.CP"));
 346 
 347         Files.createDirectories(classpathOut);
 348 
 349         System.err.println("Compiling classpath-src files:");
 350         new JavacTask(tb)
 351                 .outdir(classpathOut)
 352                 .files(findJavaFiles(classpathSrc))
 353                 .run()
 354                 .writeAll()
 355                 .getOutput(Task.OutputKind.DIRECT);
 356 
 357         Path automaticSrc = base.resolve("automatic-src");
 358         Path automaticOut = base.resolve("automatic-out");
 359 
 360         tb.writeJavaFiles(automaticSrc,
 361                           generateCheckAccessibleClass("automatic.Automatic"));
 362 
 363         Files.createDirectories(automaticOut);
 364 
 365         System.err.println("Compiling automatic-src files:");
 366         new JavacTask(tb)
 367                 .outdir(automaticOut)
 368                 .files(findJavaFiles(automaticSrc))
 369                 .run()
 370                 .writeAll()
 371                 .getOutput(Task.OutputKind.DIRECT);
 372 
 373         Path modulePath = base.resolve("module-path");
 374 
 375         Files.createDirectories(modulePath);
 376 
 377         Path automaticJar = modulePath.resolve("automatic.jar");
 378 
 379         System.err.println("Creating automatic.jar:");
 380         new JarTask(tb, automaticJar)
 381           .baseDir(automaticOut)
 382           .files("automatic/Automatic.class")
 383           .run();
 384 
 385         Path moduleSrc = base.resolve("module-src");
 386         Path m1 = moduleSrc.resolve("m1x");
 387 
 388         tb.writeJavaFiles(m1,
 389                           "module m1x { exports api; }",
 390                           "package api; public class Api { public void test() { } }");
 391 
 392         System.err.println("Compiling module-src files:");
 393         new JavacTask(tb)
 394                 .options("--module-source-path", moduleSrc.toString())
 395                 .outdir(modulePath)
 396                 .files(findJavaFiles(moduleSrc))
 397                 .run()
 398                 .writeAll()
 399                 .getOutput(Task.OutputKind.DIRECT);
 400 
 401         int index = 0;
 402 
 403         for (String moduleInfo : MODULE_INFO_VARIANTS) {
 404             for (String[] options : OPTIONS_VARIANTS) {
 405                 index++;
 406 
 407                 System.err.println("Running check: " + moduleInfo + "; " + Arrays.asList(options));
 408 
 409                 Path m2Runtime = base.resolve(index + "-runtime").resolve("m2x");
 410                 Path out = base.resolve(index + "-runtime").resolve("out").resolve("m2x");
 411 
 412                 Files.createDirectories(out);
 413 
 414                 StringBuilder testClassNamed = new StringBuilder();
 415 
 416                 testClassNamed.append("package test;\n" +
 417                                       "public class Test {\n" +
 418                                       "    public static void main(String... args) throws Exception {\n");
 419 
 420                 for (Entry<String, String> e : MODULES_TO_CHECK_TO_SAMPLE_CLASS.entrySet()) {
 421                     testClassNamed.append("        System.err.println(\"visible:" + e.getKey() + ":\" + java.lang.reflect.Layer.boot().findModule(\"" + e.getKey() + "\").isPresent());\n");
 422                 }
 423 
 424                 testClassNamed.append("        Class<?> cp = Class.forName(Test.class.getClassLoader().getUnnamedModule(), \"cp.CP\");\n");
 425                 testClassNamed.append("        cp.getDeclaredMethod(\"runMe\").invoke(null);\n");
 426 
 427                 testClassNamed.append("        Class<?> automatic = Class.forName(java.lang.reflect.Layer.boot().findModule(\"automatic\").get(), \"automatic.Automatic\");\n");
 428                 testClassNamed.append("        automatic.getDeclaredMethod(\"runMe\").invoke(null);\n");
 429 
 430                 testClassNamed.append("    }\n" +
 431                                       "}");
 432 
 433                 tb.writeJavaFiles(m2Runtime, moduleInfo, testClassNamed.toString());
 434 
 435                 System.err.println("Compiling " + m2Runtime + " files:");
 436                 new JavacTask(tb)
 437                    .options("--module-path", modulePath.toString())
 438                    .outdir(out)
 439                    .files(findJavaFiles(m2Runtime))
 440                    .run()
 441                    .writeAll();
 442 
 443                 boolean success;
 444                 String output;
 445 
 446                 try {
 447                     System.err.println("Running m2x/test.Test:");
 448                     output = new JavaTask(tb)
 449                        .vmOptions(augmentOptions(options,
 450                                                  Collections.emptyList(),
 451                                                  "--module-path", modulePath.toString() + File.pathSeparator + out.getParent().toString(),
 452                                                  "--class-path", classpathOut.toString(),
 453                                                  "--add-reads", "m2x=ALL-UNNAMED,automatic",
 454                                                  "-m", "m2x/test.Test"))
 455                        .run()
 456                        .writeAll()
 457                        .getOutput(Task.OutputKind.STDERR);
 458 
 459                     success = true;
 460                 } catch (Task.TaskError err) {
 461                     success = false;
 462                     output = "";
 463                 }
 464 
 465                 Path m2 = base.resolve(String.valueOf(index)).resolve("m2x");
 466 
 467                 tb.writeJavaFiles(m2,
 468                                   moduleInfo,
 469                                   "package test;\n" +
 470                                   "public class Test {}\n");
 471 
 472                 List<String> auxOptions = success ? Arrays.asList(
 473                     "--processor-path", System.getProperty("test.class.path"),
 474                     "-processor", CheckVisibleModule.class.getName(),
 475                     "-Aoutput=" + output,
 476                     "-XDaccessInternalAPI=true"
 477                 ) : Collections.emptyList();
 478 
 479                 System.err.println("Compiling/processing m2x files:");
 480                 new JavacTask(tb)
 481                    .options(augmentOptions(options,
 482                                            auxOptions,
 483                                            "--module-path", modulePath.toString(),
 484                                            "--class-path", classpathOut.toString(),
 485                                            "--should-stop:ifNoError=FLOW"))
 486                    .outdir(modulePath)
 487                    .files(findJavaFiles(m2))
 488                    .run(success ? Task.Expect.SUCCESS : Task.Expect.FAIL)
 489                    .writeAll();
 490             }
 491         }
 492     }
 493 
 494     private String generateCheckAccessibleClass(String fqn) {
 495         String packageName = fqn.substring(0, fqn.lastIndexOf('.'));
 496         String simpleName = fqn.substring(fqn.lastIndexOf('.') + 1);
 497         StringBuilder checkClassesAccessible = new StringBuilder();
 498         checkClassesAccessible.append("package " + packageName + ";" +
 499                                       "public class " + simpleName + " {" +
 500                                       "    public static void runMe() throws Exception {");
 501         for (Entry<String, String> e : MODULES_TO_CHECK_TO_SAMPLE_CLASS.entrySet()) {
 502             checkClassesAccessible.append("try {");
 503             checkClassesAccessible.append("Class.forName(\"" + e.getValue() + "\").newInstance();");
 504             checkClassesAccessible.append("System.err.println(\"" + fqn + ":" + e.getKey() + ":true\");");
 505             checkClassesAccessible.append("} catch (Exception ex) {");
 506             checkClassesAccessible.append("System.err.println(\"" + fqn + ":" + e.getKey() + ":false\");");
 507             checkClassesAccessible.append("}");
 508         }
 509 
 510         checkClassesAccessible.append("    }\n" +
 511                                       "}");
 512 
 513         return checkClassesAccessible.toString();
 514     }
 515 
 516     private static final Map<String, String> MODULES_TO_CHECK_TO_SAMPLE_CLASS = new LinkedHashMap<>();
 517 
 518     static {
 519         MODULES_TO_CHECK_TO_SAMPLE_CLASS.put("m1x", "api.Api");
 520         MODULES_TO_CHECK_TO_SAMPLE_CLASS.put("m2x", "test.Test");
 521         MODULES_TO_CHECK_TO_SAMPLE_CLASS.put("java.base", "java.lang.Object");
 522     };
 523 
 524     @SupportedAnnotationTypes("*")
 525     @SupportedOptions("output")
 526     public static final class CheckVisibleModule extends AbstractProcessor {
 527 
 528         @Override
 529         public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
 530             String expected = processingEnv.getOptions().get("output");
 531             Set<String> expectedElements = new HashSet<>(Arrays.asList(expected.split(System.getProperty("line.separator"))));
 532             Context context = ((JavacProcessingEnvironment) processingEnv).getContext();
 533             Symtab syms = Symtab.instance(context);
 534 
 535             for (Entry<String, String> e : MODULES_TO_CHECK_TO_SAMPLE_CLASS.entrySet()) {
 536                 String module = e.getKey();
 537                 ModuleElement mod = processingEnv.getElementUtils().getModuleElement(module);
 538                 String visible = "visible:" + module + ":" + (mod != null);
 539 
 540                 if (!expectedElements.contains(visible)) {
 541                     throw new AssertionError("actual: " + visible + "; expected: " + expected);
 542                 }
 543 
 544                 JavacElements javacElements = JavacElements.instance(context);
 545                 ClassSymbol unnamedClass = javacElements.getTypeElement(syms.unnamedModule, e.getValue());
 546                 String unnamed = "cp.CP:" + module + ":" + (unnamedClass != null);
 547 
 548                 if (!expectedElements.contains(unnamed)) {
 549                     throw new AssertionError("actual: " + unnamed + "; expected: " + expected);
 550                 }
 551 
 552                 ModuleElement automaticMod = processingEnv.getElementUtils().getModuleElement("automatic");
 553                 ClassSymbol automaticClass = javacElements.getTypeElement(automaticMod, e.getValue());
 554                 String automatic = "automatic.Automatic:" + module + ":" + (automaticClass != null);
 555 
 556                 if (!expectedElements.contains(automatic)) {
 557                     throw new AssertionError("actual: " + automatic + "; expected: " + expected);
 558                 }
 559             }
 560 
 561             return false;
 562         }
 563 
 564         @Override
 565         public SourceVersion getSupportedSourceVersion() {
 566             return SourceVersion.latest();
 567         }
 568 
 569     }
 570 
 571     public String[] augmentOptions(String[] options, List<String> auxOptions, String... baseOptions) {
 572         List<String> all = new ArrayList<>();
 573 
 574         all.addAll(Arrays.asList(options));
 575         all.addAll(Arrays.asList(baseOptions));
 576         all.addAll(auxOptions);
 577 
 578         return all.toArray(new String[0]);
 579     }
 580 
 581     private static final String[] MODULE_INFO_VARIANTS = {
 582         "module m2x { exports test; }",
 583         "module m2x { requires m1x; exports test; }"
 584     };
 585 
 586     private static final String[][] OPTIONS_VARIANTS = {
 587         {"--add-modules", "automatic"},
 588         {"--add-modules", "m1x,automatic"},
 589         {"--add-modules", "jdk.compiler,automatic"},
 590         {"--add-modules", "m1x,jdk.compiler,automatic"},
 591         {"--add-modules", "ALL-SYSTEM,automatic"},
 592         {"--limit-modules", "java.base", "--add-modules", "automatic"},
 593         {"--limit-modules", "java.base", "--add-modules", "ALL-SYSTEM,automatic"},
 594         {"--limit-modules", "m2x", "--add-modules", "automatic"},
 595         {"--limit-modules", "jdk.compiler", "--add-modules", "automatic"},
 596     };
 597 }