Add support for running tests with a "none" runtime configuration.

Change-Id: Ief4a210aa788a928f6b699f2895d2d3615d4be65
diff --git a/build.gradle b/build.gradle
index f492319..5c5efd3 100644
--- a/build.gradle
+++ b/build.gradle
@@ -1555,16 +1555,14 @@
         testLogging.showStandardStreams = true
     }
     if (project.hasProperty('dex_vm') && project.property('dex_vm') != 'default') {
-        println "Running with non default vm: " + project.property('dex_vm')
+        println "NOTE: Running with non default vm: " + project.property('dex_vm')
         systemProperty 'dex_vm', project.property('dex_vm')
     }
 
-    // Forward vm configurations for test parameters.
-    if (project.hasProperty('dex_vms')) {
-        systemProperty 'dex_vms', project.property('dex_vms')
-    }
-    if (project.hasProperty('cf_vms')) {
-        systemProperty 'cf_vms', project.property('cf_vms')
+    // Forward runtime configurations for test parameters.
+    if (project.hasProperty('runtimes')) {
+        println "NOTE: Running with runtimes: " + project.property('runtimes')
+        systemProperty 'runtimes', project.property('runtimes')
     }
 
     if (project.hasProperty('one_line_per_test')) {
diff --git a/src/test/java/com/android/tools/r8/TestParametersBuilder.java b/src/test/java/com/android/tools/r8/TestParametersBuilder.java
index 4cefe0c..12735cf 100644
--- a/src/test/java/com/android/tools/r8/TestParametersBuilder.java
+++ b/src/test/java/com/android/tools/r8/TestParametersBuilder.java
@@ -6,27 +6,24 @@
 import com.android.tools.r8.TestRuntime.CfRuntime;
 import com.android.tools.r8.TestRuntime.CfVm;
 import com.android.tools.r8.TestRuntime.DexRuntime;
+import com.android.tools.r8.TestRuntime.NoneRuntime;
 import com.android.tools.r8.ToolHelper.DexVm;
 import com.android.tools.r8.errors.Unreachable;
-import com.google.common.collect.ImmutableList;
 import java.util.Arrays;
 import java.util.List;
 import java.util.function.Predicate;
 import java.util.stream.Collectors;
+import java.util.stream.Stream;
 
 public class TestParametersBuilder {
 
   // Static computation of VMs configured as available by the testing invocation.
-  private static final List<CfVm> availableCfVms = getAvailableCfVms();
-  private static final List<DexVm> availableDexVms = getAvailableDexVms();
+  private static final List<TestRuntime> availableRuntimes =
+      getAvailableRuntimes().collect(Collectors.toList());
 
-  // Predicate describing which available CF runtimes are applicable to the test.
-  // Built via the methods found below. Default none.
-  private Predicate<CfVm> cfRuntimePredicate = vm -> false;
-
-  // Predicate describing which available DEX runtimes are applicable to the test.
-  // Built via the methods found below. Default none.
-  private Predicate<DexVm.Version> dexRuntimePredicate = vm -> false;
+  // Predicate describing which test parameters are applicable to the test.
+  // Built via the methods found below. Default to no applicable parameters, i.e., the emtpy set.
+  private Predicate<TestParameters> filter = param -> false;
 
   private TestParametersBuilder() {}
 
@@ -34,110 +31,108 @@
     return new TestParametersBuilder();
   }
 
+  private TestParametersBuilder withFilter(Predicate<TestParameters> predicate) {
+    filter = filter.or(predicate);
+    return this;
+  }
+
+  private TestParametersBuilder withCfRuntimeFilter(Predicate<CfVm> predicate) {
+    return withFilter(p -> p.isCfRuntime() && predicate.test(p.getRuntime().asCf().getVm()));
+  }
+
+  private TestParametersBuilder withDexRuntimeFilter(Predicate<DexVm.Version> predicate) {
+    return withFilter(
+        p -> p.isDexRuntime() && predicate.test(p.getRuntime().asDex().getVm().getVersion()));
+  }
+
+  public TestParametersBuilder withNoneRuntime() {
+    return withFilter(p -> p.getRuntime() == NoneRuntime.getInstance());
+  }
+
   public TestParametersBuilder withAllRuntimes() {
     return withCfRuntimes().withDexRuntimes();
   }
 
   /** Add specific runtime if available. */
   public TestParametersBuilder withCfRuntime(CfVm runtime) {
-    cfRuntimePredicate = cfRuntimePredicate.or(vm -> vm == runtime);
-    return this;
+    return withCfRuntimeFilter(vm -> vm == runtime);
   }
 
   /** Add all available CF runtimes. */
   public TestParametersBuilder withCfRuntimes() {
-    cfRuntimePredicate = vm -> true;
-    return this;
+    return withCfRuntimeFilter(vm -> true);
   }
 
   /** Add all available CF runtimes between {@param startInclusive} and {@param endInclusive}. */
   public TestParametersBuilder withCfRuntimes(CfVm startInclusive, CfVm endInclusive) {
-    cfRuntimePredicate =
-        cfRuntimePredicate.or(
-            vm -> startInclusive.lessThanOrEqual(vm) && vm.lessThanOrEqual(endInclusive));
-    return this;
+    return withCfRuntimeFilter(
+        vm -> startInclusive.lessThanOrEqual(vm) && vm.lessThanOrEqual(endInclusive));
   }
 
   /** Add all available CF runtimes starting from and including {@param startInclusive}. */
   public TestParametersBuilder withCfRuntimesStartingFromIncluding(CfVm startInclusive) {
-    cfRuntimePredicate = cfRuntimePredicate.or(vm -> startInclusive.lessThanOrEqual(vm));
-    return this;
+    return withCfRuntimeFilter(vm -> startInclusive.lessThanOrEqual(vm));
   }
 
   /** Add all available CF runtimes starting from and excluding {@param startExcluding}. */
   public TestParametersBuilder withCfRuntimesStartingFromExcluding(CfVm startExcluding) {
-    cfRuntimePredicate = cfRuntimePredicate.or(vm -> startExcluding.lessThan(vm));
-    return this;
+    return withCfRuntimeFilter(vm -> startExcluding.lessThan(vm));
   }
 
   /** Add all available CF runtimes ending at and including {@param endInclusive}. */
   public TestParametersBuilder withCfRuntimesEndingAtIncluding(CfVm endInclusive) {
-    cfRuntimePredicate = cfRuntimePredicate.or(vm -> vm.lessThanOrEqual(endInclusive));
-    return this;
+    return withCfRuntimeFilter(vm -> vm.lessThanOrEqual(endInclusive));
   }
 
   /** Add all available CF runtimes ending at and excluding {@param endExclusive}. */
   public TestParametersBuilder withCfRuntimesEndingAtExcluding(CfVm endExclusive) {
-    cfRuntimePredicate = cfRuntimePredicate.or(vm -> vm.lessThan(endExclusive));
-    return this;
+    return withCfRuntimeFilter(vm -> vm.lessThan(endExclusive));
   }
 
   /** Add all available DEX runtimes. */
   public TestParametersBuilder withDexRuntimes() {
-    dexRuntimePredicate = vm -> true;
-    return this;
+    return withDexRuntimeFilter(vm -> true);
   }
 
   /** Add specific runtime if available. */
   public TestParametersBuilder withDexRuntime(DexVm.Version runtime) {
-    dexRuntimePredicate = dexRuntimePredicate.or(vm -> vm == runtime);
-    return this;
+    return withDexRuntimeFilter(vm -> vm == runtime);
   }
 
   /** Add all available CF runtimes between {@param startInclusive} and {@param endInclusive}. */
   public TestParametersBuilder withDexRuntimes(
       DexVm.Version startInclusive, DexVm.Version endInclusive) {
-    dexRuntimePredicate =
-        dexRuntimePredicate.or(
-            vm -> startInclusive.isOlderThanOrEqual(vm) && vm.isOlderThanOrEqual(endInclusive));
-    return this;
+    return withDexRuntimeFilter(
+        vm -> startInclusive.isOlderThanOrEqual(vm) && vm.isOlderThanOrEqual(endInclusive));
   }
 
   /** Add all available DEX runtimes starting from and including {@param startInclusive}. */
   public TestParametersBuilder withDexRuntimesStartingFromIncluding(DexVm.Version startInclusive) {
-    dexRuntimePredicate = dexRuntimePredicate.or(vm -> startInclusive.isOlderThanOrEqual(vm));
-    return this;
+    return withDexRuntimeFilter(vm -> startInclusive.isOlderThanOrEqual(vm));
   }
 
   /** Add all available DEX runtimes starting from and excluding {@param startExcluding}. */
   public TestParametersBuilder withDexRuntimesStartingFromExcluding(DexVm.Version startExcluding) {
-    dexRuntimePredicate =
-        dexRuntimePredicate.or(vm -> vm != startExcluding && startExcluding.isOlderThanOrEqual(vm));
-    return this;
+    return withDexRuntimeFilter(
+        vm -> vm != startExcluding && startExcluding.isOlderThanOrEqual(vm));
   }
 
   /** Add all available DEX runtimes ending at and including {@param endInclusive}. */
   public TestParametersBuilder withDexRuntimesEndingAtIncluding(DexVm.Version endInclusive) {
-    dexRuntimePredicate = dexRuntimePredicate.or(vm -> vm.isOlderThanOrEqual(endInclusive));
-    return this;
+    return withDexRuntimeFilter(vm -> vm.isOlderThanOrEqual(endInclusive));
   }
 
   /** Add all available DEX runtimes ending at and excluding {@param endExclusive}. */
   public TestParametersBuilder withDexRuntimesEndingAtExcluding(DexVm.Version endExclusive) {
-    dexRuntimePredicate =
-        dexRuntimePredicate.or(vm -> vm != endExclusive && vm.isOlderThanOrEqual(endExclusive));
-    return this;
+    return withDexRuntimeFilter(vm -> vm != endExclusive && vm.isOlderThanOrEqual(endExclusive));
   }
 
   public TestParametersCollection build() {
-    ImmutableList.Builder<TestParameters> parameters = ImmutableList.builder();
-    availableCfVms.stream()
-        .filter(cfRuntimePredicate)
-        .forEach(vm -> parameters.add(new TestParameters(new CfRuntime(vm))));
-    availableDexVms.stream()
-        .filter(vm -> dexRuntimePredicate.test(vm.getVersion()))
-        .forEach(vm -> parameters.add(new TestParameters(new DexRuntime(vm))));
-    return new TestParametersCollection(parameters.build());
+    return new TestParametersCollection(
+        getAvailableRuntimes()
+            .map(TestParameters::new)
+            .filter(filter)
+            .collect(Collectors.toList()));
   }
 
   // Public method to check that the CF runtime coincides with the system runtime.
@@ -158,33 +153,44 @@
     return isSystemJdk(vm);
   }
 
-  public static List<CfVm> getAvailableCfVms() {
-    String cfVmsProperty = System.getProperty("cf_vms");
-    if (cfVmsProperty != null) {
-      return Arrays.stream(cfVmsProperty.split(":"))
-          .filter(s -> !s.isEmpty())
-          .map(TestRuntime.CfVm::fromName)
-          .filter(TestParametersBuilder::isSupportedJdk)
-          .collect(Collectors.toList());
+  private static Stream<TestRuntime> getAvailableRuntimes() {
+    String runtimesProperty = System.getProperty("runtimes");
+    Stream<TestRuntime> runtimes;
+    if (runtimesProperty != null) {
+      runtimes =
+          Arrays.stream(runtimesProperty.split(":"))
+              .filter(s -> !s.isEmpty())
+              .map(
+                  name -> {
+                    TestRuntime runtime = TestRuntime.fromName(name);
+                    if (runtime != null) {
+                      return runtime;
+                    }
+                    throw new RuntimeException("Unexpected runtime property name: " + name);
+                  });
     } else {
-      // TODO(b/127785410) Support multiple VMs at the same time.
-      return Arrays.stream(TestRuntime.CfVm.values())
-          .filter(TestParametersBuilder::isSystemJdk)
-          .collect(Collectors.toList());
+      runtimes =
+          Stream.concat(
+              Stream.of(NoneRuntime.getInstance()),
+              Stream.concat(
+                  Arrays.stream(TestRuntime.CfVm.values()).map(CfRuntime::new),
+                  Arrays.stream(DexVm.Version.values()).map(DexRuntime::new)));
     }
+    // TODO(b/127785410) Support multiple VMs at the same time.
+    return runtimes.filter(runtime -> !runtime.isCf() || isSupportedJdk(runtime.asCf().getVm()));
+  }
+
+  public static List<CfVm> getAvailableCfVms() {
+    return getAvailableRuntimes()
+        .filter(TestRuntime::isCf)
+        .map(runtime -> runtime.asCf().getVm())
+        .collect(Collectors.toList());
   }
 
   public static List<DexVm> getAvailableDexVms() {
-    String dexVmsProperty = System.getProperty("dex_vms");
-    if (dexVmsProperty != null) {
-      return Arrays.stream(dexVmsProperty.split(":"))
-          .filter(s -> !s.isEmpty())
-          .map(v -> DexVm.fromShortName(v + "_host"))
-          .collect(Collectors.toList());
-    } else {
-      return Arrays.stream(DexVm.Version.values())
-          .map(v -> DexVm.fromShortName(v.toString() + "_host"))
-          .collect(Collectors.toList());
-    }
+    return getAvailableRuntimes()
+        .filter(TestRuntime::isDex)
+        .map(runtime -> runtime.asDex().getVm())
+        .collect(Collectors.toList());
   }
 }
diff --git a/src/test/java/com/android/tools/r8/TestParametersCollection.java b/src/test/java/com/android/tools/r8/TestParametersCollection.java
index 53a0714..52bc8d5 100644
--- a/src/test/java/com/android/tools/r8/TestParametersCollection.java
+++ b/src/test/java/com/android/tools/r8/TestParametersCollection.java
@@ -3,16 +3,16 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8;
 
-import com.google.common.collect.ImmutableList;
+import java.util.Collection;
 import java.util.Iterator;
 import java.util.stream.Stream;
 import org.jetbrains.annotations.NotNull;
 
 public class TestParametersCollection implements Iterable<TestParameters> {
 
-  private final ImmutableList<TestParameters> parameters;
+  private final Collection<TestParameters> parameters;
 
-  public TestParametersCollection(ImmutableList<TestParameters> parameters) {
+  public TestParametersCollection(Collection<TestParameters> parameters) {
     assert parameters != null;
     this.parameters = parameters;
   }
diff --git a/src/test/java/com/android/tools/r8/TestRuntime.java b/src/test/java/com/android/tools/r8/TestRuntime.java
index d94a100..cd0bd3f 100644
--- a/src/test/java/com/android/tools/r8/TestRuntime.java
+++ b/src/test/java/com/android/tools/r8/TestRuntime.java
@@ -11,6 +11,23 @@
 // Base class for the runtime structure in the test parameters.
 public class TestRuntime {
 
+  public static TestRuntime fromName(String name) {
+    if (NoneRuntime.NAME.equals(name)) {
+      return NoneRuntime.getInstance();
+    }
+    CfVm cfVm = CfVm.fromName(name);
+    if (cfVm != null) {
+      return new CfRuntime(cfVm);
+    }
+    if (name.startsWith("dex-")) {
+      DexVm dexVm = DexVm.fromShortName(name.substring(4) + "_host");
+      if (dexVm != null) {
+        return new DexRuntime(dexVm);
+      }
+    }
+    return null;
+  }
+
   // Enum describing the possible/supported CF runtimes.
   public enum CfVm {
     JDK8("jdk8"),
@@ -24,7 +41,7 @@
           return value;
         }
       }
-      throw new Unreachable("Unexpected CfVm name: " + v);
+      return null;
     }
 
     CfVm(String name) {
@@ -53,10 +70,31 @@
     }
   }
 
+  public static class NoneRuntime extends TestRuntime {
+
+    private static final String NAME = "none";
+    private static final NoneRuntime INSTANCE = new NoneRuntime();
+
+    private NoneRuntime() {}
+
+    public static NoneRuntime getInstance() {
+      return INSTANCE;
+    }
+
+    @Override
+    public String toString() {
+      return NAME;
+    }
+  }
+
   // Wrapper for the DEX runtimes.
   public static class DexRuntime extends TestRuntime {
     private final DexVm vm;
 
+    public DexRuntime(DexVm.Version version) {
+      this(DexVm.fromVersion(version));
+    }
+
     public DexRuntime(DexVm vm) {
       assert vm != null;
       this.vm = vm;
diff --git a/src/test/java/com/android/tools/r8/ToolHelper.java b/src/test/java/com/android/tools/r8/ToolHelper.java
index 1ab645d..3853ced 100644
--- a/src/test/java/com/android/tools/r8/ToolHelper.java
+++ b/src/test/java/com/android/tools/r8/ToolHelper.java
@@ -222,6 +222,10 @@
       return SHORT_NAME_MAP.get(shortName);
     }
 
+    public static DexVm fromVersion(Version version) {
+      return SHORT_NAME_MAP.get(version.shortName + "_" + Kind.HOST.toString());
+    }
+
     public boolean isNewerThan(DexVm other) {
       return version.isNewerThan(other.version);
     }
diff --git a/src/test/java/com/android/tools/r8/maindexlist/MainDexListTests.java b/src/test/java/com/android/tools/r8/maindexlist/MainDexListTests.java
index ef53f73..2b00c20 100644
--- a/src/test/java/com/android/tools/r8/maindexlist/MainDexListTests.java
+++ b/src/test/java/com/android/tools/r8/maindexlist/MainDexListTests.java
@@ -81,7 +81,6 @@
 import java.nio.file.Files;
 import java.nio.file.Path;
 import java.util.ArrayList;
-import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
@@ -113,9 +112,9 @@
   private static final int MANY_CLASSES_MULTI_DEX_METHODS_PER_CLASS = 10;
   private static List<String> MANY_CLASSES;
 
-  @Parameters
+  @Parameters(name = "{0}")
   public static TestParametersCollection data() {
-    return getTestParameters().withCfRuntimes().build();
+    return getTestParameters().withNoneRuntime().build();
   }
 
   public MainDexListTests(TestParameters parameters) {
diff --git a/tools/test.py b/tools/test.py
index 6f664eb..26a2fb0 100755
--- a/tools/test.py
+++ b/tools/test.py
@@ -255,27 +255,26 @@
 
   rotate_test_reports()
 
+  if options.only_jctf:
+    # Note: not setting -Pruntimes will run with all available runtimes.
+    return_code = gradle.RunGradle(gradle_args, throw_on_failure=False)
+    return 0
+
   # Now run tests on selected runtime(s).
   vms_to_test = [options.dex_vm] if options.dex_vm != "all" else ALL_ART_VMS
 
-  # The full set of VMs is configured in the first run, then set to empty below.
-  dex_vms_property = ':'.join(vms_to_test)
-
-  if options.only_jctf:
-    vms_to_test = ['default']
-
   for art_vm in vms_to_test:
     vm_suffix = "_" + options.dex_vm_kind if art_vm != "default" else ""
+    runtimes = ['dex-' + art_vm]
+    # Only append the "none" runtime and JVMs if running on the "default" DEX VM.
+    if art_vm == "default":
+      runtimes.extend(['jdk8', 'jdk9', 'none'])
     return_code = gradle.RunGradle(
         gradle_args + [
           '-Pdex_vm=%s' % art_vm + vm_suffix,
-          '-Pdex_vms=%s' % dex_vms_property
-        ] +
-        # Only run the CF VMs on the 'default' configuration.
-        ([] if art_vm == "default" else ['-Pcf_vms=']),
+          '-Pruntimes=%s' % ':'.join(runtimes),
+        ],
         throw_on_failure=False)
-    # Only run the full set of DEX VMs on the first run.
-    dex_vms_property = ""
     if options.generate_golden_files_to:
       sha1 = '%s' % utils.get_HEAD_sha1()
       with utils.ChangedWorkingDirectory(options.generate_golden_files_to):