Rewrite testForJvm() to testForJvm(parameters)

This adds validation that the test is not run with redundant API levels.

Bug: b/270024302
Bug: b/167145686
Change-Id: I19ea6d35278fffc0de16b02b099c71aa8fb15a9c
diff --git a/src/main/java/com/android/tools/r8/ClassFileConsumer.java b/src/main/java/com/android/tools/r8/ClassFileConsumer.java
index b5dfa03..fa3e5c4 100644
--- a/src/main/java/com/android/tools/r8/ClassFileConsumer.java
+++ b/src/main/java/com/android/tools/r8/ClassFileConsumer.java
@@ -144,7 +144,10 @@
     }
 
     public static void writeResourcesForTesting(
-        Path archive, List<ProgramResource> resources, Set<DataEntryResource> dataResources)
+        Path archive,
+        List<ProgramResource> resources,
+        Set<DataDirectoryResource> dataDirectoryResources,
+        Set<DataEntryResource> dataEntryResources)
         throws IOException, ResourceException {
       OpenOption[] options =
           new OpenOption[] {StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING};
@@ -152,7 +155,8 @@
         try (ZipOutputStream out =
             new ZipOutputStream(
                 new BufferedOutputStream(Files.newOutputStream(archive, options)))) {
-          ZipUtils.writeResourcesToZip(resources, dataResources, closer, out);
+          ZipUtils.writeResourcesToZip(
+              resources, dataDirectoryResources, dataEntryResources, closer, out);
         }
       }
     }
diff --git a/src/main/java/com/android/tools/r8/DexIndexedConsumer.java b/src/main/java/com/android/tools/r8/DexIndexedConsumer.java
index b7ff9c5..39f5b2e 100644
--- a/src/main/java/com/android/tools/r8/DexIndexedConsumer.java
+++ b/src/main/java/com/android/tools/r8/DexIndexedConsumer.java
@@ -174,7 +174,10 @@
     }
 
     public static void writeResourcesForTesting(
-        Path archive, List<ProgramResource> resources, Set<DataEntryResource> dataResources)
+        Path archive,
+        List<ProgramResource> resources,
+        Set<DataDirectoryResource> dataDirectoryResources,
+        Set<DataEntryResource> dataEntryResources)
         throws IOException, ResourceException {
       OpenOption[] options =
           new OpenOption[] {StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING};
@@ -188,9 +191,14 @@
             byte[] bytes = ByteStreams.toByteArray(closer.register(resource.getByteStream()));
             ZipUtils.writeToZipStream(out, entryName, bytes, ZipEntry.STORED);
           }
-          for (DataEntryResource dataResource : dataResources) {
-            String entryName = dataResource.getName();
-            byte[] bytes = ByteStreams.toByteArray(closer.register(dataResource.getByteStream()));
+          for (DataDirectoryResource dataDirectoryResource : dataDirectoryResources) {
+            ZipUtils.writeToZipStream(
+                out, dataDirectoryResource.getName(), new byte[0], ZipEntry.STORED);
+          }
+          for (DataEntryResource dataEntryResource : dataEntryResources) {
+            String entryName = dataEntryResource.getName();
+            byte[] bytes =
+                ByteStreams.toByteArray(closer.register(dataEntryResource.getByteStream()));
             ZipUtils.writeToZipStream(out, entryName, bytes, ZipEntry.STORED);
           }
         }
diff --git a/src/main/java/com/android/tools/r8/utils/AndroidApp.java b/src/main/java/com/android/tools/r8/utils/AndroidApp.java
index e7d29da..50ea5cf 100644
--- a/src/main/java/com/android/tools/r8/utils/AndroidApp.java
+++ b/src/main/java/com/android/tools/r8/utils/AndroidApp.java
@@ -331,37 +331,6 @@
     return new Pair<>(dataDirectoryResources, dataEntryResources);
   }
 
-  @Deprecated
-  public Set<DataEntryResource> getDataEntryResourcesForTesting() throws ResourceException {
-    Set<DataEntryResource> out = new TreeSet<>(Comparator.comparing(DataResource::getName));
-    for (ProgramResourceProvider programResourceProvider : getProgramResourceProviders()) {
-      DataResourceProvider dataResourceProvider = programResourceProvider.getDataResourceProvider();
-      if (dataResourceProvider != null) {
-        dataResourceProvider.accept(
-            new Visitor() {
-
-              @Override
-              public void visit(DataDirectoryResource directory) {
-                // Ignore.
-              }
-
-              @Override
-              public void visit(DataEntryResource file) {
-                try {
-                  byte[] bytes = ByteStreams.toByteArray(file.getByteStream());
-                  DataEntryResource copy =
-                      DataEntryResource.fromBytes(bytes, file.getName(), file.getOrigin());
-                  out.add(copy);
-                } catch (IOException | ResourceException e) {
-                  throw new RuntimeException(e);
-                }
-              }
-            });
-      }
-    }
-    return out;
-  }
-
   /** Get program resource providers. */
   public List<ProgramResourceProvider> getProgramResourceProviders() {
     return programResourceProviders;
@@ -477,16 +446,26 @@
   public void writeToZipForTesting(Path archive, OutputMode outputMode) throws IOException {
     try {
       if (outputMode == OutputMode.DexIndexed) {
+        Pair<Set<DataDirectoryResource>, Set<DataEntryResource>> dataResourcesForTesting =
+            getDataResourcesForTesting();
         DexIndexedConsumer.ArchiveConsumer.writeResourcesForTesting(
-            archive, getDexProgramResourcesForTesting(), getDataEntryResourcesForTesting());
+            archive,
+            getDexProgramResourcesForTesting(),
+            dataResourcesForTesting.getFirst(),
+            dataResourcesForTesting.getSecond());
       } else if (outputMode == OutputMode.DexFilePerClassFile
           || outputMode == OutputMode.DexFilePerClass) {
         List<ProgramResource> resources = getDexProgramResourcesForTesting();
         DexFilePerClassFileConsumer.ArchiveConsumer.writeResourcesForTesting(
             archive, resources, programResourcesMainDescriptor);
       } else if (outputMode == OutputMode.ClassFile) {
+        Pair<Set<DataDirectoryResource>, Set<DataEntryResource>> dataResourcesForTesting =
+            getDataResourcesForTesting();
         ClassFileConsumer.ArchiveConsumer.writeResourcesForTesting(
-            archive, getClassProgramResourcesForTesting(), getDataEntryResourcesForTesting());
+            archive,
+            getClassProgramResourcesForTesting(),
+            dataResourcesForTesting.getFirst(),
+            dataResourcesForTesting.getSecond());
       } else {
         throw new Unreachable("Unsupported output-mode for writing: " + outputMode);
       }
diff --git a/src/main/java/com/android/tools/r8/utils/AndroidAppConsumers.java b/src/main/java/com/android/tools/r8/utils/AndroidAppConsumers.java
index 06fef54..7a77e25 100644
--- a/src/main/java/com/android/tools/r8/utils/AndroidAppConsumers.java
+++ b/src/main/java/com/android/tools/r8/utils/AndroidAppConsumers.java
@@ -133,6 +133,8 @@
               @Override
               public void accept(
                   DataDirectoryResource directory, DiagnosticsHandler diagnosticsHandler) {
+                builder.addDataResource(
+                    DataDirectoryResource.fromName(directory.getName(), directory.getOrigin()));
                 if (dataResourceConsumer != null) {
                   dataResourceConsumer.accept(directory, diagnosticsHandler);
                 }
@@ -287,6 +289,8 @@
               @Override
               public void accept(
                   DataDirectoryResource directory, DiagnosticsHandler diagnosticsHandler) {
+                builder.addDataResource(
+                    DataDirectoryResource.fromName(directory.getName(), directory.getOrigin()));
                 if (dataResourceConsumer != null) {
                   dataResourceConsumer.accept(directory, diagnosticsHandler);
                 }
diff --git a/src/main/java/com/android/tools/r8/utils/ArrayUtils.java b/src/main/java/com/android/tools/r8/utils/ArrayUtils.java
index b207857..57ef9b4 100644
--- a/src/main/java/com/android/tools/r8/utils/ArrayUtils.java
+++ b/src/main/java/com/android/tools/r8/utils/ArrayUtils.java
@@ -7,6 +7,7 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Map;
+import java.util.Optional;
 import java.util.function.Function;
 import java.util.function.IntPredicate;
 import java.util.function.Predicate;
@@ -174,4 +175,13 @@
   public static <T> T first(T[] ts) {
     return ts[0];
   }
+
+  public static <T> Optional<T>[] withOptionalNone(T[] ts) {
+    Optional<T>[] optionals = new Optional[ts.length + 1];
+    for (int i = 0; i < ts.length; i++) {
+      optionals[i] = Optional.of(ts[i]);
+    }
+    optionals[ts.length] = Optional.empty();
+    return optionals;
+  }
 }
diff --git a/src/main/java/com/android/tools/r8/utils/FileUtils.java b/src/main/java/com/android/tools/r8/utils/FileUtils.java
index b8b8286..a7caf57 100644
--- a/src/main/java/com/android/tools/r8/utils/FileUtils.java
+++ b/src/main/java/com/android/tools/r8/utils/FileUtils.java
@@ -8,6 +8,7 @@
 import java.io.File;
 import java.io.IOException;
 import java.io.OutputStream;
+import java.io.UncheckedIOException;
 import java.nio.charset.Charset;
 import java.nio.charset.StandardCharsets;
 import java.nio.file.Files;
@@ -96,6 +97,14 @@
     return new String(Files.readAllBytes(file), charset);
   }
 
+  public static byte[] uncheckedReadAllBytes(Path file) {
+    try {
+      return Files.readAllBytes(file);
+    } catch (IOException e) {
+      throw new UncheckedIOException(e);
+    }
+  }
+
   public static List<String> readAllLines(Path file) throws IOException {
     return Files.readAllLines(file);
   }
diff --git a/src/main/java/com/android/tools/r8/utils/ListUtils.java b/src/main/java/com/android/tools/r8/utils/ListUtils.java
index 430e670..55fe509 100644
--- a/src/main/java/com/android/tools/r8/utils/ListUtils.java
+++ b/src/main/java/com/android/tools/r8/utils/ListUtils.java
@@ -242,6 +242,14 @@
     return list.remove(list.size() - 1);
   }
 
+  public static <T> List<T> reverse(List<T> list) {
+    List<T> reversed = new ArrayList<>(list.size());
+    for (int i = list.size() - 1; i >= 0; i--) {
+      reversed.add(list.get(i));
+    }
+    return reversed;
+  }
+
   public static <T extends Comparable<T>> boolean verifyListIsOrdered(List<T> list) {
     for (int i = list.size() - 1; i > 0; i--) {
       if (list.get(i).compareTo(list.get(i - 1)) < 0) {
diff --git a/src/main/java/com/android/tools/r8/utils/ZipUtils.java b/src/main/java/com/android/tools/r8/utils/ZipUtils.java
index 43b1b02..39c6354 100644
--- a/src/main/java/com/android/tools/r8/utils/ZipUtils.java
+++ b/src/main/java/com/android/tools/r8/utils/ZipUtils.java
@@ -8,6 +8,7 @@
 import static com.android.tools.r8.utils.FileUtils.MODULE_INFO_CLASS;
 
 import com.android.tools.r8.ByteDataView;
+import com.android.tools.r8.DataDirectoryResource;
 import com.android.tools.r8.DataEntryResource;
 import com.android.tools.r8.ProgramResource;
 import com.android.tools.r8.ResourceException;
@@ -52,13 +53,17 @@
 
   public static void writeResourcesToZip(
       List<ProgramResource> resources,
-      Set<DataEntryResource> dataResources,
+      Set<DataDirectoryResource> dataDirectoryResources,
+      Set<DataEntryResource> dataEntryResources,
       Closer closer,
       ZipOutputStream out)
       throws IOException, ResourceException {
-    for (DataEntryResource dataResource : dataResources) {
-      String entryName = dataResource.getName();
-      byte[] bytes = ByteStreams.toByteArray(closer.register(dataResource.getByteStream()));
+    for (DataDirectoryResource dataDirectoryResource : dataDirectoryResources) {
+      writeToZipStream(out, dataDirectoryResource.getName(), new byte[0], ZipEntry.DEFLATED);
+    }
+    for (DataEntryResource dataEntryResource : dataEntryResources) {
+      String entryName = dataEntryResource.getName();
+      byte[] bytes = ByteStreams.toByteArray(closer.register(dataEntryResource.getByteStream()));
       writeToZipStream(
           out,
           entryName,
diff --git a/src/test/java/com/android/tools/r8/R8TestBuilder.java b/src/test/java/com/android/tools/r8/R8TestBuilder.java
index 25628d7..33c870e 100644
--- a/src/test/java/com/android/tools/r8/R8TestBuilder.java
+++ b/src/test/java/com/android/tools/r8/R8TestBuilder.java
@@ -37,8 +37,10 @@
 import com.android.tools.r8.utils.AndroidApp;
 import com.android.tools.r8.utils.FileUtils;
 import com.android.tools.r8.utils.InternalOptions;
+import com.android.tools.r8.utils.MapIdTemplateProvider;
 import com.android.tools.r8.utils.Pair;
 import com.android.tools.r8.utils.SemanticVersion;
+import com.android.tools.r8.utils.SourceFileTemplateProvider;
 import java.io.IOException;
 import java.lang.annotation.Annotation;
 import java.nio.file.Path;
@@ -749,6 +751,17 @@
     return self();
   }
 
+  public T setMapIdTemplate(String mapIdTemplate) {
+    builder.setMapIdProvider(MapIdTemplateProvider.create(mapIdTemplate, builder.getReporter()));
+    return self();
+  }
+
+  public T setSourceFileTemplate(String sourceFileTemplate) {
+    builder.setSourceFileProvider(
+        SourceFileTemplateProvider.create(sourceFileTemplate, builder.getReporter()));
+    return self();
+  }
+
   @Override
   public T addApplyMapping(String proguardMap) {
     applyMappingMaps.add(proguardMap);
diff --git a/src/test/java/com/android/tools/r8/TestBase.java b/src/test/java/com/android/tools/r8/TestBase.java
index acc1312..4f99c46 100644
--- a/src/test/java/com/android/tools/r8/TestBase.java
+++ b/src/test/java/com/android/tools/r8/TestBase.java
@@ -233,6 +233,7 @@
   }
 
   public JvmTestBuilder testForJvm(TestParameters parameters) {
+    parameters.assertCfRuntime();
     parameters.assertIsRepresentativeApiLevelForRuntime();
     return testForJvm(temp);
   }
diff --git a/src/test/java/com/android/tools/r8/TestCompileResult.java b/src/test/java/com/android/tools/r8/TestCompileResult.java
index d722704..05b91fd 100644
--- a/src/test/java/com/android/tools/r8/TestCompileResult.java
+++ b/src/test/java/com/android/tools/r8/TestCompileResult.java
@@ -88,6 +88,19 @@
     this.libraryDesugaringTestConfiguration = libraryDesugaringTestConfiguration;
   }
 
+  public CR addVmArguments(Collection<String> arguments) {
+    vmArguments.addAll(arguments);
+    return self();
+  }
+
+  public CR addVmArguments(String... arguments) {
+    return addVmArguments(Arrays.asList(arguments));
+  }
+
+  public CR noVerify() {
+    return addVmArguments("-noverify");
+  }
+
   public CR applyIf(boolean condition, ThrowableConsumer<CR> thenConsumer) {
     return applyIf(condition, thenConsumer, result -> {});
   }
diff --git a/src/test/java/com/android/tools/r8/TestParameters.java b/src/test/java/com/android/tools/r8/TestParameters.java
index b821207..a05309c 100644
--- a/src/test/java/com/android/tools/r8/TestParameters.java
+++ b/src/test/java/com/android/tools/r8/TestParameters.java
@@ -190,6 +190,10 @@
     return runtime.toString();
   }
 
+  public void assertCfRuntime() {
+    assertTrue(runtime.isCf());
+  }
+
   public void assertNoneRuntime() {
     assertEquals(NoneRuntime.getInstance(), runtime);
   }
@@ -208,12 +212,30 @@
     return this;
   }
 
+  public TestParameters assumeIsOrSimulateNoneRuntime() {
+    assumeTrue(isOrSimulateNoneRuntime());
+    return this;
+  }
+
+  public boolean isJvmTestParameters() {
+    if (isCfRuntime()) {
+      return apiLevel == null || representativeApiLevelForRuntime;
+    }
+    return false;
+  }
+
   public TestParameters assumeJvmTestParameters() {
     assumeCfRuntime();
     assumeTrue(apiLevel == null || representativeApiLevelForRuntime);
     return this;
   }
 
+  public TestParameters assumeProguardTestParameters() {
+    assumeCfRuntime();
+    assumeTrue(apiLevel == null || representativeApiLevelForRuntime);
+    return this;
+  }
+
   public TestParameters assumeR8TestParameters() {
     assertFalse(
         "No need to use assumeR8TestParameters() when not using api levels for CF",
diff --git a/src/test/java/com/android/tools/r8/TestParametersBuilder.java b/src/test/java/com/android/tools/r8/TestParametersBuilder.java
index c289130..315dfc4 100644
--- a/src/test/java/com/android/tools/r8/TestParametersBuilder.java
+++ b/src/test/java/com/android/tools/r8/TestParametersBuilder.java
@@ -212,6 +212,10 @@
     return withApiFilter((api, runtime) -> true);
   }
 
+  public TestParametersBuilder withMinimumApiLevel() {
+    return withApiFilter((api, runtime) -> api.equals(lowestCompilerApiLevel));
+  }
+
   public TestParametersBuilder withMaximumApiLevel() {
     return withApiFilter((api, runtime) -> api.equals(runtime.maxSupportedApiLevel()));
   }
diff --git a/src/test/java/com/android/tools/r8/accessrelaxation/NonConstructorRelaxationTest.java b/src/test/java/com/android/tools/r8/accessrelaxation/NonConstructorRelaxationTest.java
index 07fa59b..1c6d936 100644
--- a/src/test/java/com/android/tools/r8/accessrelaxation/NonConstructorRelaxationTest.java
+++ b/src/test/java/com/android/tools/r8/accessrelaxation/NonConstructorRelaxationTest.java
@@ -70,7 +70,7 @@
     Class<?> mainClass = C.class;
     if (parameters.isCfRuntime()) {
       // Only run JVM reference on CF runtimes.
-      testForJvm()
+      testForJvm(parameters)
           .addTestClasspath()
           .run(parameters.getRuntime(), mainClass)
           .assertSuccessWithOutput(expectedOutput);
@@ -156,7 +156,7 @@
     Class<?> mainClass = TestMain.class;
     if (parameters.isCfRuntime()) {
       // Only run JVM reference on CF runtimes.
-      testForJvm()
+      testForJvm(parameters)
           .addTestClasspath()
           .run(parameters.getRuntime(), mainClass)
           .assertSuccessWithOutput(expectedOutput);
diff --git a/src/test/java/com/android/tools/r8/annotations/DalvikAnnotationOptimizationTest.java b/src/test/java/com/android/tools/r8/annotations/DalvikAnnotationOptimizationTest.java
index f904840..f14c979 100644
--- a/src/test/java/com/android/tools/r8/annotations/DalvikAnnotationOptimizationTest.java
+++ b/src/test/java/com/android/tools/r8/annotations/DalvikAnnotationOptimizationTest.java
@@ -4,7 +4,6 @@
 package com.android.tools.r8.annotations;
 
 import static org.junit.Assert.assertEquals;
-import static org.junit.Assume.assumeTrue;
 import static org.objectweb.asm.Opcodes.ASM7;
 
 import com.android.tools.r8.ClassFileResourceProvider;
@@ -88,8 +87,8 @@
 
   @Test
   public void testD8() throws Exception {
-    assumeTrue(parameters.isDexRuntime());
-    testForD8(parameters.getBackend())
+    parameters.assumeDexRuntime();
+    testForD8()
         .addProgramClassFileData(
             transformer(TestClass.class).addMethodTransformer(getMethodTransformer()).transform())
         .setMinApi(parameters)
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelD8GradleSetupTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelD8GradleSetupTest.java
index c7e150d..2332313 100644
--- a/src/test/java/com/android/tools/r8/apimodel/ApiModelD8GradleSetupTest.java
+++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelD8GradleSetupTest.java
@@ -104,8 +104,8 @@
 
   @Test
   public void testReference() throws Exception {
-    assumeTrue(parameters.isCfRuntime());
-    testForJvm()
+    parameters.assumeJvmTestParameters();
+    testForJvm(parameters)
         .addProgramClasses(Main.class, ProgramClassOne.class, ProgramClassTwo.class)
         .addAndroidBuildVersion(AndroidApiLevel.B)
         .addLibraryClasses(LibraryClassOne.class, LibraryClassTwo.class, LibraryClassThree.class)
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelIndirectTargetWithDifferentApiLevelTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelIndirectTargetWithDifferentApiLevelTest.java
index 533eab1..c84fae1 100644
--- a/src/test/java/com/android/tools/r8/apimodel/ApiModelIndirectTargetWithDifferentApiLevelTest.java
+++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelIndirectTargetWithDifferentApiLevelTest.java
@@ -10,7 +10,6 @@
 import static com.android.tools.r8.apimodel.ApiModelingTestHelper.verifyThat;
 import static org.hamcrest.CoreMatchers.containsString;
 import static org.hamcrest.CoreMatchers.not;
-import static org.junit.Assume.assumeTrue;
 
 import com.android.tools.r8.CompilationMode;
 import com.android.tools.r8.SingleTestRunResult;
@@ -88,8 +87,8 @@
 
   @Test
   public void testReference() throws Exception {
-    assumeTrue(parameters.isCfRuntime() && parameters.getApiLevel().isEqualTo(AndroidApiLevel.B));
-    testForJvm()
+    parameters.assumeJvmTestParameters();
+    testForJvm(parameters)
         .addProgramClasses(Main.class, ProgramJoiner.class)
         .addAndroidBuildVersion(parameters.getApiLevel())
         .addLibraryClasses(LibraryClass.class, LibraryInterface.class)
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelIndirectTargetWithSameApiLevelTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelIndirectTargetWithSameApiLevelTest.java
index e8e8f2f..6f03205 100644
--- a/src/test/java/com/android/tools/r8/apimodel/ApiModelIndirectTargetWithSameApiLevelTest.java
+++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelIndirectTargetWithSameApiLevelTest.java
@@ -10,7 +10,6 @@
 import static com.android.tools.r8.apimodel.ApiModelingTestHelper.verifyThat;
 import static org.hamcrest.CoreMatchers.containsString;
 import static org.hamcrest.CoreMatchers.not;
-import static org.junit.Assume.assumeTrue;
 
 import com.android.tools.r8.CompilationMode;
 import com.android.tools.r8.SingleTestRunResult;
@@ -76,8 +75,8 @@
 
   @Test
   public void testReference() throws Exception {
-    assumeTrue(parameters.isCfRuntime() && parameters.getApiLevel().isEqualTo(AndroidApiLevel.B));
-    testForJvm()
+    parameters.assumeJvmTestParameters();
+    testForJvm(parameters)
         .addProgramClasses(Main.class, ProgramJoiner.class)
         .addAndroidBuildVersion(parameters.getApiLevel())
         .addLibraryClasses(LibraryClass.class, LibraryInterface.class)
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelMockClassCheckCastTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelMockClassCheckCastTest.java
index 6810dcd..0a9cc42 100644
--- a/src/test/java/com/android/tools/r8/apimodel/ApiModelMockClassCheckCastTest.java
+++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelMockClassCheckCastTest.java
@@ -9,7 +9,6 @@
 import static org.hamcrest.CoreMatchers.containsString;
 import static org.hamcrest.CoreMatchers.not;
 import static org.hamcrest.MatcherAssert.assertThat;
-import static org.junit.Assume.assumeTrue;
 
 import com.android.tools.r8.CompilationMode;
 import com.android.tools.r8.NeverInline;
@@ -55,8 +54,8 @@
 
   @Test
   public void testReference() throws Exception {
-    assumeTrue(parameters.isCfRuntime() && parameters.getApiLevel().isEqualTo(AndroidApiLevel.B));
-    testForJvm()
+    parameters.assumeJvmTestParameters();
+    testForJvm(parameters)
         .addProgramClasses(Main.class, TestClass.class)
         .run(parameters.getRuntime(), Main.class)
         .apply(this::checkOutput);
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelMockClassLoadingByClassForNameTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelMockClassLoadingByClassForNameTest.java
index f6a4d4e..dccfdbf 100644
--- a/src/test/java/com/android/tools/r8/apimodel/ApiModelMockClassLoadingByClassForNameTest.java
+++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelMockClassLoadingByClassForNameTest.java
@@ -9,7 +9,6 @@
 import static org.hamcrest.CoreMatchers.containsString;
 import static org.hamcrest.CoreMatchers.not;
 import static org.hamcrest.MatcherAssert.assertThat;
-import static org.junit.Assume.assumeTrue;
 
 import com.android.tools.r8.CompilationMode;
 import com.android.tools.r8.NeverInline;
@@ -55,8 +54,8 @@
 
   @Test
   public void testReference() throws Exception {
-    assumeTrue(parameters.isCfRuntime() && parameters.getApiLevel().isEqualTo(AndroidApiLevel.B));
-    testForJvm()
+    parameters.assumeJvmTestParameters();
+    testForJvm(parameters)
         .addProgramClasses(Main.class, TestClass.class)
         .run(parameters.getRuntime(), Main.class)
         .apply(this::checkOutput);
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelMockClassLoadingByClassReferenceTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelMockClassLoadingByClassReferenceTest.java
index 3226262..4c90ac5 100644
--- a/src/test/java/com/android/tools/r8/apimodel/ApiModelMockClassLoadingByClassReferenceTest.java
+++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelMockClassLoadingByClassReferenceTest.java
@@ -9,7 +9,6 @@
 import static org.hamcrest.CoreMatchers.containsString;
 import static org.hamcrest.CoreMatchers.not;
 import static org.hamcrest.MatcherAssert.assertThat;
-import static org.junit.Assume.assumeTrue;
 
 import com.android.tools.r8.CompilationMode;
 import com.android.tools.r8.NeverInline;
@@ -55,8 +54,8 @@
 
   @Test
   public void testReference() throws Exception {
-    assumeTrue(parameters.isCfRuntime() && parameters.getApiLevel().isEqualTo(AndroidApiLevel.B));
-    testForJvm()
+    parameters.assumeJvmTestParameters();
+    testForJvm(parameters)
         .addProgramClasses(Main.class, TestClass.class)
         .run(parameters.getRuntime(), Main.class)
         .apply(this::checkOutput);
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelNoOutlineForFullyMockedTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelNoOutlineForFullyMockedTest.java
index ce84ddc..57e692a 100644
--- a/src/test/java/com/android/tools/r8/apimodel/ApiModelNoOutlineForFullyMockedTest.java
+++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelNoOutlineForFullyMockedTest.java
@@ -11,7 +11,6 @@
 import static com.android.tools.r8.utils.codeinspector.Matchers.isAbsent;
 import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
 import static org.hamcrest.MatcherAssert.assertThat;
-import static org.junit.Assume.assumeTrue;
 
 import com.android.tools.r8.NeverInline;
 import com.android.tools.r8.NoReturnTypeStrengthening;
@@ -65,7 +64,7 @@
 
   @Test
   public void testD8() throws Exception {
-    assumeTrue(parameters.isDexRuntime());
+    parameters.assumeDexRuntime();
     String result;
     if (parameters.isDexRuntime()
         && parameters.getApiLevel().isGreaterThanOrEqualTo(libraryApiLevel)) {
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelOutlineCheckCastTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelOutlineCheckCastTest.java
index c733fa8..86630ca 100644
--- a/src/test/java/com/android/tools/r8/apimodel/ApiModelOutlineCheckCastTest.java
+++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelOutlineCheckCastTest.java
@@ -7,7 +7,6 @@
 import static com.android.tools.r8.apimodel.ApiModelingTestHelper.setMockApiLevelForClass;
 import static com.android.tools.r8.apimodel.ApiModelingTestHelper.setMockApiLevelForMethod;
 import static com.android.tools.r8.apimodel.ApiModelingTestHelper.verifyThat;
-import static org.junit.Assume.assumeTrue;
 
 import com.android.tools.r8.CompilationMode;
 import com.android.tools.r8.SingleTestRunResult;
@@ -69,8 +68,8 @@
 
   @Test
   public void testReference() throws Exception {
-    assumeTrue(parameters.isCfRuntime() && parameters.getApiLevel().isEqualTo(AndroidApiLevel.B));
-    testForJvm()
+    parameters.assumeJvmTestParameters();
+    testForJvm(parameters)
         .addProgramClasses(Main.class)
         .addAndroidBuildVersion(parameters.getApiLevel())
         .addLibraryClasses(LibraryProvider.class)
@@ -80,7 +79,7 @@
 
   @Test
   public void testD8Debug() throws Exception {
-    assumeTrue(parameters.isDexRuntime());
+    parameters.assumeDexRuntime();
     testForD8()
         .setMode(CompilationMode.DEBUG)
         .apply(this::setupTestBuilder)
@@ -96,7 +95,7 @@
 
   @Test
   public void testD8Release() throws Exception {
-    assumeTrue(parameters.isDexRuntime());
+    parameters.assumeDexRuntime();
     testForD8()
         .setMode(CompilationMode.RELEASE)
         .apply(this::setupTestBuilder)
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelOutlineConstClassTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelOutlineConstClassTest.java
index 23496d7..371531b 100644
--- a/src/test/java/com/android/tools/r8/apimodel/ApiModelOutlineConstClassTest.java
+++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelOutlineConstClassTest.java
@@ -6,7 +6,6 @@
 
 import static com.android.tools.r8.apimodel.ApiModelingTestHelper.setMockApiLevelForClass;
 import static com.android.tools.r8.apimodel.ApiModelingTestHelper.verifyThat;
-import static org.junit.Assume.assumeTrue;
 
 import com.android.tools.r8.CompilationMode;
 import com.android.tools.r8.SingleTestRunResult;
@@ -62,8 +61,8 @@
 
   @Test
   public void testReference() throws Exception {
-    assumeTrue(parameters.isCfRuntime() && parameters.getApiLevel().isEqualTo(AndroidApiLevel.B));
-    testForJvm()
+    parameters.assumeJvmTestParameters();
+    testForJvm(parameters)
         .addProgramClasses(Main.class)
         .addAndroidBuildVersion(parameters.getApiLevel())
         .run(parameters.getRuntime(), Main.class)
@@ -72,7 +71,7 @@
 
   @Test
   public void testD8Debug() throws Exception {
-    assumeTrue(parameters.isDexRuntime());
+    parameters.assumeDexRuntime();
     testForD8()
         .setMode(CompilationMode.DEBUG)
         .apply(this::setupTestBuilder)
@@ -85,7 +84,7 @@
 
   @Test
   public void testD8Release() throws Exception {
-    assumeTrue(parameters.isDexRuntime());
+    parameters.assumeDexRuntime();
     testForD8()
         .setMode(CompilationMode.RELEASE)
         .apply(this::setupTestBuilder)
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelOutlineInstanceOfTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelOutlineInstanceOfTest.java
index f1a365e..a4e7c2e 100644
--- a/src/test/java/com/android/tools/r8/apimodel/ApiModelOutlineInstanceOfTest.java
+++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelOutlineInstanceOfTest.java
@@ -7,7 +7,6 @@
 import static com.android.tools.r8.apimodel.ApiModelingTestHelper.setMockApiLevelForClass;
 import static com.android.tools.r8.apimodel.ApiModelingTestHelper.setMockApiLevelForMethod;
 import static com.android.tools.r8.apimodel.ApiModelingTestHelper.verifyThat;
-import static org.junit.Assume.assumeTrue;
 
 import com.android.tools.r8.CompilationMode;
 import com.android.tools.r8.SingleTestRunResult;
@@ -68,8 +67,8 @@
 
   @Test
   public void testReference() throws Exception {
-    assumeTrue(parameters.isCfRuntime() && parameters.getApiLevel().isEqualTo(AndroidApiLevel.B));
-    testForJvm()
+    parameters.assumeJvmTestParameters();
+    testForJvm(parameters)
         .addProgramClasses(Main.class)
         .addAndroidBuildVersion(parameters.getApiLevel())
         .addLibraryClasses(LibraryProvider.class)
@@ -79,7 +78,7 @@
 
   @Test
   public void testD8Debug() throws Exception {
-    assumeTrue(parameters.isDexRuntime());
+    parameters.assumeDexRuntime();
     testForD8()
         .setMode(CompilationMode.DEBUG)
         .apply(this::setupTestBuilder)
@@ -95,7 +94,7 @@
 
   @Test
   public void testD8Release() throws Exception {
-    assumeTrue(parameters.isDexRuntime());
+    parameters.assumeDexRuntime();
     testForD8()
         .setMode(CompilationMode.RELEASE)
         .apply(this::setupTestBuilder)
diff --git a/src/test/java/com/android/tools/r8/apimodel/ClassValueTest.java b/src/test/java/com/android/tools/r8/apimodel/ClassValueTest.java
index 04d14ba..22ae509 100644
--- a/src/test/java/com/android/tools/r8/apimodel/ClassValueTest.java
+++ b/src/test/java/com/android/tools/r8/apimodel/ClassValueTest.java
@@ -61,8 +61,8 @@
 
   @Test
   public void testD8() throws Exception {
-    assumeTrue(parameters.isDexRuntime());
-    testForD8(parameters.getBackend())
+    parameters.assumeDexRuntime();
+    testForD8()
         .addInnerClasses(getClass())
         .setMinApi(parameters)
         .compile()
diff --git a/src/test/java/com/android/tools/r8/bridgeremoval/KeepAbstractMethodShadowingTest.java b/src/test/java/com/android/tools/r8/bridgeremoval/KeepAbstractMethodShadowingTest.java
index cfdcc90..1d947e8 100644
--- a/src/test/java/com/android/tools/r8/bridgeremoval/KeepAbstractMethodShadowingTest.java
+++ b/src/test/java/com/android/tools/r8/bridgeremoval/KeepAbstractMethodShadowingTest.java
@@ -13,7 +13,6 @@
 import com.android.tools.r8.transformers.ClassFileTransformer.MethodPredicate;
 import com.android.tools.r8.utils.codeinspector.ClassSubject;
 import com.android.tools.r8.utils.codeinspector.MethodSubject;
-import org.junit.Assume;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
@@ -35,8 +34,8 @@
 
   @Test
   public void testJvm() throws Exception {
-    Assume.assumeTrue(parameters.isCfRuntime());
-    testForJvm()
+    parameters.assumeJvmTestParameters();
+    testForJvm(parameters)
         .addProgramClasses(A.class, C.class, Main.class)
         .addProgramClassFileData(getBWithAbstractFoo())
         .run(parameters.getRuntime(), Main.class)
diff --git a/src/test/java/com/android/tools/r8/bridgeremoval/RemoveVisibilityBridgeMethodsTest.java b/src/test/java/com/android/tools/r8/bridgeremoval/RemoveVisibilityBridgeMethodsTest.java
index 604c13c..2c372de 100644
--- a/src/test/java/com/android/tools/r8/bridgeremoval/RemoveVisibilityBridgeMethodsTest.java
+++ b/src/test/java/com/android/tools/r8/bridgeremoval/RemoveVisibilityBridgeMethodsTest.java
@@ -95,7 +95,7 @@
 
     // Run input program on java.
     if (parameters.isCfRuntime()) {
-      testForJvm()
+      testForJvm(parameters)
           .addProgramClassFileData(programClassFileData)
           .run(parameters.getRuntime(), mainClass.name)
           .assertSuccessWithOutputLines("Hello World");
diff --git a/src/test/java/com/android/tools/r8/cf/AlwaysNullGetItemTestRunner.java b/src/test/java/com/android/tools/r8/cf/AlwaysNullGetItemTestRunner.java
index fa17abd..a8f2ac2 100644
--- a/src/test/java/com/android/tools/r8/cf/AlwaysNullGetItemTestRunner.java
+++ b/src/test/java/com/android/tools/r8/cf/AlwaysNullGetItemTestRunner.java
@@ -4,7 +4,6 @@
 package com.android.tools.r8.cf;
 
 import static org.junit.Assert.assertEquals;
-import static org.junit.Assume.assumeTrue;
 
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
@@ -50,8 +49,8 @@
   @Test
   public void testNoCheckCast() throws Exception {
     // Test that JVM accepts javac output when method calls have been replaced by ACONST_NULL.
-    assumeTrue(parameters.isCfRuntime());
-    testForJvm()
+    parameters.assumeJvmTestParameters();
+    testForJvm(parameters)
         .addProgramClassFileData(AlwaysNullGetItemDump.dump())
         .run(parameters.getRuntime(), CLASS)
         .assertSuccessWithOutputLines(NullPointerException.class.getSimpleName());
diff --git a/src/test/java/com/android/tools/r8/cf/CfDebugLocalStackMapVerificationTest.java b/src/test/java/com/android/tools/r8/cf/CfDebugLocalStackMapVerificationTest.java
index 0f1668f..f890219 100644
--- a/src/test/java/com/android/tools/r8/cf/CfDebugLocalStackMapVerificationTest.java
+++ b/src/test/java/com/android/tools/r8/cf/CfDebugLocalStackMapVerificationTest.java
@@ -43,7 +43,7 @@
 
   @Test
   public void testReference() throws Exception {
-    testForJvm()
+    testForJvm(parameters)
         .addProgramClasses(SmallRepro.class)
         .run(parameters.getRuntime(), SmallRepro.class)
         .assertSuccessWithOutputThatMatches(containsString("FOO"));
diff --git a/src/test/java/com/android/tools/r8/cf/CompanionClassPreamblePositionTest.java b/src/test/java/com/android/tools/r8/cf/CompanionClassPreamblePositionTest.java
index d56bc2b..a281690 100644
--- a/src/test/java/com/android/tools/r8/cf/CompanionClassPreamblePositionTest.java
+++ b/src/test/java/com/android/tools/r8/cf/CompanionClassPreamblePositionTest.java
@@ -45,7 +45,7 @@
 
   @Test
   public void testZeroInInput() throws Exception {
-    testForJvm()
+    testForJvm(parameters)
         .addProgramClasses(TestClass.class, A.class)
         .addProgramClassFileData(getTransformedI(true))
         .run(parameters.getRuntime(), TestClass.class)
@@ -62,7 +62,7 @@
             .setMinApi(parameters)
             .compile()
             .writeToZip();
-    testForJvm()
+    testForJvm(parameters)
         .addProgramFiles(out)
         .run(parameters.getRuntime(), TestClass.class)
         .assertSuccessWithOutput(EXPECTED)
diff --git a/src/test/java/com/android/tools/r8/cf/DebugInfoTestRunner.java b/src/test/java/com/android/tools/r8/cf/DebugInfoTestRunner.java
index 0d62e66..6ab2aef 100644
--- a/src/test/java/com/android/tools/r8/cf/DebugInfoTestRunner.java
+++ b/src/test/java/com/android/tools/r8/cf/DebugInfoTestRunner.java
@@ -5,55 +5,64 @@
 
 import com.android.tools.r8.R8FullTestBuilder;
 import com.android.tools.r8.TestBase;
-import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
 import java.nio.file.Path;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
 import org.junit.runners.Parameterized.Parameters;
 
 @RunWith(Parameterized.class)
 public class DebugInfoTestRunner extends TestBase {
+
   private static final Class<?> CLASS = DebugInfoTest.class;
   private static final String EXPECTED = "";
 
+  @Parameter(0)
+  public TestParameters parameters;
+
   @Parameters(name = "{0}")
-  public static Backend[] data() {
-    return ToolHelper.getBackends();
+  public static TestParametersCollection data() {
+    return getTestParameters().withAllRuntimesAndApiLevels().build();
   }
 
-  private final Backend backend;
-
-  public DebugInfoTestRunner(Backend backend) {
-    this.backend = backend;
+  @Test
+  public void testJvm() throws Exception {
+    parameters.assumeJvmTestParameters();
+    testForJvm(parameters)
+        .addProgramClasses(CLASS)
+        .run(parameters.getRuntime(), CLASS)
+        .assertSuccessWithEmptyOutput();
   }
 
   @Test
   public void test() throws Exception {
-    if (backend == Backend.CF) {
-      testForJvm().addProgramClasses(CLASS).run(CLASS).assertSuccessWithOutput(EXPECTED);
-    }
-
     // Compile the input with R8 and run.
     Path out = temp.getRoot().toPath().resolve("out.zip");
     builder()
         .addProgramClasses(CLASS)
         .compile()
         .writeToZip(out)
-        .run(CLASS)
-        .assertSuccessWithOutput(EXPECTED);
+        .run(parameters.getRuntime(), CLASS)
+        .assertSuccessWithEmptyOutput();
 
-    if (backend == Backend.CF) {
+    if (parameters.isCfRuntime()) {
       // If first compilation was to CF, then compile and run it again.
-      builder().addProgramFiles(out).run(CLASS).assertSuccessWithOutput(EXPECTED);
+      builder()
+          .addProgramFiles(out)
+          .run(parameters.getRuntime(), CLASS)
+          .assertSuccessWithEmptyOutput();
     }
   }
 
   private R8FullTestBuilder builder() {
-    return testForR8(backend)
+    return testForR8(parameters.getBackend())
         .debug()
         .noTreeShaking()
         .addDontObfuscate()
-        .addOptionsModification(o -> o.invalidDebugInfoFatal = true);
+        .addOptionsModification(o -> o.invalidDebugInfoFatal = true)
+        .setMinApi(parameters);
   }
 }
diff --git a/src/test/java/com/android/tools/r8/cf/InconsistentLocalTypeOnExceptionEdgeTest.java b/src/test/java/com/android/tools/r8/cf/InconsistentLocalTypeOnExceptionEdgeTest.java
index 97c1aa5..b83c425 100644
--- a/src/test/java/com/android/tools/r8/cf/InconsistentLocalTypeOnExceptionEdgeTest.java
+++ b/src/test/java/com/android/tools/r8/cf/InconsistentLocalTypeOnExceptionEdgeTest.java
@@ -41,7 +41,7 @@
     List<byte[]> classFileData = getProgramClassFileData();
     String main = "Main";
     if (parameters.isCfRuntime()) {
-      testForJvm()
+      testForJvm(parameters)
           .addProgramClassFileData(classFileData)
           .run(parameters.getRuntime(), main)
           .assertFailureWithErrorThatThrows(VerifyError.class);
diff --git a/src/test/java/com/android/tools/r8/cf/InstructionsTest.java b/src/test/java/com/android/tools/r8/cf/InstructionsTest.java
index 986b838..f79a575 100644
--- a/src/test/java/com/android/tools/r8/cf/InstructionsTest.java
+++ b/src/test/java/com/android/tools/r8/cf/InstructionsTest.java
@@ -31,7 +31,7 @@
   @Test
   public void test() throws Exception {
     if (parameters.isCfRuntime()) {
-      testForJvm()
+      testForJvm(parameters)
           .addProgramClassFileData(dump())
           .run(parameters.getRuntime(), "Test")
           .assertSuccessWithOutputLines(EXPECTED);
diff --git a/src/test/java/com/android/tools/r8/cf/InvokeClinitTest.java b/src/test/java/com/android/tools/r8/cf/InvokeClinitTest.java
index 8d0ca9a..654e789 100644
--- a/src/test/java/com/android/tools/r8/cf/InvokeClinitTest.java
+++ b/src/test/java/com/android/tools/r8/cf/InvokeClinitTest.java
@@ -7,7 +7,6 @@
 import static org.hamcrest.CoreMatchers.anyOf;
 import static org.hamcrest.CoreMatchers.containsString;
 import static org.junit.Assert.assertThrows;
-import static org.junit.Assume.assumeTrue;
 
 import com.android.tools.r8.CompilationFailedException;
 import com.android.tools.r8.TestBase;
@@ -40,8 +39,8 @@
 
   @Test
   public void testJvm() throws Exception {
-    assumeTrue(parameters.isCfRuntime());
-    testForJvm()
+    parameters.assumeJvmTestParameters();
+    testForJvm(parameters)
         .addProgramClasses(A.class)
         .addProgramClassFileData(transformMain())
         .run(parameters.getRuntime(), Main.class)
diff --git a/src/test/java/com/android/tools/r8/cf/MethodHandleDifferentNameArgumentPropagationTest.java b/src/test/java/com/android/tools/r8/cf/MethodHandleDifferentNameArgumentPropagationTest.java
index 5106ff8..deca50b 100644
--- a/src/test/java/com/android/tools/r8/cf/MethodHandleDifferentNameArgumentPropagationTest.java
+++ b/src/test/java/com/android/tools/r8/cf/MethodHandleDifferentNameArgumentPropagationTest.java
@@ -30,7 +30,8 @@
 
   @Test
   public void testJvm() throws Exception {
-    testForJvm()
+    parameters.assumeJvmTestParameters();
+    testForJvm(parameters)
         .addInnerClasses(MethodHandleDifferentNameArgumentPropagationTest.class)
         .run(parameters.getRuntime(), Main.class)
         .assertSuccessWithOutputLines(EXPECTED);
diff --git a/src/test/java/com/android/tools/r8/cf/SillyBlockOrderTest.java b/src/test/java/com/android/tools/r8/cf/SillyBlockOrderTest.java
index 76d3b1f..dc74aef 100644
--- a/src/test/java/com/android/tools/r8/cf/SillyBlockOrderTest.java
+++ b/src/test/java/com/android/tools/r8/cf/SillyBlockOrderTest.java
@@ -35,7 +35,7 @@
   @Test
   public void test() throws Exception {
     if (parameters.isCfRuntime()) {
-      testForJvm()
+      testForJvm(parameters)
           .addProgramClasses(TestClass.class)
           .run(parameters.getRuntime(), TestClass.class)
           .assertSuccessWithOutput(EXPECTED)
diff --git a/src/test/java/com/android/tools/r8/cf/bootstrap/BootstrapCurrentEqualityTest.java b/src/test/java/com/android/tools/r8/cf/bootstrap/BootstrapCurrentEqualityTest.java
index f41ac28..fe5441b 100644
--- a/src/test/java/com/android/tools/r8/cf/bootstrap/BootstrapCurrentEqualityTest.java
+++ b/src/test/java/com/android/tools/r8/cf/bootstrap/BootstrapCurrentEqualityTest.java
@@ -200,7 +200,7 @@
   @Test
   public void test() throws Exception {
     Path program = Paths.get(ToolHelper.EXAMPLES_BUILD_DIR, "hello" + JAR_EXTENSION);
-    testForJvm()
+    testForJvm(parameters)
         .addProgramFiles(program)
         .run(parameters.getRuntime(), HELLO_NAME)
         .assertSuccessWithOutput(HELLO_EXPECTED)
@@ -216,7 +216,7 @@
             .addKeepRules(keep)
             .setMode(CompilationMode.DEBUG)
             .compile();
-    testForJvm()
+    testForJvm(parameters)
         .addProgramFiles(runR8Debug.outputJar())
         .run(parameters.getRuntime(), main)
         .assertSuccessWithOutput(expectedOutput);
@@ -227,7 +227,7 @@
             .addKeepRules(keep)
             .setMode(CompilationMode.RELEASE)
             .compile();
-    testForJvm()
+    testForJvm(parameters)
         .addProgramFiles(runR8Release.outputJar())
         .run(parameters.getRuntime(), main)
         .assertSuccessWithOutput(expectedOutput);
diff --git a/src/test/java/com/android/tools/r8/cf/bootstrap/BootstrapTest.java b/src/test/java/com/android/tools/r8/cf/bootstrap/BootstrapTest.java
index 8c70d15..0210341 100644
--- a/src/test/java/com/android/tools/r8/cf/bootstrap/BootstrapTest.java
+++ b/src/test/java/com/android/tools/r8/cf/bootstrap/BootstrapTest.java
@@ -10,7 +10,6 @@
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.TestParametersCollection;
-import com.android.tools.r8.TestRuntime.CfRuntime;
 import com.android.tools.r8.ToolHelper;
 import com.android.tools.r8.ToolHelper.ProcessResult;
 import com.android.tools.r8.utils.FileUtils;
@@ -22,6 +21,7 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
 import org.junit.runners.Parameterized.Parameters;
 
 @RunWith(Parameterized.class)
@@ -50,17 +50,12 @@
     }
   }
 
+  @Parameter(0)
+  public TestParameters parameters;
+
   @Parameters(name = "{0}")
   public static TestParametersCollection data() {
-    return getTestParameters().withNoneRuntime().build();
-  }
-
-  private static CfRuntime getHostRuntime() {
-    return CfRuntime.getSystemRuntime();
-  }
-
-  public BootstrapTest(TestParameters parameters) {
-    parameters.assertNoneRuntime();
+    return getTestParameters().withDefaultCfRuntime().build();
   }
 
   private Path getHelloInputs() {
@@ -73,9 +68,9 @@
 
   @Test
   public void reference() throws Exception {
-    testForJvm()
+    testForJvm(parameters)
         .addProgramFiles(getHelloInputs())
-        .run(getHostRuntime(), Hello.class)
+        .run(parameters.getRuntime(), Hello.class)
         .assertSuccessWithOutput(HELLO_EXPECTED);
   }
 
@@ -93,9 +88,9 @@
     // Run r8.jar on hello.jar to ensure that r8.jar is a working compiler.
     R8Result helloCompiledWithR8 =
         runExternalR8(R8_STABLE_JAR, getHelloInputs(), getHelloKeepRules(), mode);
-    testForJvm()
+    testForJvm(parameters)
         .addProgramFiles(helloCompiledWithR8.outputJar)
-        .run(getHostRuntime(), Hello.class)
+        .run(parameters.getRuntime(), Hello.class)
         .assertSuccessWithOutput(HELLO_EXPECTED);
 
     compareR8(helloCompiledWithR8, mode);
@@ -114,7 +109,7 @@
   }
 
   private Path compileR8WithR8(CompilationMode mode) throws Exception {
-    return testForR8(Backend.CF)
+    return testForR8(parameters.getBackend())
         .setMode(mode)
         .addProgramFiles(R8_STABLE_JAR)
         .addKeepRules(TestBase.keepMainProguardConfiguration(R8.class))
@@ -135,7 +130,7 @@
     FileUtils.writeTextFile(pgConfigFile, keepRules);
     ProcessResult processResult =
         ToolHelper.runJava(
-            getHostRuntime(),
+            parameters.getRuntime().asCf(),
             Collections.singletonList(r8Jar),
             R8.class.getTypeName(),
             "--lib",
diff --git a/src/test/java/com/android/tools/r8/cf/bootstrap/KotlinCompilerTreeShakingTest.java b/src/test/java/com/android/tools/r8/cf/bootstrap/KotlinCompilerTreeShakingTest.java
index d7a4cdc..1ffd2e4 100644
--- a/src/test/java/com/android/tools/r8/cf/bootstrap/KotlinCompilerTreeShakingTest.java
+++ b/src/test/java/com/android/tools/r8/cf/bootstrap/KotlinCompilerTreeShakingTest.java
@@ -65,7 +65,7 @@
             .addSourceFiles(HELLO_KT)
             .setOutputPath(temp.newFolder().toPath())
             .compile();
-    testForJvm()
+    testForJvm(parameters)
         .addRunClasspathFiles(kotlinTestParameters.getCompiler().getKotlinStdlibJar())
         .addClasspath(classPathBefore)
         .run(parameters.getRuntime(), PKG_NAME + ".HelloKt")
@@ -133,7 +133,7 @@
             .addSourceFiles(HELLO_KT)
             .setOutputPath(temp.newFolder().toPath())
             .compile();
-    testForJvm()
+    testForJvm(parameters)
         .addRunClasspathFiles(kotlinc.getKotlinStdlibJar())
         .addClasspath(classPathAfter)
         .run(parameters.getRuntime(), PKG_NAME + ".HelloKt")
diff --git a/src/test/java/com/android/tools/r8/cf/frames/DoubleAndLongIncompatibleTypesOnStackTest.java b/src/test/java/com/android/tools/r8/cf/frames/DoubleAndLongIncompatibleTypesOnStackTest.java
index 38d090c..4e51bb0 100644
--- a/src/test/java/com/android/tools/r8/cf/frames/DoubleAndLongIncompatibleTypesOnStackTest.java
+++ b/src/test/java/com/android/tools/r8/cf/frames/DoubleAndLongIncompatibleTypesOnStackTest.java
@@ -4,7 +4,6 @@
 package com.android.tools.r8.cf.frames;
 
 import static org.hamcrest.CoreMatchers.containsString;
-import static org.junit.Assume.assumeTrue;
 
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
@@ -38,8 +37,8 @@
 
   @Test
   public void testJvm() throws Exception {
-    assumeTrue(parameters.isCfRuntime());
-    testForJvm()
+    parameters.assumeJvmTestParameters();
+    testForJvm(parameters)
         .addProgramClassFileData(getTransformedMain())
         .run(parameters.getRuntime(), Main.class)
         .applyIf(
@@ -63,7 +62,7 @@
 
   @Test
   public void testD8() throws Exception {
-    assumeTrue(parameters.isDexRuntime());
+    parameters.assumeDexRuntime();
     AssertUtils.assertFailsCompilation(
         () ->
             testForD8()
diff --git a/src/test/java/com/android/tools/r8/cf/frames/OverlappingWidesOnStackTest.java b/src/test/java/com/android/tools/r8/cf/frames/OverlappingWidesOnStackTest.java
index 28c0401..8833ae2 100644
--- a/src/test/java/com/android/tools/r8/cf/frames/OverlappingWidesOnStackTest.java
+++ b/src/test/java/com/android/tools/r8/cf/frames/OverlappingWidesOnStackTest.java
@@ -4,7 +4,6 @@
 package com.android.tools.r8.cf.frames;
 
 import static org.hamcrest.CoreMatchers.containsString;
-import static org.junit.Assume.assumeTrue;
 
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
@@ -38,8 +37,8 @@
 
   @Test
   public void testJvm() throws Exception {
-    assumeTrue(parameters.isCfRuntime());
-    testForJvm()
+    parameters.assumeJvmTestParameters();
+    testForJvm(parameters)
         .addProgramClassFileData(getTransformedMain())
         .run(parameters.getRuntime(), Main.class)
         .applyIf(
@@ -63,7 +62,7 @@
 
   @Test
   public void testD8() throws Exception {
-    assumeTrue(parameters.isDexRuntime());
+    parameters.assumeDexRuntime();
     AssertUtils.assertFailsCompilation(
         () ->
             testForD8()
diff --git a/src/test/java/com/android/tools/r8/cf/frames/PrimitiveAndObjectIncompatibleTypesOnStackTest.java b/src/test/java/com/android/tools/r8/cf/frames/PrimitiveAndObjectIncompatibleTypesOnStackTest.java
index c108710..7b2797b 100644
--- a/src/test/java/com/android/tools/r8/cf/frames/PrimitiveAndObjectIncompatibleTypesOnStackTest.java
+++ b/src/test/java/com/android/tools/r8/cf/frames/PrimitiveAndObjectIncompatibleTypesOnStackTest.java
@@ -4,7 +4,6 @@
 package com.android.tools.r8.cf.frames;
 
 import static org.hamcrest.CoreMatchers.containsString;
-import static org.junit.Assume.assumeTrue;
 
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
@@ -38,8 +37,8 @@
 
   @Test
   public void testJvm() throws Exception {
-    assumeTrue(parameters.isCfRuntime());
-    testForJvm()
+    parameters.assumeJvmTestParameters();
+    testForJvm(parameters)
         .addProgramClassFileData(getTransformedMain())
         .run(parameters.getRuntime(), Main.class)
         .applyIf(
@@ -63,7 +62,7 @@
 
   @Test
   public void testD8() throws Exception {
-    assumeTrue(parameters.isDexRuntime());
+    parameters.assumeDexRuntime();
     AssertUtils.assertFailsCompilation(
         () ->
             testForD8()
diff --git a/src/test/java/com/android/tools/r8/cf/methodhandles/InvokeMethodHandleRuntimeErrorTest.java b/src/test/java/com/android/tools/r8/cf/methodhandles/InvokeMethodHandleRuntimeErrorTest.java
index cf0d616..351a79a 100644
--- a/src/test/java/com/android/tools/r8/cf/methodhandles/InvokeMethodHandleRuntimeErrorTest.java
+++ b/src/test/java/com/android/tools/r8/cf/methodhandles/InvokeMethodHandleRuntimeErrorTest.java
@@ -51,8 +51,8 @@
 
   @Test
   public void testReference() throws Throwable {
-    assumeTrue(parameters.isCfRuntime());
-    testForJvm()
+    parameters.assumeJvmTestParameters();
+    testForJvm(parameters)
         .addProgramClasses(Main.class, I.class, Super.class)
         .addProgramClassFileData(getInvokeCustomTransform())
         .run(parameters.getRuntime(), Main.class)
diff --git a/src/test/java/com/android/tools/r8/cf/methodhandles/MethodHandleTestRunner.java b/src/test/java/com/android/tools/r8/cf/methodhandles/MethodHandleTestRunner.java
index 34f58ce..b513d1b 100644
--- a/src/test/java/com/android/tools/r8/cf/methodhandles/MethodHandleTestRunner.java
+++ b/src/test/java/com/android/tools/r8/cf/methodhandles/MethodHandleTestRunner.java
@@ -62,8 +62,8 @@
 
   @Test
   public void testReference() throws Exception {
-    assumeTrue(parameters.isCfRuntime());
-    testForJvm()
+    parameters.assumeJvmTestParameters();
+    testForJvm(parameters)
         .addProgramClasses(getInputClasses())
         .addProgramClassFileData(getTransformedClasses())
         .run(parameters.getRuntime(), CLASS.getName())
@@ -72,8 +72,8 @@
 
   @Test
   public void testD8() throws Exception {
-    assumeTrue(parameters.isDexRuntime());
-    testForD8(parameters.getBackend())
+    parameters.assumeDexRuntime();
+    testForD8()
         .setMinApi(parameters)
         .addProgramClasses(getInputClasses())
         .addProgramClassFileData(getTransformedClasses())
diff --git a/src/test/java/com/android/tools/r8/cf/methodhandles/VarHandleTest.java b/src/test/java/com/android/tools/r8/cf/methodhandles/VarHandleTest.java
index 1d9ef5b..a7082e1 100644
--- a/src/test/java/com/android/tools/r8/cf/methodhandles/VarHandleTest.java
+++ b/src/test/java/com/android/tools/r8/cf/methodhandles/VarHandleTest.java
@@ -77,8 +77,8 @@
 
   @Test
   public void testReference() throws Throwable {
-    assumeTrue(parameters.isCfRuntime());
-    testForJvm()
+    parameters.assumeJvmTestParameters();
+    testForJvm(parameters)
         .addProgramFiles(getProgramInputs())
         .run(parameters.getRuntime(), MAIN.typeName())
         .assertSuccessWithOutput(EXPECTED);
diff --git a/src/test/java/com/android/tools/r8/cf/methodhandles/fields/ClassFieldMethodHandleTest.java b/src/test/java/com/android/tools/r8/cf/methodhandles/fields/ClassFieldMethodHandleTest.java
index 2d5ea93..9dc5739 100644
--- a/src/test/java/com/android/tools/r8/cf/methodhandles/fields/ClassFieldMethodHandleTest.java
+++ b/src/test/java/com/android/tools/r8/cf/methodhandles/fields/ClassFieldMethodHandleTest.java
@@ -4,7 +4,6 @@
 package com.android.tools.r8.cf.methodhandles.fields;
 
 import static org.hamcrest.CoreMatchers.containsString;
-import static org.junit.Assume.assumeTrue;
 import static org.objectweb.asm.Opcodes.ARETURN;
 import static org.objectweb.asm.Opcodes.H_GETFIELD;
 import static org.objectweb.asm.Opcodes.H_GETSTATIC;
@@ -56,8 +55,8 @@
 
   @Test
   public void testReference() throws Exception {
-    assumeTrue(parameters.isCfRuntime());
-    testForJvm()
+    parameters.assumeJvmTestParameters();
+    testForJvm(parameters)
         .addProgramClasses(C.class)
         .addProgramClassFileData(getTransformedMain())
         .run(parameters.getRuntime(), Main.class)
@@ -66,8 +65,8 @@
 
   @Test
   public void testD8() throws Exception {
-    assumeTrue(parameters.isDexRuntime());
-    testForD8(parameters.getBackend())
+    parameters.assumeDexRuntime();
+    testForD8()
         .addLibraryFiles(ToolHelper.getMostRecentAndroidJar())
         .addProgramClasses(C.class)
         .addProgramClassFileData(getTransformedMain())
diff --git a/src/test/java/com/android/tools/r8/cf/methodhandles/fields/InterfaceFieldMethodHandleTest.java b/src/test/java/com/android/tools/r8/cf/methodhandles/fields/InterfaceFieldMethodHandleTest.java
index 020f83e..6c435c0 100644
--- a/src/test/java/com/android/tools/r8/cf/methodhandles/fields/InterfaceFieldMethodHandleTest.java
+++ b/src/test/java/com/android/tools/r8/cf/methodhandles/fields/InterfaceFieldMethodHandleTest.java
@@ -5,7 +5,6 @@
 
 import static com.android.tools.r8.DiagnosticsMatcher.diagnosticType;
 import static org.hamcrest.CoreMatchers.containsString;
-import static org.junit.Assume.assumeTrue;
 import static org.objectweb.asm.Opcodes.ARETURN;
 import static org.objectweb.asm.Opcodes.H_GETSTATIC;
 import static org.objectweb.asm.Opcodes.H_PUTSTATIC;
@@ -59,8 +58,8 @@
 
   @Test
   public void testReference() throws Exception {
-    assumeTrue(parameters.isCfRuntime());
-    testForJvm()
+    parameters.assumeJvmTestParameters();
+    testForJvm(parameters)
         .addProgramClasses(I.class)
         .addProgramClassFileData(getTransformedMain())
         .run(parameters.getRuntime(), Main.class)
@@ -69,8 +68,8 @@
 
   @Test
   public void testD8() throws Exception {
-    assumeTrue(parameters.isDexRuntime());
-    testForD8(parameters.getBackend())
+    parameters.assumeDexRuntime();
+    testForD8()
         .addLibraryFiles(ToolHelper.getMostRecentAndroidJar())
         .addProgramClasses(I.class)
         .addProgramClassFileData(getTransformedMain())
diff --git a/src/test/java/com/android/tools/r8/cf/methodhandles/invokespecial/InvokeSpecialMethodHandleTest.java b/src/test/java/com/android/tools/r8/cf/methodhandles/invokespecial/InvokeSpecialMethodHandleTest.java
index 6f607ae..802ccce 100644
--- a/src/test/java/com/android/tools/r8/cf/methodhandles/invokespecial/InvokeSpecialMethodHandleTest.java
+++ b/src/test/java/com/android/tools/r8/cf/methodhandles/invokespecial/InvokeSpecialMethodHandleTest.java
@@ -5,7 +5,6 @@
 
 import static com.android.tools.r8.DiagnosticsMatcher.diagnosticType;
 import static org.hamcrest.CoreMatchers.containsString;
-import static org.junit.Assume.assumeTrue;
 import static org.objectweb.asm.Opcodes.ARETURN;
 import static org.objectweb.asm.Opcodes.H_INVOKESPECIAL;
 
@@ -60,8 +59,8 @@
 
   @Test
   public void testReference() throws Exception {
-    assumeTrue(parameters.isCfRuntime());
-    testForJvm()
+    parameters.assumeJvmTestParameters();
+    testForJvm(parameters)
         .addProgramClasses(C.class, Main.class)
         .addProgramClassFileData(getTransformedD())
         .run(parameters.getRuntime(), Main.class)
@@ -70,8 +69,8 @@
 
   @Test
   public void testD8() throws Exception {
-    assumeTrue(parameters.isDexRuntime());
-    testForD8(parameters.getBackend())
+    parameters.assumeDexRuntime();
+    testForD8()
         .addLibraryFiles(ToolHelper.getMostRecentAndroidJar())
         .addProgramClasses(C.class, Main.class)
         .addProgramClassFileData(getTransformedD())
diff --git a/src/test/java/com/android/tools/r8/cf/stackmap/InvalidLongStackValueMaxHeightTest.java b/src/test/java/com/android/tools/r8/cf/stackmap/InvalidLongStackValueMaxHeightTest.java
index 0880720..e112d51 100644
--- a/src/test/java/com/android/tools/r8/cf/stackmap/InvalidLongStackValueMaxHeightTest.java
+++ b/src/test/java/com/android/tools/r8/cf/stackmap/InvalidLongStackValueMaxHeightTest.java
@@ -6,7 +6,6 @@
 
 import static com.android.tools.r8.DiagnosticsMatcher.diagnosticMessage;
 import static org.hamcrest.CoreMatchers.containsString;
-import static org.junit.Assume.assumeTrue;
 
 import com.android.tools.r8.CompilationFailedException;
 import com.android.tools.r8.TestBase;
@@ -43,7 +42,7 @@
 
   @Test(expected = CompilationFailedException.class)
   public void testD8Cf() throws Exception {
-    assumeTrue(parameters.isCfRuntime());
+    parameters.assumeCfRuntime();
     testForD8(parameters.getBackend())
         .addProgramClasses(Tester.class)
         .addProgramClassFileData(getMainWithChangedMaxStackHeight())
@@ -57,8 +56,8 @@
 
   @Test()
   public void testD8Dex() throws Exception {
-    assumeTrue(parameters.isDexRuntime());
-    testForD8(parameters.getBackend())
+    parameters.assumeDexRuntime();
+    testForD8()
         .addProgramClasses(Tester.class)
         .addProgramClassFileData(getMainWithChangedMaxStackHeight())
         .setMinApi(parameters)
diff --git a/src/test/java/com/android/tools/r8/cf/stackmap/InvalidStackHeightTest.java b/src/test/java/com/android/tools/r8/cf/stackmap/InvalidStackHeightTest.java
index 9552075..b5998cb 100644
--- a/src/test/java/com/android/tools/r8/cf/stackmap/InvalidStackHeightTest.java
+++ b/src/test/java/com/android/tools/r8/cf/stackmap/InvalidStackHeightTest.java
@@ -5,7 +5,6 @@
 package com.android.tools.r8.cf.stackmap;
 
 import static org.hamcrest.CoreMatchers.containsString;
-import static org.junit.Assume.assumeTrue;
 
 import com.android.tools.r8.CompilationFailedException;
 import com.android.tools.r8.NeverInline;
@@ -43,7 +42,7 @@
 
   @Test(expected = CompilationFailedException.class)
   public void testD8Cf() throws Exception {
-    assumeTrue(parameters.isCfRuntime());
+    parameters.assumeCfRuntime();
     testForD8(parameters.getBackend())
         .addProgramClassFileData(getMainWithChangedMaxStackHeight())
         .setMinApi(parameters)
@@ -52,8 +51,8 @@
 
   @Test
   public void testD8Dex() throws Exception {
-    assumeTrue(parameters.isDexRuntime());
-    testForD8(parameters.getBackend())
+    parameters.assumeDexRuntime();
+    testForD8()
         .addProgramClassFileData(getMainWithChangedMaxStackHeight())
         .setMinApi(parameters)
         .compileWithExpectedDiagnostics(this::inspect)
diff --git a/src/test/java/com/android/tools/r8/cf/stackmap/LongStackValuesInFramesTest.java b/src/test/java/com/android/tools/r8/cf/stackmap/LongStackValuesInFramesTest.java
index 77cd080..6cae22e 100644
--- a/src/test/java/com/android/tools/r8/cf/stackmap/LongStackValuesInFramesTest.java
+++ b/src/test/java/com/android/tools/r8/cf/stackmap/LongStackValuesInFramesTest.java
@@ -5,7 +5,6 @@
 package com.android.tools.r8.cf.stackmap;
 
 import static com.android.tools.r8.cf.stackmap.LongStackValuesInFramesTest.LongStackValuesInFramesTest$MainDump.dump;
-import static org.junit.Assume.assumeTrue;
 
 import com.android.tools.r8.NeverInline;
 import com.android.tools.r8.TestBase;
@@ -14,6 +13,7 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
 import org.junit.runners.Parameterized.Parameters;
 import org.objectweb.asm.ClassWriter;
 import org.objectweb.asm.Label;
@@ -25,21 +25,18 @@
 
   private final String[] EXPECTED = new String[] {"52"};
 
-  private final TestParameters parameters;
+  @Parameter(0)
+  public TestParameters parameters;
 
   @Parameters(name = "{0}")
   public static TestParametersCollection data() {
     return getTestParameters().withAllRuntimes().withAllApiLevelsAlsoForCf().build();
   }
 
-  public LongStackValuesInFramesTest(TestParameters parameters) {
-    this.parameters = parameters;
-  }
-
   @Test
   public void testJvm() throws Exception {
-    assumeTrue(parameters.isCfRuntime());
-    testForJvm()
+    parameters.assumeJvmTestParameters();
+    testForJvm(parameters)
         .addProgramClasses(Tester.class)
         .addProgramClassFileData(dump())
         .run(parameters.getRuntime(), Main.class)
diff --git a/src/test/java/com/android/tools/r8/cf/stackmap/SharedExceptionTypeTest.java b/src/test/java/com/android/tools/r8/cf/stackmap/SharedExceptionTypeTest.java
index 1f30f40..09bb6dd 100644
--- a/src/test/java/com/android/tools/r8/cf/stackmap/SharedExceptionTypeTest.java
+++ b/src/test/java/com/android/tools/r8/cf/stackmap/SharedExceptionTypeTest.java
@@ -4,36 +4,33 @@
 
 package com.android.tools.r8.cf.stackmap;
 
-import static org.junit.Assume.assumeTrue;
 
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.TestParametersCollection;
-import com.android.tools.r8.utils.AndroidApiLevel;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
 import org.junit.runners.Parameterized.Parameters;
 
 @RunWith(Parameterized.class)
 public class SharedExceptionTypeTest extends TestBase {
 
-  private final TestParameters parameters;
-  private final String EXPECTED = "Hello World!";
+  private static final String EXPECTED = "Hello World!";
+
+  @Parameter(0)
+  public TestParameters parameters;
 
   @Parameters(name = "{0}")
   public static TestParametersCollection data() {
-    return getTestParameters().withAllRuntimes().build();
-  }
-
-  public SharedExceptionTypeTest(TestParameters parameters) {
-    this.parameters = parameters;
+    return getTestParameters().withAllRuntimes().withMinimumApiLevel().build();
   }
 
   @Test
   public void testJvm() throws Exception {
-    assumeTrue(parameters.isCfRuntime());
-    testForJvm()
+    parameters.assumeJvmTestParameters();
+    testForJvm(parameters)
         .addInnerClasses(SharedExceptionTypeTest.class)
         .run(parameters.getRuntime(), Main.class)
         .assertSuccessWithOutputLines(EXPECTED);
@@ -41,10 +38,10 @@
 
   @Test
   public void testD8() throws Exception {
-    assumeTrue(parameters.isDexRuntime());
-    testForD8(parameters.getBackend())
+    parameters.assumeDexRuntime();
+    testForD8()
         .addInnerClasses(SharedExceptionTypeTest.class)
-        .setMinApi(AndroidApiLevel.B)
+        .setMinApi(parameters)
         .addOptionsModification(options -> options.testing.readInputStackMaps = true)
         .run(parameters.getRuntime(), Main.class)
         .assertSuccessWithOutputLines(EXPECTED);
diff --git a/src/test/java/com/android/tools/r8/cf/stackmap/StackMapVerificationNoFrameForHandlerTest.java b/src/test/java/com/android/tools/r8/cf/stackmap/StackMapVerificationNoFrameForHandlerTest.java
index e8db38c..2b0bc97 100644
--- a/src/test/java/com/android/tools/r8/cf/stackmap/StackMapVerificationNoFrameForHandlerTest.java
+++ b/src/test/java/com/android/tools/r8/cf/stackmap/StackMapVerificationNoFrameForHandlerTest.java
@@ -6,7 +6,6 @@
 
 import static com.android.tools.r8.DiagnosticsMatcher.diagnosticMessage;
 import static org.hamcrest.CoreMatchers.containsString;
-import static org.junit.Assume.assumeTrue;
 
 import com.android.tools.r8.JvmTestRunResult;
 import com.android.tools.r8.TestBase;
@@ -49,9 +48,9 @@
 
   @Test
   public void testJvm() throws Exception {
-    assumeTrue(parameters.isCfRuntime());
+    parameters.assumeJvmTestParameters();
     JvmTestRunResult mainResult =
-        testForJvm()
+        testForJvm(parameters)
             .addProgramClassFileData(
                 includeFrameInHandler
                     ? MainDump.dump()
@@ -68,7 +67,7 @@
 
   @Test
   public void testD8() throws Exception {
-    assumeTrue(parameters.isDexRuntime());
+    parameters.assumeDexRuntime();
     testForD8()
         .addProgramClassFileData(
             includeFrameInHandler
diff --git a/src/test/java/com/android/tools/r8/cf/stackmap/SwitchStackFrameFallThroughTest.java b/src/test/java/com/android/tools/r8/cf/stackmap/SwitchStackFrameFallThroughTest.java
index e38eaf5..064eb84 100644
--- a/src/test/java/com/android/tools/r8/cf/stackmap/SwitchStackFrameFallThroughTest.java
+++ b/src/test/java/com/android/tools/r8/cf/stackmap/SwitchStackFrameFallThroughTest.java
@@ -4,7 +4,6 @@
 
 package com.android.tools.r8.cf.stackmap;
 
-import static org.junit.Assume.assumeTrue;
 
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
@@ -35,8 +34,8 @@
 
   @Test
   public void testJvm() throws Exception {
-    assumeTrue(parameters.isCfRuntime());
-    testForJvm()
+    parameters.assumeJvmTestParameters();
+    testForJvm(parameters)
         .addProgramClassFileData(SwitchStackFrameFallThroughTest$MainDump.dump())
         .run(parameters.getRuntime(), Main.class)
         .assertSuccessWithOutputLines("java.io.IOException");
@@ -44,8 +43,8 @@
 
   @Test
   public void testD8() throws Exception {
-    assumeTrue(parameters.isDexRuntime());
-    testForD8(parameters.getBackend())
+    parameters.assumeDexRuntime();
+    testForD8()
         .addProgramClassFileData(SwitchStackFrameFallThroughTest$MainDump.dump())
         .setMinApi(parameters)
         .addOptionsModification(options -> options.testing.readInputStackMaps = true)
diff --git a/src/test/java/com/android/tools/r8/cf/stackmap/UninitializedGetFieldTest.java b/src/test/java/com/android/tools/r8/cf/stackmap/UninitializedGetFieldTest.java
index d5540f3..34872cf 100644
--- a/src/test/java/com/android/tools/r8/cf/stackmap/UninitializedGetFieldTest.java
+++ b/src/test/java/com/android/tools/r8/cf/stackmap/UninitializedGetFieldTest.java
@@ -7,7 +7,6 @@
 import static com.android.tools.r8.DiagnosticsMatcher.diagnosticMessage;
 import static com.android.tools.r8.cf.stackmap.UninitializedGetFieldTest.MainDump.dump;
 import static org.hamcrest.CoreMatchers.containsString;
-import static org.junit.Assume.assumeTrue;
 
 import com.android.tools.r8.CompilationFailedException;
 import com.android.tools.r8.TestBase;
@@ -37,8 +36,8 @@
 
   @Test
   public void testJvm() throws Exception {
-    assumeTrue(parameters.isCfRuntime());
-    testForJvm()
+    parameters.assumeJvmTestParameters();
+    testForJvm(parameters)
         .addProgramClassFileData(dump())
         .run(parameters.getRuntime(), Main.class)
         .assertFailureWithErrorThatThrows(VerifyError.class);
@@ -46,7 +45,7 @@
 
   @Test(expected = CompilationFailedException.class)
   public void testD8Cf() throws Exception {
-    assumeTrue(parameters.isCfRuntime());
+    parameters.assumeCfRuntime();
     testForD8(parameters.getBackend())
         .addProgramClassFileData(dump())
         .setMinApi(parameters)
@@ -55,8 +54,8 @@
 
   @Test
   public void testD8Dex() throws Exception {
-    assumeTrue(parameters.isDexRuntime());
-    testForD8(parameters.getBackend())
+    parameters.assumeDexRuntime();
+    testForD8()
         .addProgramClassFileData(dump())
         .setMinApi(parameters)
         .compileWithExpectedDiagnostics(this::inspect)
diff --git a/src/test/java/com/android/tools/r8/cf/stackmap/UninitializedInstanceOfTest.java b/src/test/java/com/android/tools/r8/cf/stackmap/UninitializedInstanceOfTest.java
index b5fd730..49f3a19 100644
--- a/src/test/java/com/android/tools/r8/cf/stackmap/UninitializedInstanceOfTest.java
+++ b/src/test/java/com/android/tools/r8/cf/stackmap/UninitializedInstanceOfTest.java
@@ -6,7 +6,6 @@
 
 import static com.android.tools.r8.cf.stackmap.UninitializedInstanceOfTest.MainDump.dump;
 import static org.hamcrest.CoreMatchers.containsString;
-import static org.junit.Assume.assumeTrue;
 
 import com.android.tools.r8.CompilationFailedException;
 import com.android.tools.r8.TestBase;
@@ -37,8 +36,8 @@
 
   @Test
   public void testJvm() throws Exception {
-    assumeTrue(parameters.isCfRuntime());
-    testForJvm()
+    parameters.assumeJvmTestParameters();
+    testForJvm(parameters)
         .addProgramClassFileData(dump())
         .run(parameters.getRuntime(), Main.class)
         .assertFailureWithErrorThatThrows(VerifyError.class);
@@ -46,7 +45,7 @@
 
   @Test(expected = CompilationFailedException.class)
   public void testD8Cf() throws Exception {
-    assumeTrue(parameters.isCfRuntime());
+    parameters.assumeCfRuntime();
     testForD8(parameters.getBackend())
         .addProgramClassFileData(dump())
         .setMinApi(parameters)
@@ -55,7 +54,7 @@
 
   @Test()
   public void testD8Dex() throws Exception {
-    assumeTrue(parameters.isDexRuntime());
+    parameters.assumeDexRuntime();
     boolean expectFailure = parameters.getDexRuntimeVersion().isNewerThanOrEqual(Version.V7_0_0);
     testForD8(parameters.getBackend())
         .addProgramClassFileData(dump())
diff --git a/src/test/java/com/android/tools/r8/cf/stackmap/UninitializedNewCheckCastTest.java b/src/test/java/com/android/tools/r8/cf/stackmap/UninitializedNewCheckCastTest.java
index 9039a86..78d805b 100644
--- a/src/test/java/com/android/tools/r8/cf/stackmap/UninitializedNewCheckCastTest.java
+++ b/src/test/java/com/android/tools/r8/cf/stackmap/UninitializedNewCheckCastTest.java
@@ -6,7 +6,6 @@
 
 import static com.android.tools.r8.cf.stackmap.UninitializedNewCheckCastTest.MainDump.dump;
 import static org.hamcrest.CoreMatchers.containsString;
-import static org.junit.Assume.assumeTrue;
 
 import com.android.tools.r8.CompilationFailedException;
 import com.android.tools.r8.TestBase;
@@ -35,8 +34,8 @@
 
   @Test
   public void testJvm() throws Exception {
-    assumeTrue(parameters.isCfRuntime());
-    testForJvm()
+    parameters.assumeJvmTestParameters();
+    testForJvm(parameters)
         .addProgramClassFileData(dump())
         .run(parameters.getRuntime(), Main.class)
         .assertFailureWithErrorThatThrows(VerifyError.class);
@@ -44,7 +43,7 @@
 
   @Test(expected = CompilationFailedException.class)
   public void testD8Cf() throws Exception {
-    assumeTrue(parameters.isCfRuntime());
+    parameters.assumeCfRuntime();
     testForD8(parameters.getBackend())
         .addProgramClassFileData(dump())
         .setMinApi(parameters)
@@ -53,8 +52,8 @@
 
   @Test
   public void testD8Dex() throws Exception {
-    assumeTrue(parameters.isDexRuntime());
-    testForD8(parameters.getBackend())
+    parameters.assumeDexRuntime();
+    testForD8()
         .addProgramClassFileData(dump())
         .setMinApi(parameters)
         .compileWithExpectedDiagnostics(this::inspect)
diff --git a/src/test/java/com/android/tools/r8/cf/stackmap/UninitializedPutFieldSelfTest.java b/src/test/java/com/android/tools/r8/cf/stackmap/UninitializedPutFieldSelfTest.java
index 4e541e4..d7a852d 100644
--- a/src/test/java/com/android/tools/r8/cf/stackmap/UninitializedPutFieldSelfTest.java
+++ b/src/test/java/com/android/tools/r8/cf/stackmap/UninitializedPutFieldSelfTest.java
@@ -6,7 +6,6 @@
 
 import static com.android.tools.r8.cf.stackmap.UninitializedPutFieldSelfTest.MainDump.dump;
 import static org.hamcrest.CoreMatchers.containsString;
-import static org.junit.Assume.assumeTrue;
 
 import com.android.tools.r8.CompilationFailedException;
 import com.android.tools.r8.TestBase;
@@ -17,6 +16,7 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
 import org.junit.runners.Parameterized.Parameters;
 import org.objectweb.asm.ClassWriter;
 import org.objectweb.asm.FieldVisitor;
@@ -26,7 +26,8 @@
 @RunWith(Parameterized.class)
 public class UninitializedPutFieldSelfTest extends TestBase {
 
-  private final TestParameters parameters;
+  @Parameter(0)
+  public TestParameters parameters;
 
   @Parameters(name = "{0}")
   public static TestParametersCollection data() {
@@ -35,8 +36,8 @@
 
   @Test
   public void testJvm() throws Exception {
-    assumeTrue(parameters.isCfRuntime());
-    testForJvm()
+    parameters.assumeJvmTestParameters();
+    testForJvm(parameters)
         .addProgramClassFileData(dump())
         .run(parameters.getRuntime(), Main.class)
         .assertFailureWithErrorThatThrows(VerifyError.class);
@@ -44,7 +45,7 @@
 
   @Test(expected = CompilationFailedException.class)
   public void testD8Cf() throws Exception {
-    assumeTrue(parameters.isCfRuntime());
+    parameters.assumeCfRuntime();
     testForD8(parameters.getBackend())
         .addProgramClassFileData(dump())
         .setMinApi(parameters)
@@ -53,11 +54,11 @@
 
   @Test
   public void testD8Dex() throws Exception {
-    assumeTrue(parameters.isDexRuntime());
+    parameters.assumeDexRuntime();
     boolean willFailVerification =
         parameters.getDexRuntimeVersion().isOlderThan(Version.V5_1_1)
             || parameters.getDexRuntimeVersion().isNewerThan(Version.V6_0_1);
-    testForD8(parameters.getBackend())
+    testForD8()
         .addProgramClassFileData(dump())
         .setMinApi(parameters)
         .compileWithExpectedDiagnostics(this::inspect)
@@ -78,10 +79,6 @@
     }
   }
 
-  public UninitializedPutFieldSelfTest(TestParameters parameters) {
-    this.parameters = parameters;
-  }
-
   public static class Main {
 
     private Main main;
diff --git a/src/test/java/com/android/tools/r8/cf/stackmap/UninitializedPutFieldTest.java b/src/test/java/com/android/tools/r8/cf/stackmap/UninitializedPutFieldTest.java
index 7740360..4c8fa72 100644
--- a/src/test/java/com/android/tools/r8/cf/stackmap/UninitializedPutFieldTest.java
+++ b/src/test/java/com/android/tools/r8/cf/stackmap/UninitializedPutFieldTest.java
@@ -7,7 +7,6 @@
 import static com.android.tools.r8.DiagnosticsMatcher.diagnosticMessage;
 import static com.android.tools.r8.cf.stackmap.UninitializedPutFieldTest.MainDump.dump;
 import static org.hamcrest.CoreMatchers.containsString;
-import static org.junit.Assume.assumeTrue;
 
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
@@ -15,6 +14,7 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
 import org.junit.runners.Parameterized.Parameters;
 import org.objectweb.asm.ClassWriter;
 import org.objectweb.asm.FieldVisitor;
@@ -24,8 +24,10 @@
 @RunWith(Parameterized.class)
 public class UninitializedPutFieldTest extends TestBase {
 
-  private final String[] EXPECTED = new String[] {"Main::foo"};
-  private final TestParameters parameters;
+  private static final String[] EXPECTED = new String[] {"Main::foo"};
+
+  @Parameter(0)
+  public TestParameters parameters;
 
   @Parameters(name = "{0}")
   public static TestParametersCollection data() {
@@ -34,16 +36,16 @@
 
   @Test
   public void testJvm() throws Exception {
-    assumeTrue(parameters.isCfRuntime());
-    testForJvm()
+    parameters.assumeJvmTestParameters();
+    testForJvm(parameters)
         .addProgramClassFileData(dump())
         .run(parameters.getRuntime(), Main.class)
         .assertSuccessWithOutputLines(EXPECTED);
   }
 
-  @Test()
+  @Test
   public void testD8Cf() throws Exception {
-    assumeTrue(parameters.isCfRuntime());
+    parameters.assumeCfRuntime();
     testForD8(parameters.getBackend())
         .addProgramClassFileData(dump())
         .setMinApi(parameters)
@@ -58,8 +60,8 @@
 
   @Test
   public void testD8Dex() throws Exception {
-    assumeTrue(parameters.isDexRuntime());
-    testForD8(parameters.getBackend())
+    parameters.assumeDexRuntime();
+    testForD8()
         .addProgramClassFileData(dump())
         .setMinApi(parameters)
         .compileWithExpectedDiagnostics(
@@ -71,10 +73,6 @@
         .assertSuccessWithOutputLines(EXPECTED);
   }
 
-  public UninitializedPutFieldTest(TestParameters parameters) {
-    this.parameters = parameters;
-  }
-
   public static class Main {
 
     private Object object;
diff --git a/src/test/java/com/android/tools/r8/cf/varhandle/VarHandleDesugaringTestBase.java b/src/test/java/com/android/tools/r8/cf/varhandle/VarHandleDesugaringTestBase.java
index e4cfea6..3d0484c 100644
--- a/src/test/java/com/android/tools/r8/cf/varhandle/VarHandleDesugaringTestBase.java
+++ b/src/test/java/com/android/tools/r8/cf/varhandle/VarHandleDesugaringTestBase.java
@@ -77,7 +77,7 @@
     // possible spurious failures but expect it to behave like compareAndSet (which is what the
     // desugared implementation does.
     assumeTrue(parameters.isCfRuntime() && parameters.asCfRuntime().isNewerThanOrEqual(CfVm.JDK9));
-    testForJvm()
+    testForJvm(parameters)
         .addProgramFiles(VarHandle.jar())
         .run(parameters.getRuntime(), getMainClass())
         .assertSuccessWithOutput(getExpectedOutputForReferenceImplementation());
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/ImplicitClassInitializationSynchronizationTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/ImplicitClassInitializationSynchronizationTest.java
index 834a1f6..0380300 100644
--- a/src/test/java/com/android/tools/r8/classmerging/horizontal/ImplicitClassInitializationSynchronizationTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/ImplicitClassInitializationSynchronizationTest.java
@@ -4,7 +4,6 @@
 
 package com.android.tools.r8.classmerging.horizontal;
 
-import static org.junit.Assume.assumeTrue;
 
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
@@ -47,8 +46,8 @@
 
   @Test
   public void testJvm() throws Exception {
-    assumeTrue(parameters.isCfRuntime());
-    testForJvm()
+    parameters.assumeJvmTestParameters();
+    testForJvm(parameters)
         .addTestClasspath()
         .run(parameters.getRuntime(), Main.class)
         .assertSuccessWithOutputLines(getExpectedOutput());
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/MergedConstructorStackTraceTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/MergedConstructorStackTraceTest.java
index be3d82f..bb0626e 100644
--- a/src/test/java/com/android/tools/r8/classmerging/horizontal/MergedConstructorStackTraceTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/MergedConstructorStackTraceTest.java
@@ -14,22 +14,22 @@
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.TestRuntime.CfRuntime;
 import com.android.tools.r8.naming.retrace.StackTrace;
-import org.junit.Before;
+import org.junit.BeforeClass;
 import org.junit.Test;
 
 public class MergedConstructorStackTraceTest extends HorizontalClassMergingTestBase {
 
-  public StackTrace expectedStackTrace;
+  private static StackTrace expectedStackTrace;
 
   public MergedConstructorStackTraceTest(TestParameters parameters) {
     super(parameters);
   }
 
-  @Before
-  public void setup() throws Exception {
+  @BeforeClass
+  public static void setup() throws Exception {
     // Get the expected stack trace by running on the JVM.
     expectedStackTrace =
-        testForJvm()
+        testForJvm(getStaticTemp())
             .addTestClasspath()
             .run(CfRuntime.getSystemRuntime(), Main.class)
             .assertFailure()
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/MergedConstructorWithEquivalenceStackTraceTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/MergedConstructorWithEquivalenceStackTraceTest.java
index f43e7bd..c39d3ef 100644
--- a/src/test/java/com/android/tools/r8/classmerging/horizontal/MergedConstructorWithEquivalenceStackTraceTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/MergedConstructorWithEquivalenceStackTraceTest.java
@@ -14,22 +14,22 @@
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.TestRuntime.CfRuntime;
 import com.android.tools.r8.naming.retrace.StackTrace;
-import org.junit.Before;
+import org.junit.BeforeClass;
 import org.junit.Test;
 
 public class MergedConstructorWithEquivalenceStackTraceTest extends HorizontalClassMergingTestBase {
 
-  public StackTrace expectedStackTrace;
+  private static StackTrace expectedStackTrace;
 
   public MergedConstructorWithEquivalenceStackTraceTest(TestParameters parameters) {
     super(parameters);
   }
 
-  @Before
-  public void setup() throws Exception {
+  @BeforeClass
+  public static void setup() throws Exception {
     // Get the expected stack trace by running on the JVM.
     expectedStackTrace =
-        testForJvm()
+        testForJvm(getStaticTemp())
             .addTestClasspath()
             .run(CfRuntime.getSystemRuntime(), Main.class)
             .assertFailure()
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/MergedVirtualMethodStackTraceTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/MergedVirtualMethodStackTraceTest.java
index da563cb..e1cdfe3 100644
--- a/src/test/java/com/android/tools/r8/classmerging/horizontal/MergedVirtualMethodStackTraceTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/MergedVirtualMethodStackTraceTest.java
@@ -18,7 +18,7 @@
 import com.android.tools.r8.utils.BooleanUtils;
 import com.android.tools.r8.utils.InternalOptions.InlinerOptions;
 import java.util.List;
-import org.junit.Before;
+import org.junit.BeforeClass;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
@@ -27,6 +27,8 @@
 @RunWith(Parameterized.class)
 public class MergedVirtualMethodStackTraceTest extends TestBase {
 
+  private static StackTrace expectedStackTrace;
+
   @Parameter(0)
   public TestParameters parameters;
 
@@ -39,13 +41,11 @@
         getTestParameters().withAllRuntimesAndApiLevels().build(), BooleanUtils.values());
   }
 
-  public StackTrace expectedStackTrace;
-
-  @Before
-  public void setup() throws Exception {
+  @BeforeClass
+  public static void setup() throws Exception {
     // Get the expected stack trace by running on the JVM.
     expectedStackTrace =
-        testForJvm()
+        testForJvm(getStaticTemp())
             .addTestClasspath()
             .run(CfRuntime.getSystemRuntime(), Main.class)
             .assertFailure()
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontalstatic/InliningAfterStaticClassMergerTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontalstatic/InliningAfterStaticClassMergerTest.java
index 077f3ad..c3cd8f4 100644
--- a/src/test/java/com/android/tools/r8/classmerging/horizontalstatic/InliningAfterStaticClassMergerTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/horizontalstatic/InliningAfterStaticClassMergerTest.java
@@ -21,6 +21,7 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
 import org.junit.runners.Parameterized.Parameters;
 
 /**
@@ -30,6 +31,9 @@
 @RunWith(Parameterized.class)
 public class InliningAfterStaticClassMergerTest extends TestBase {
 
+  private static final String EXPECTED_OUTPUT =
+      StringUtils.joinLines("StaticMergeCandidateA.m()", "StaticMergeCandidateB.m()");
+
   // A class that implements a library class.
   static class StaticMergeCandidateA implements Cloneable {
 
@@ -60,11 +64,8 @@
     }
   }
 
-  private final TestParameters parameters;
-
-  public InliningAfterStaticClassMergerTest(TestParameters parameters) {
-    this.parameters = parameters;
-  }
+  @Parameter(0)
+  public TestParameters parameters;
 
   @Parameters(name = "{0}")
   public static TestParametersCollection data() {
@@ -72,12 +73,16 @@
   }
 
   @Test
+  public void testJvm() throws Exception {
+    parameters.assumeJvmTestParameters();
+    testForJvm(parameters)
+        .addTestClasspath()
+        .run(parameters.getRuntime(), TestClass.class)
+        .assertSuccessWithOutput(EXPECTED_OUTPUT);
+  }
+
+  @Test
   public void testMethodsAreInlined() throws Exception {
-    String expected =
-        StringUtils.joinLines("StaticMergeCandidateA.m()", "StaticMergeCandidateB.m()");
-
-    testForJvm().addTestClasspath().run(TestClass.class).assertSuccessWithOutput(expected);
-
     CodeInspector inspector =
         testForR8(parameters.getBackend())
             .addProgramClasses(
@@ -89,7 +94,7 @@
             .addDontObfuscate()
             .setMinApi(parameters)
             .run(parameters.getRuntime(), TestClass.class)
-            .assertSuccessWithOutput(expected)
+            .assertSuccessWithOutput(EXPECTED_OUTPUT)
             .inspector();
 
     // Check that StaticMergeCandidateB has been removed.
diff --git a/src/test/java/com/android/tools/r8/classmerging/vertical/B141942381.java b/src/test/java/com/android/tools/r8/classmerging/vertical/B141942381.java
index e09fd4b..07d4778 100644
--- a/src/test/java/com/android/tools/r8/classmerging/vertical/B141942381.java
+++ b/src/test/java/com/android/tools/r8/classmerging/vertical/B141942381.java
@@ -37,7 +37,7 @@
   @Test
   public void testJVM() throws Exception {
     parameters.assumeJvmTestParameters();
-    testForJvm()
+    testForJvm(parameters)
         .addTestClasspath()
         .run(parameters.getRuntime(), TestClass.class)
         .assertSuccessWithOutputLines("true");
diff --git a/src/test/java/com/android/tools/r8/classmerging/vertical/StaticInitializerTest.java b/src/test/java/com/android/tools/r8/classmerging/vertical/StaticInitializerTest.java
index aa6a4f7..637ec96 100644
--- a/src/test/java/com/android/tools/r8/classmerging/vertical/StaticInitializerTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/vertical/StaticInitializerTest.java
@@ -6,41 +6,47 @@
 
 import com.android.tools.r8.NeverInline;
 import com.android.tools.r8.TestBase;
-import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
 import com.android.tools.r8.utils.StringUtils;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
 import org.junit.runners.Parameterized.Parameters;
 
 @RunWith(Parameterized.class)
 public class StaticInitializerTest extends TestBase {
 
-  private final Backend backend;
+  private static final String EXPECTED_OUTPUT =
+      StringUtils.lines("In A.m()", "In B.<clinit>()", "In B.m()");
 
-  @Parameters(name = "Backend: {0}")
-  public static Backend[] data() {
-    return ToolHelper.getBackends();
-  }
+  @Parameter(0)
+  public TestParameters parameters;
 
-  public StaticInitializerTest(Backend backend) {
-    this.backend = backend;
+  @Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withAllRuntimesAndApiLevels().build();
   }
 
   @Test
-  public void test() throws Exception {
-    String expectedOutput = StringUtils.lines("In A.m()", "In B.<clinit>()", "In B.m()");
+  public void testJvm() throws Exception {
+    parameters.assumeJvmTestParameters();
+    testForJvm(parameters)
+        .addTestClasspath()
+        .run(parameters.getRuntime(), TestClass.class)
+        .assertSuccessWithOutput(EXPECTED_OUTPUT);
+  }
 
-    if (backend == Backend.CF) {
-      testForJvm().addTestClasspath().run(TestClass.class).assertSuccessWithOutput(expectedOutput);
-    }
-
-    testForR8(backend)
+  @Test
+  public void testR8() throws Exception {
+    testForR8(parameters.getBackend())
         .addInnerClasses(StaticInitializerTest.class)
         .addKeepMainRule(TestClass.class)
         .enableInliningAnnotations()
-        .run(TestClass.class)
-        .assertSuccessWithOutput(expectedOutput);
+        .setMinApi(parameters)
+        .run(parameters.getRuntime(), TestClass.class)
+        .assertSuccessWithOutput(EXPECTED_OUTPUT);
   }
 
   static class TestClass {
diff --git a/src/test/java/com/android/tools/r8/classmerging/vertical/VerticalClassMergerSuperToLibraryTest.java b/src/test/java/com/android/tools/r8/classmerging/vertical/VerticalClassMergerSuperToLibraryTest.java
index fa191c8..a05424e 100644
--- a/src/test/java/com/android/tools/r8/classmerging/vertical/VerticalClassMergerSuperToLibraryTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/vertical/VerticalClassMergerSuperToLibraryTest.java
@@ -6,7 +6,6 @@
 
 import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
 import static org.hamcrest.MatcherAssert.assertThat;
-import static org.junit.Assume.assumeTrue;
 import static org.objectweb.asm.Opcodes.INVOKESPECIAL;
 
 import com.android.tools.r8.NeverClassInline;
@@ -39,8 +38,8 @@
 
   @Test
   public void testJvm() throws Exception {
-    assumeTrue(parameters.isCfRuntime());
-    testForJvm()
+    parameters.assumeJvmTestParameters();
+    testForJvm(parameters)
         .addProgramClasses(B.class, Main.class)
         .addProgramClassFileData(getAWithRewrittenInvokeSpecialToBase())
         .addLibraryClasses(LibParent.class)
@@ -52,8 +51,8 @@
 
   @Test
   public void testD8() throws Exception {
-    assumeTrue(parameters.isDexRuntime());
-    testForD8(parameters.getBackend())
+    parameters.assumeDexRuntime();
+    testForD8()
         .addDefaultRuntimeLibrary(parameters)
         .addLibraryClasses(Lib.class, LibParent.class)
         .addProgramClasses(B.class, Main.class)
diff --git a/src/test/java/com/android/tools/r8/classmerging/vertical/VerticalClassMergerVirtualToLibraryTest.java b/src/test/java/com/android/tools/r8/classmerging/vertical/VerticalClassMergerVirtualToLibraryTest.java
index 468309e..57ad5f6 100644
--- a/src/test/java/com/android/tools/r8/classmerging/vertical/VerticalClassMergerVirtualToLibraryTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/vertical/VerticalClassMergerVirtualToLibraryTest.java
@@ -6,7 +6,6 @@
 
 import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
 import static org.hamcrest.MatcherAssert.assertThat;
-import static org.junit.Assume.assumeTrue;
 
 import com.android.tools.r8.NeverClassInline;
 import com.android.tools.r8.NeverInline;
@@ -37,8 +36,8 @@
 
   @Test
   public void testJvm() throws Exception {
-    assumeTrue(parameters.isCfRuntime());
-    testForJvm()
+    parameters.assumeJvmTestParameters();
+    testForJvm(parameters)
         .addProgramClasses(B.class, Main.class, A.class)
         .addLibraryClassFileData(classWithoutBarMethod(LibParent.class))
         .addLibraryClasses(Lib.class)
@@ -52,8 +51,8 @@
 
   @Test
   public void testD8() throws Exception {
-    assumeTrue(parameters.isDexRuntime());
-    testForD8(parameters.getBackend())
+    parameters.assumeDexRuntime();
+    testForD8()
         .addDefaultRuntimeLibrary(parameters)
         .addLibraryClasses(LibParent.class)
         .addLibraryClassFileData(classWithoutBarMethod(Lib.class))
diff --git a/src/test/java/com/android/tools/r8/code/PassThroughTest.java b/src/test/java/com/android/tools/r8/code/PassThroughTest.java
index cb93c83..acbb529 100644
--- a/src/test/java/com/android/tools/r8/code/PassThroughTest.java
+++ b/src/test/java/com/android/tools/r8/code/PassThroughTest.java
@@ -5,6 +5,7 @@
 package com.android.tools.r8.code;
 
 import static junit.framework.Assert.assertSame;
+import static org.junit.Assume.assumeTrue;
 
 import com.android.tools.r8.ArchiveClassFileProvider;
 import com.android.tools.r8.CfFrontendExamplesTest;
@@ -18,7 +19,6 @@
 import com.android.tools.r8.utils.BooleanUtils;
 import com.android.tools.r8.utils.DescriptorUtils;
 import com.android.tools.r8.utils.StringUtils;
-import com.android.tools.r8.utils.codeinspector.CodeInspector;
 import java.nio.file.Path;
 import java.util.Arrays;
 import java.util.List;
@@ -27,6 +27,7 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
 import org.junit.runners.Parameterized.Parameters;
 
 @RunWith(Parameterized.class)
@@ -34,27 +35,25 @@
 
   private final String EXPECTED = StringUtils.lines("0", "foo", "0", "foo", "foo");
 
-  private final TestParameters parameters;
-  private final boolean keepDebug;
+  @Parameter(0)
+  public TestParameters parameters;
+
+  @Parameter(1)
+  public boolean keepDebug;
 
   @Parameters(name = "{0}, keep-debug: {1}")
   public static List<Object[]> data() {
     return buildParameters(getTestParameters().withCfRuntimes().build(), BooleanUtils.values());
   }
 
-  public PassThroughTest(TestParameters parameters, boolean keepDebug) {
-    this.parameters = parameters;
-    this.keepDebug = keepDebug;
-  }
-
   @Test
-  public void testJmv() throws Exception {
-    CodeInspector inspector =
-        testForJvm()
-            .addProgramClasses(Main.class)
-            .run(parameters.getRuntime(), Main.class)
-            .assertSuccessWithOutput(EXPECTED)
-            .inspector();
+  public void testJvm() throws Exception {
+    assumeTrue(keepDebug);
+    testForJvm(parameters)
+        .addProgramClasses(Main.class)
+        .run(parameters.getRuntime(), Main.class)
+        .assertSuccessWithOutput(EXPECTED);
+
     // Check that reading the same input is actual matches.
     ClassFileResourceProvider original =
         DirectoryClassFileProvider.fromDirectory(ToolHelper.getClassPathForTests());
diff --git a/src/test/java/com/android/tools/r8/code/invokedynamic/InvokeCustomRuntimeErrorTest.java b/src/test/java/com/android/tools/r8/code/invokedynamic/InvokeCustomRuntimeErrorTest.java
index adb977f..5d5e72a 100644
--- a/src/test/java/com/android/tools/r8/code/invokedynamic/InvokeCustomRuntimeErrorTest.java
+++ b/src/test/java/com/android/tools/r8/code/invokedynamic/InvokeCustomRuntimeErrorTest.java
@@ -56,8 +56,8 @@
 
   @Test
   public void testReference() throws Throwable {
-    assumeTrue(parameters.isCfRuntime());
-    testForJvm()
+    parameters.assumeJvmTestParameters();
+    testForJvm(parameters)
         .addProgramClasses(I.class, A.class)
         .addProgramClassFileData(getTransformedTestClass())
         .run(parameters.getRuntime(), TestClass.class)
diff --git a/src/test/java/com/android/tools/r8/compatproguard/CompatKeepClassMemberNamesTestRunner.java b/src/test/java/com/android/tools/r8/compatproguard/CompatKeepClassMemberNamesTestRunner.java
index a733112..1bd723a 100644
--- a/src/test/java/com/android/tools/r8/compatproguard/CompatKeepClassMemberNamesTestRunner.java
+++ b/src/test/java/com/android/tools/r8/compatproguard/CompatKeepClassMemberNamesTestRunner.java
@@ -29,6 +29,7 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
 import org.junit.runners.Parameterized.Parameters;
 
 /** Regression test for compatibility with Proguard -keepclassmember{s,names}. b/119076934. */
@@ -58,17 +59,15 @@
     return getTestParameters().withCfRuntimes().build();
   }
 
-  private final TestParameters parameters;
-
-  public CompatKeepClassMemberNamesTestRunner(TestParameters parameters) {
-    this.parameters = parameters;
-  }
+  @Parameter(0)
+  public TestParameters parameters;
 
   // Test reference implementation.
 
   @Test
   public void testJvm() throws Exception {
-    testForJvm()
+    parameters.assumeJvmTestParameters();
+    testForJvm(parameters)
         .addProgramClasses(CLASSES)
         .run(parameters.getRuntime(), MAIN_CLASS)
         .assertSuccessWithOutput(EXPECTED);
diff --git a/src/test/java/com/android/tools/r8/compatproguard/ifrules/ConditionalOnInlinedFieldTest.java b/src/test/java/com/android/tools/r8/compatproguard/ifrules/ConditionalOnInlinedFieldTest.java
index 588948f..f767bd0 100644
--- a/src/test/java/com/android/tools/r8/compatproguard/ifrules/ConditionalOnInlinedFieldTest.java
+++ b/src/test/java/com/android/tools/r8/compatproguard/ifrules/ConditionalOnInlinedFieldTest.java
@@ -3,17 +3,23 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.compatproguard.ifrules;
 
+import static org.junit.Assume.assumeFalse;
+import static org.junit.Assume.assumeTrue;
+
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.TestRunResult;
 import com.android.tools.r8.TestShrinkerBuilder;
 import com.android.tools.r8.shaking.methods.MethodsTestBase.Shrinker;
+import com.android.tools.r8.utils.ArrayUtils;
 import com.android.tools.r8.utils.BooleanUtils;
 import com.android.tools.r8.utils.StringUtils;
 import java.util.List;
+import java.util.Optional;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
 import org.junit.runners.Parameterized.Parameters;
 
 @RunWith(Parameterized.class)
@@ -54,24 +60,24 @@
     }
   }
 
-  private static String EXPECTED = StringUtils.lines("B::method");
+  private static final String EXPECTED = StringUtils.lines("B::method");
 
   @Parameters(name = "{0}, {1}, ref:{2}")
   public static List<Object[]> data() {
     return buildParameters(
-        Shrinker.values(), getTestParameters().withCfRuntimes().build(), BooleanUtils.values());
+        ArrayUtils.withOptionalNone(Shrinker.values()),
+        getTestParameters().withCfRuntimes().build(),
+        BooleanUtils.values());
   }
 
-  private final Shrinker shrinker;
-  private final TestParameters parameters;
-  private final boolean withFieldReference;
+  @Parameter(0)
+  public Optional<Shrinker> optionalShrinker;
 
-  public ConditionalOnInlinedFieldTest(
-      Shrinker shrinker, TestParameters parameters, boolean withFieldReference) {
-    this.shrinker = shrinker;
-    this.parameters = parameters;
-    this.withFieldReference = withFieldReference;
-  }
+  @Parameter(1)
+  public TestParameters parameters;
+
+  @Parameter(2)
+  public boolean withFieldReference;
 
   private Class<?> getMain() {
     return withFieldReference ? MainWithFieldReference.class : MainWithoutFieldReference.class;
@@ -79,13 +85,15 @@
 
   @Test
   public void testReference() throws Exception {
-    testForJvm()
+    assumeFalse(optionalShrinker.isPresent());
+    assumeTrue(withFieldReference);
+    testForJvm(parameters)
         .addProgramClasses(getMain(), A.class, B.class)
         .run(parameters.getRuntime(), getMain(), B.class.getTypeName())
         .assertSuccessWithOutput(EXPECTED);
   }
 
-  private TestShrinkerBuilder<?, ?, ?, ?, ?> buildShrinker() throws Exception {
+  private TestShrinkerBuilder<?, ?, ?, ?, ?> buildShrinker(Shrinker shrinker) {
     TestShrinkerBuilder<?, ?, ?, ?, ?> builder;
     if (shrinker == Shrinker.Proguard) {
       builder = testForProguard().addDontWarn(ConditionalOnInlinedFieldTest.class);
@@ -108,8 +116,12 @@
 
   @Test
   public void testConditionalOnField() throws Exception {
+    assumeTrue(optionalShrinker.isPresent());
+    Shrinker shrinker = optionalShrinker.get();
     TestRunResult<?> result =
-        buildShrinker().compile().run(parameters.getRuntime(), getMain(), B.class.getTypeName());
+        buildShrinker(shrinker)
+            .compile()
+            .run(parameters.getRuntime(), getMain(), B.class.getTypeName());
     if (!withFieldReference && shrinker != Shrinker.Proguard) {
       // Without the reference we expect an error. For some reason PG keeps in any case.
       result.assertFailureWithErrorThatThrows(ClassNotFoundException.class);
diff --git a/src/test/java/com/android/tools/r8/compatproguard/ifrules/ConditionalOnInlinedTest.java b/src/test/java/com/android/tools/r8/compatproguard/ifrules/ConditionalOnInlinedTest.java
index e1d6571..4a9e493 100644
--- a/src/test/java/com/android/tools/r8/compatproguard/ifrules/ConditionalOnInlinedTest.java
+++ b/src/test/java/com/android/tools/r8/compatproguard/ifrules/ConditionalOnInlinedTest.java
@@ -3,18 +3,25 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.compatproguard.ifrules;
 
+import static org.junit.Assume.assumeFalse;
+import static org.junit.Assume.assumeTrue;
+
+import com.android.tools.r8.ProguardVersion;
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.TestRunResult;
 import com.android.tools.r8.TestShrinkerBuilder;
 import com.android.tools.r8.shaking.methods.MethodsTestBase.Shrinker;
+import com.android.tools.r8.utils.ArrayUtils;
 import com.android.tools.r8.utils.StringUtils;
 import com.google.common.collect.ImmutableList;
 import java.util.Collection;
 import java.util.List;
+import java.util.Optional;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
 import org.junit.runners.Parameterized.Parameters;
 
 @RunWith(Parameterized.class)
@@ -47,29 +54,30 @@
 
   @Parameters(name = "{0}, {1}")
   public static List<Object[]> data() {
-    return buildParameters(Shrinker.values(), getTestParameters().withCfRuntimes().build());
+    return buildParameters(
+        ArrayUtils.withOptionalNone(Shrinker.values()),
+        getTestParameters().withCfRuntimes().build());
   }
 
-  private final Shrinker shrinker;
-  private final TestParameters parameters;
+  @Parameter(0)
+  public Optional<Shrinker> optionalShrinker;
 
-  public ConditionalOnInlinedTest(Shrinker shrinker, TestParameters parameters) {
-    this.shrinker = shrinker;
-    this.parameters = parameters;
-  }
+  @Parameter(1)
+  public TestParameters parameters;
 
   @Test
   public void testReference() throws Exception {
-    testForJvm()
+    assumeFalse(optionalShrinker.isPresent());
+    testForJvm(parameters)
         .addProgramClasses(CLASSES)
         .run(parameters.getRuntime(), MAIN_CLASS, B.class.getTypeName())
         .assertSuccessWithOutput(EXPECTED);
   }
 
-  private TestShrinkerBuilder<?, ?, ?, ?, ?> buildShrinker() throws Exception {
+  private TestShrinkerBuilder<?, ?, ?, ?, ?> buildShrinker(Shrinker shrinker) {
     TestShrinkerBuilder<?, ?, ?, ?, ?> builder;
     if (shrinker == Shrinker.Proguard) {
-      builder = testForProguard().addDontWarn(ConditionalOnInlinedTest.class);
+      builder = testForProguard(ProguardVersion.V6_0_1).addDontWarn(ConditionalOnInlinedTest.class);
     } else if (shrinker == Shrinker.R8Compat) {
       builder = testForR8Compat(parameters.getBackend());
     } else {
@@ -80,8 +88,10 @@
 
   @Test
   public void testConditionalOnClass() throws Exception {
+    assumeTrue(optionalShrinker.isPresent());
+    Shrinker shrinker = optionalShrinker.get();
     TestRunResult<?> result =
-        buildShrinker()
+        buildShrinker(shrinker)
             .addKeepRules(
                 "-if class "
                     + A.class.getTypeName()
@@ -100,8 +110,10 @@
 
   @Test
   public void testConditionalOnClassAndMethod() throws Exception {
+    assumeTrue(optionalShrinker.isPresent());
+    Shrinker shrinker = optionalShrinker.get();
     TestRunResult<?> result =
-        buildShrinker()
+        buildShrinker(shrinker)
             .addKeepRules(
                 "-if class "
                     + A.class.getTypeName()
diff --git a/src/test/java/com/android/tools/r8/compatproguard/reflection/ReflectionTest.java b/src/test/java/com/android/tools/r8/compatproguard/reflection/ReflectionTest.java
index fb1be42..ec988a6 100644
--- a/src/test/java/com/android/tools/r8/compatproguard/reflection/ReflectionTest.java
+++ b/src/test/java/com/android/tools/r8/compatproguard/reflection/ReflectionTest.java
@@ -5,22 +5,21 @@
 package com.android.tools.r8.compatproguard.reflection;
 
 import static com.android.tools.r8.utils.codeinspector.Matchers.isPresentAndRenamed;
+import static org.hamcrest.CoreMatchers.equalTo;
 import static org.hamcrest.MatcherAssert.assertThat;
-import static org.junit.Assert.assertEquals;
 
 import com.android.tools.r8.KeepConstantArguments;
 import com.android.tools.r8.NeverInline;
-import com.android.tools.r8.R8Command;
 import com.android.tools.r8.TestBase;
-import com.android.tools.r8.ToolHelper;
-import com.android.tools.r8.origin.Origin;
-import com.android.tools.r8.utils.AndroidApp;
-import com.android.tools.r8.utils.codeinspector.CodeInspector;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
 import com.google.common.collect.ImmutableList;
 import java.lang.reflect.Method;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
 
 class A {
 
@@ -451,117 +450,175 @@
 @RunWith(Parameterized.class)
 public class ReflectionTest extends TestBase {
 
-  private Backend backend;
+  private static final String MAIN_ALL_BOXED_TYPES_EXPECTED_OUTPUT =
+      "true0a1234.45.5true0a1234.45.5";
+  private static final String MAIN_ALL_PRIMITIVE_TYPES_EXPECTED_OUTPUT =
+      "true0a1234.45.5true0a1234.45.5";
+  private static final String MAIN_NON_CONST_ARRAY_SIZE_EXPECTED_OUTPUT = "00";
+  private static final String MAIN_TEST_EXPECTED_OUTPUT = "00000123012340123012342345545467234767";
 
-  @Parameterized.Parameters(name = "Backend: {0}")
-  public static Backend[] data() {
-    return ToolHelper.getBackends();
-  }
+  @Parameter(0)
+  public TestParameters parameters;
 
-  public ReflectionTest(Backend backend) {
-    this.backend = backend;
+  @Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withAllRuntimesAndApiLevels().build();
   }
 
   @Test
-  public void test() throws Exception {
+  public void testJvmMainTest() throws Exception {
+    parameters.assumeJvmTestParameters();
+    testForJvm(parameters)
+        .addTestClasspath()
+        .run(parameters.getRuntime(), MainTest.class)
+        .assertSuccessWithOutput(MAIN_TEST_EXPECTED_OUTPUT);
+  }
+
+  @Test
+  public void testR8MainTest() throws Exception {
     Class<?> mainClass = MainTest.class;
-    AndroidApp output =
-        compileWithR8(
-            readClasses(A.class, mainClass), keepMainProguardConfiguration(mainClass), backend);
-    CodeInspector inspector = new CodeInspector(output);
-
-    assertThat(
-        inspector.clazz(A.class).method("void", "method0", ImmutableList.of()),
-        isPresentAndRenamed());
-    assertThat(
-        inspector.clazz(A.class).method("void", "method1", ImmutableList.of("java.lang.String")),
-        isPresentAndRenamed());
-    assertThat(
-        inspector
-            .clazz(A.class)
-            .method("void", "method2", ImmutableList.of("java.lang.String", "java.lang.String")),
-        isPresentAndRenamed());
-
-    assertEquals(runOnJava(mainClass), runOnVM(output, mainClass, backend));
-  }
-
-  @Test
-  public void testNonConstArraySize() throws Exception {
-    testForR8(backend)
-        .addProgramClasses(MainNonConstArraySize.class, A.class)
-        .addKeepMainRule(MainNonConstArraySize.class)
-        .enableConstantArgumentAnnotations()
-        .enableInliningAnnotations()
-        .run(MainNonConstArraySize.class)
+    testForR8(parameters.getBackend())
+        .addProgramClasses(mainClass, A.class)
+        .addKeepMainRule(mainClass)
+        .setMinApi(parameters)
+        .compile()
         .inspect(
             inspector -> {
               assertThat(
                   inspector.clazz(A.class).method("void", "method0", ImmutableList.of()),
                   isPresentAndRenamed());
+              assertThat(
+                  inspector
+                      .clazz(A.class)
+                      .method("void", "method1", ImmutableList.of("java.lang.String")),
+                  isPresentAndRenamed());
+              assertThat(
+                  inspector
+                      .clazz(A.class)
+                      .method(
+                          "void",
+                          "method2",
+                          ImmutableList.of("java.lang.String", "java.lang.String")),
+                  isPresentAndRenamed());
             })
+        .run(parameters.getRuntime(), mainClass)
+        .assertSuccessWithOutput(MAIN_TEST_EXPECTED_OUTPUT);
+  }
+
+  @Test
+  public void testJvmMainNonConstArraySize() throws Exception {
+    parameters.assumeJvmTestParameters();
+    testForJvm(parameters)
+        .addTestClasspath()
+        .run(parameters.getRuntime(), MainNonConstArraySize.class)
+        .assertSuccessWithOutput(MAIN_NON_CONST_ARRAY_SIZE_EXPECTED_OUTPUT);
+  }
+
+  @Test
+  public void testR8MainNonConstArraySize() throws Exception {
+    Class<?> mainClass = MainNonConstArraySize.class;
+    testForR8(parameters.getBackend())
+        .addProgramClasses(mainClass, A.class)
+        .addKeepMainRule(mainClass)
+        .enableConstantArgumentAnnotations()
+        .enableInliningAnnotations()
+        .setMinApi(parameters)
+        .compile()
+        .inspect(
+            inspector ->
+                assertThat(
+                    inspector.clazz(A.class).method("void", "method0", ImmutableList.of()),
+                    isPresentAndRenamed()))
+        .run(parameters.getRuntime(), mainClass)
         // The reference run on the Java VM will succeed, whereas the run on the R8 output will fail
         // as in this test we fail to recognize the reflective call. To compare the output of the
         // successful reference run append "java.lang.NoSuchMethodException" to it.
         .assertSuccessWithOutput(
-            runOnJava(MainNonConstArraySize.class) + "java.lang.NoSuchMethodException");
+            MAIN_NON_CONST_ARRAY_SIZE_EXPECTED_OUTPUT + "java.lang.NoSuchMethodException");
   }
 
   @Test
-  public void testPhiValue() throws Exception {
+  public void testJvmPhiValue() throws Exception {
+    parameters.assumeJvmTestParameters();
+    testForJvm(parameters)
+        .addTestClasspath()
+        .run(parameters.getRuntime(), MainPhiValue.class)
+        .assertFailureWithErrorThatThrows(Exception.class)
+        .assertStdoutMatches(equalTo("010"));
+  }
+
+  @Test
+  public void testR8PhiValue() throws Exception {
     Class<?> mainClass = MainPhiValue.class;
-    R8Command.Builder builder =
-        ToolHelper.prepareR8CommandBuilder(
-                readClasses(A.class, mainClass, NeverInline.class), emptyConsumer(backend))
-            .addLibraryFiles(runtimeJar(backend));
-    builder.addProguardConfiguration(
-        ImmutableList.of(keepMainProguardConfigurationWithInliningAnnotation(mainClass)),
-        Origin.unknown());
-    ToolHelper.allowTestProguardOptions(builder);
-    AndroidApp output =
-        ToolHelper.runR8(builder.build(), o -> o.inlinerOptions().enableInlining = false);
-
-    runOnVM(output, mainClass, backend);
+    testForR8(parameters.getBackend())
+        .addProgramClasses(mainClass, A.class)
+        .addKeepMainRule(mainClass)
+        .enableInliningAnnotations()
+        .setMinApi(parameters)
+        .compile()
+        .run(parameters.getRuntime(), mainClass)
+        .assertSuccessWithOutput("01");
   }
 
   @Test
-  public void testAllPrimitiveTypes() throws Exception {
+  public void testJvmAllPrimitiveTypes() throws Exception {
+    parameters.assumeJvmTestParameters();
+    testForJvm(parameters)
+        .addTestClasspath()
+        .run(parameters.getRuntime(), MainAllPrimitiveTypes.class)
+        .assertSuccessWithOutput(MAIN_ALL_PRIMITIVE_TYPES_EXPECTED_OUTPUT);
+  }
+
+  @Test
+  public void testR8AllPrimitiveTypes() throws Exception {
     Class<?> mainClass = MainAllPrimitiveTypes.class;
-    AndroidApp output =
-        compileWithR8(
-            readClasses(AllPrimitiveTypes.class, mainClass),
-            keepMainProguardConfiguration(mainClass),
-            backend);
-
-    new CodeInspector(output)
-        .clazz(AllPrimitiveTypes.class)
-        .forAllMethods(
-            m -> {
-              if (!m.isInstanceInitializer()) {
-                assertThat(m, isPresentAndRenamed());
-              }
-            });
-
-    assertEquals(runOnJava(mainClass), runOnVM(output, mainClass, backend));
+    testForR8(parameters.getBackend())
+        .addProgramClasses(mainClass, AllPrimitiveTypes.class)
+        .addKeepMainRule(mainClass)
+        .setMinApi(parameters)
+        .compile()
+        .inspect(
+            inspector ->
+                inspector
+                    .clazz(AllPrimitiveTypes.class)
+                    .forAllMethods(
+                        m -> {
+                          if (!m.isInstanceInitializer()) {
+                            assertThat(m, isPresentAndRenamed());
+                          }
+                        }))
+        .run(parameters.getRuntime(), mainClass)
+        .assertSuccessWithOutput(MAIN_ALL_PRIMITIVE_TYPES_EXPECTED_OUTPUT);
   }
 
   @Test
-  public void testAllBoxedTypes() throws Exception {
+  public void testJvmAllBoxedTypes() throws Exception {
+    parameters.assumeJvmTestParameters();
+    testForJvm(parameters)
+        .addTestClasspath()
+        .run(parameters.getRuntime(), MainAllBoxedTypes.class)
+        .assertSuccessWithOutput(MAIN_ALL_BOXED_TYPES_EXPECTED_OUTPUT);
+  }
+
+  @Test
+  public void testR8AllBoxedTypes() throws Exception {
     Class<?> mainClass = MainAllBoxedTypes.class;
-    AndroidApp output =
-        compileWithR8(
-            readClasses(AllBoxedTypes.class, mainClass),
-            keepMainProguardConfiguration(mainClass),
-            backend);
-
-    new CodeInspector(output)
-        .clazz(AllBoxedTypes.class)
-        .forAllMethods(
-            m -> {
-              if (!m.isInstanceInitializer()) {
-                assertThat(m, isPresentAndRenamed());
-              }
-            });
-
-    assertEquals(runOnJava(mainClass), runOnVM(output, mainClass, backend));
+    testForR8(parameters.getBackend())
+        .addProgramClasses(mainClass, AllBoxedTypes.class)
+        .addKeepMainRule(mainClass)
+        .setMinApi(parameters)
+        .compile()
+        .inspect(
+            inspector ->
+                inspector
+                    .clazz(AllBoxedTypes.class)
+                    .forAllMethods(
+                        m -> {
+                          if (!m.isInstanceInitializer()) {
+                            assertThat(m, isPresentAndRenamed());
+                          }
+                        }))
+        .run(parameters.getRuntime(), mainClass)
+        .assertSuccessWithOutput(MAIN_ALL_BOXED_TYPES_EXPECTED_OUTPUT);
   }
 }
diff --git a/src/test/java/com/android/tools/r8/d8/IncompatiblePrimitiveTypesTest.java b/src/test/java/com/android/tools/r8/d8/IncompatiblePrimitiveTypesTest.java
index d34c9b2..16b916b 100644
--- a/src/test/java/com/android/tools/r8/d8/IncompatiblePrimitiveTypesTest.java
+++ b/src/test/java/com/android/tools/r8/d8/IncompatiblePrimitiveTypesTest.java
@@ -23,6 +23,7 @@
 import org.junit.rules.TemporaryFolder;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
 import org.junit.runners.Parameterized.Parameters;
 
 @RunWith(Parameterized.class)
@@ -36,14 +37,11 @@
 
   @Parameters(name = "{0}")
   public static TestParametersCollection data() {
-    return getTestParameters().withAllRuntimes().withAllApiLevels().build();
+    return getTestParameters().withAllRuntimesAndApiLevels().build();
   }
 
-  final TestParameters parameters;
-
-  public IncompatiblePrimitiveTypesTest(TestParameters parameters) {
-    this.parameters = parameters;
-  }
+  @Parameter(0)
+  public TestParameters parameters;
 
   @BeforeClass
   public static void setup() throws Exception {
@@ -71,14 +69,17 @@
   }
 
   @Test
-  public void test() throws Exception {
-    if (parameters.isCfRuntime()) {
-      testForJvm()
-          .addClasspath(inputJar)
-          .run(parameters.getRuntime(), "TestClass")
-          .assertSuccessWithOutput(expectedOutput);
-      return;
-    }
+  public void testJvm() throws Exception {
+    parameters.assumeJvmTestParameters();
+    testForJvm(parameters)
+        .addClasspath(inputJar)
+        .run(parameters.getRuntime(), "TestClass")
+        .assertSuccessWithOutput(expectedOutput);
+  }
+
+  @Test
+  public void testD8() throws Exception {
+    parameters.assumeDexRuntime();
     TestRunResult<?> d8Result =
         testForD8()
             .addProgramFiles(inputJar)
diff --git a/src/test/java/com/android/tools/r8/dagger/DaggerBasicNotSingletonUsingBindsTest.java b/src/test/java/com/android/tools/r8/dagger/DaggerBasicNotSingletonUsingBindsTest.java
index 885ac9b..f0bc1e5 100644
--- a/src/test/java/com/android/tools/r8/dagger/DaggerBasicNotSingletonUsingBindsTest.java
+++ b/src/test/java/com/android/tools/r8/dagger/DaggerBasicNotSingletonUsingBindsTest.java
@@ -49,8 +49,9 @@
 
   @Test
   public void testJvm() throws Exception {
-    assumeTrue(parameters.isCfRuntime());
-    testForJvm()
+    parameters.assumeJvmTestParameters();
+    assumeTrue(target.equals(javacTargets.get(0)));
+    testForJvm(parameters)
         .addProgramFiles(getProgramFiles(target))
         .run(parameters.getRuntime(), MAIN_CLASS)
         .assertSuccessWithOutputLines(EXPECTED_OUTPUT);
@@ -58,8 +59,8 @@
 
   @Test
   public void testD8() throws Exception {
-    assumeTrue(parameters.isDexRuntime());
-    testForD8(parameters.getBackend())
+    parameters.assumeDexRuntime();
+    testForD8()
         .addProgramFiles(getProgramFiles(target))
         .setMinApi(parameters)
         .run(parameters.getRuntime(), MAIN_CLASS)
diff --git a/src/test/java/com/android/tools/r8/dagger/DaggerBasicNotSingletonUsingProvidesTest.java b/src/test/java/com/android/tools/r8/dagger/DaggerBasicNotSingletonUsingProvidesTest.java
index bd932c1..4b87b71 100644
--- a/src/test/java/com/android/tools/r8/dagger/DaggerBasicNotSingletonUsingProvidesTest.java
+++ b/src/test/java/com/android/tools/r8/dagger/DaggerBasicNotSingletonUsingProvidesTest.java
@@ -49,8 +49,9 @@
 
   @Test
   public void testJvm() throws Exception {
-    assumeTrue(parameters.isCfRuntime());
-    testForJvm()
+    parameters.assumeJvmTestParameters();
+    assumeTrue(target.equals(javacTargets.get(0)));
+    testForJvm(parameters)
         .addProgramFiles(getProgramFiles(target))
         .run(parameters.getRuntime(), MAIN_CLASS)
         .assertSuccessWithOutputLines(EXPECTED_OUTPUT);
@@ -58,8 +59,8 @@
 
   @Test
   public void testD8() throws Exception {
-    assumeTrue(parameters.isDexRuntime());
-    testForD8(parameters.getBackend())
+    parameters.assumeDexRuntime();
+    testForD8()
         .addProgramFiles(getProgramFiles(target))
         .setMinApi(parameters)
         .run(parameters.getRuntime(), MAIN_CLASS)
diff --git a/src/test/java/com/android/tools/r8/dagger/DaggerBasicSingletonUsingBindsTest.java b/src/test/java/com/android/tools/r8/dagger/DaggerBasicSingletonUsingBindsTest.java
index d339df2..742b463 100644
--- a/src/test/java/com/android/tools/r8/dagger/DaggerBasicSingletonUsingBindsTest.java
+++ b/src/test/java/com/android/tools/r8/dagger/DaggerBasicSingletonUsingBindsTest.java
@@ -52,8 +52,9 @@
 
   @Test
   public void testJvm() throws Exception {
-    assumeTrue(parameters.isCfRuntime());
-    testForJvm()
+    parameters.assumeJvmTestParameters();
+    assumeTrue(target.equals(javacTargets.get(0)));
+    testForJvm(parameters)
         .addProgramFiles(getProgramFiles(target))
         .run(parameters.getRuntime(), MAIN_CLASS)
         .assertSuccessWithOutputLines(EXPECTED_OUTPUT);
@@ -61,8 +62,8 @@
 
   @Test
   public void testD8() throws Exception {
-    assumeTrue(parameters.isDexRuntime());
-    testForD8(parameters.getBackend())
+    parameters.assumeDexRuntime();
+    testForD8()
         .addProgramFiles(getProgramFiles(target))
         .setMinApi(parameters)
         .run(parameters.getRuntime(), MAIN_CLASS)
diff --git a/src/test/java/com/android/tools/r8/dagger/DaggerBasicSingletonUsingProvidesTest.java b/src/test/java/com/android/tools/r8/dagger/DaggerBasicSingletonUsingProvidesTest.java
index 74d0197..4a3efd7 100644
--- a/src/test/java/com/android/tools/r8/dagger/DaggerBasicSingletonUsingProvidesTest.java
+++ b/src/test/java/com/android/tools/r8/dagger/DaggerBasicSingletonUsingProvidesTest.java
@@ -68,8 +68,9 @@
 
   @Test
   public void testJvm() throws Exception {
-    assumeTrue(parameters.isCfRuntime());
-    testForJvm()
+    parameters.assumeJvmTestParameters();
+    assumeTrue(target.equals(javacTargets.get(0)));
+    testForJvm(parameters)
         .addProgramFiles(getProgramFiles(target))
         .run(parameters.getRuntime(), MAIN_CLASS)
         .assertSuccessWithOutputLines(EXPECTED_OUTPUT);
@@ -77,8 +78,8 @@
 
   @Test
   public void testD8() throws Exception {
-    assumeTrue(parameters.isDexRuntime());
-    testForD8(parameters.getBackend())
+    parameters.assumeDexRuntime();
+    testForD8()
         .addProgramFiles(getProgramFiles(target))
         .setMinApi(parameters)
         .run(parameters.getRuntime(), MAIN_CLASS)
diff --git a/src/test/java/com/android/tools/r8/debug/JvmSyntheticTestRunner.java b/src/test/java/com/android/tools/r8/debug/JvmSyntheticTestRunner.java
index 0600584..b4841d6 100644
--- a/src/test/java/com/android/tools/r8/debug/JvmSyntheticTestRunner.java
+++ b/src/test/java/com/android/tools/r8/debug/JvmSyntheticTestRunner.java
@@ -10,6 +10,7 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
 import org.junit.runners.Parameterized.Parameters;
 
 @RunWith(Parameterized.class)
@@ -22,15 +23,12 @@
     return getTestParameters().withCfRuntimes().build();
   }
 
-  private TestParameters parameters;
-
-  public JvmSyntheticTestRunner(TestParameters parameters) {
-    this.parameters = parameters;
-  }
+  @Parameter(0)
+  public TestParameters parameters;
 
   @Test
   public void testStacktrace() throws Throwable {
-    testForJvm()
+    testForJvm(parameters)
         .addProgramClasses(A.class, CLASS)
         .run(parameters.getRuntime(), CLASS)
         .assertSuccessWithOutputThatMatches(
diff --git a/src/test/java/com/android/tools/r8/debug/LambdaOuterContextTestRunner.java b/src/test/java/com/android/tools/r8/debug/LambdaOuterContextTestRunner.java
index 1635252..d6b8dc4 100644
--- a/src/test/java/com/android/tools/r8/debug/LambdaOuterContextTestRunner.java
+++ b/src/test/java/com/android/tools/r8/debug/LambdaOuterContextTestRunner.java
@@ -4,17 +4,16 @@
 package com.android.tools.r8.debug;
 
 import static com.android.tools.r8.references.Reference.methodFromMethod;
-import static org.junit.Assume.assumeTrue;
 
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.TestParametersCollection;
 import com.android.tools.r8.debug.LambdaOuterContextTest.Converter;
-import com.android.tools.r8.utils.AndroidApiLevel;
 import com.android.tools.r8.utils.StringUtils;
 import org.apache.harmony.jpda.tests.framework.jdwp.Value;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
 import org.junit.runners.Parameterized.Parameters;
 
 @RunWith(Parameterized.class)
@@ -25,19 +24,20 @@
 
   @Parameters(name = "{0}")
   public static TestParametersCollection data() {
-    return getTestParameters().withAllRuntimes().build();
+    return getTestParameters()
+        .withAllRuntimes()
+        .withMinimumApiLevel()
+        .enableApiLevelsForCf()
+        .build();
   }
 
-  private final TestParameters parameters;
-
-  public LambdaOuterContextTestRunner(TestParameters parameters) {
-    this.parameters = parameters;
-  }
+  @Parameter(0)
+  public TestParameters parameters;
 
   @Test
   public void testJvm() throws Throwable {
-    assumeTrue(parameters.isCfRuntime());
-    testForJvm()
+    parameters.assumeJvmTestParameters();
+    testForJvm(parameters)
         .addProgramClassesAndInnerClasses(CLASS)
         .run(parameters.getRuntime(), CLASS)
         .assertSuccessWithOutput(EXPECTED)
@@ -48,7 +48,7 @@
   public void testD8() throws Throwable {
     testForD8(parameters.getBackend())
         .addProgramClassesAndInnerClasses(CLASS)
-        .setMinApi(AndroidApiLevel.B)
+        .setMinApi(parameters)
         .run(parameters.getRuntime(), CLASS)
         .assertSuccessWithOutput(EXPECTED)
         .debugger(this::runDebugger);
@@ -61,7 +61,7 @@
         .debug()
         .addDontObfuscate()
         .noTreeShaking()
-        .setMinApi(AndroidApiLevel.B)
+        .setMinApi(parameters)
         .run(parameters.getRuntime(), CLASS)
         .assertSuccessWithOutput(EXPECTED)
         .debugger(this::runDebugger);
diff --git a/src/test/java/com/android/tools/r8/debug/UninitializedInitialLocalsTest.java b/src/test/java/com/android/tools/r8/debug/UninitializedInitialLocalsTest.java
index 03c591f..6b15c99 100644
--- a/src/test/java/com/android/tools/r8/debug/UninitializedInitialLocalsTest.java
+++ b/src/test/java/com/android/tools/r8/debug/UninitializedInitialLocalsTest.java
@@ -9,6 +9,8 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
 import org.objectweb.asm.ClassWriter;
 import org.objectweb.asm.Label;
 import org.objectweb.asm.MethodVisitor;
@@ -17,31 +19,31 @@
 @RunWith(Parameterized.class)
 public class UninitializedInitialLocalsTest extends TestBase implements Opcodes {
 
-  private final TestParameters parameters;
+  @Parameter(0)
+  public TestParameters parameters;
 
-  @Parameterized.Parameters(name = "{0}")
+  @Parameters(name = "{0}")
   public static TestParametersCollection data() {
-    return getTestParameters().withAllRuntimes().withAllApiLevels().build();
+    return getTestParameters().withAllRuntimesAndApiLevels().build();
   }
 
-  public UninitializedInitialLocalsTest(TestParameters parameters) {
-    this.parameters = parameters;
+  @Test
+  public void testJvm() throws Exception {
+    parameters.assumeJvmTestParameters();
+    testForJvm(parameters)
+        .addProgramClassFileData(dump())
+        .run(parameters.getRuntime(), "Test")
+        .assertSuccessWithOutputLines("42");
   }
 
   @Test
   public void test() throws Exception {
-    if (parameters.isCfRuntime()) {
-      testForJvm()
-          .addProgramClassFileData(dump())
-          .run(parameters.getRuntime(), "Test")
-          .assertSuccessWithOutputLines("42");
-    } else {
-      testForD8()
-          .addProgramClassFileData(dump())
-          .setMinApi(parameters)
-          .run(parameters.getRuntime(), "Test")
-          .assertSuccessWithOutputLines("42");
-    }
+    parameters.assumeDexRuntime();
+    testForD8()
+        .addProgramClassFileData(dump())
+        .setMinApi(parameters)
+        .run(parameters.getRuntime(), "Test")
+        .assertSuccessWithOutputLines("42");
   }
 
   public static byte[] dump() {
diff --git a/src/test/java/com/android/tools/r8/debuginfo/AsmZeroLineEntryRegressionTest.java b/src/test/java/com/android/tools/r8/debuginfo/AsmZeroLineEntryRegressionTest.java
index 018c618..acbe0e5 100644
--- a/src/test/java/com/android/tools/r8/debuginfo/AsmZeroLineEntryRegressionTest.java
+++ b/src/test/java/com/android/tools/r8/debuginfo/AsmZeroLineEntryRegressionTest.java
@@ -42,7 +42,7 @@
    */
   @Test
   public void testReference() throws Exception {
-    testForJvm()
+    testForJvm(parameters)
         .addProgramClassFileData(getClassWithZeroLineEntry())
         .run(parameters.getRuntime(), TestClass.class)
         .assertFailureWithErrorThatThrows(RuntimeException.class)
@@ -56,7 +56,7 @@
    */
   @Test
   public void testAsmIdentity() throws Exception {
-    testForJvm()
+    testForJvm(parameters)
         .addProgramClassFileData(
             getClassAfterAsmIdentity(
                 getClassWithZeroLineEntry(), Reference.classFromClass(TestClass.class)))
diff --git a/src/test/java/com/android/tools/r8/debuginfo/SingleLineInfoInlineRemoveTest.java b/src/test/java/com/android/tools/r8/debuginfo/SingleLineInfoInlineRemoveTest.java
index 07ef08c..a4abfb2 100644
--- a/src/test/java/com/android/tools/r8/debuginfo/SingleLineInfoInlineRemoveTest.java
+++ b/src/test/java/com/android/tools/r8/debuginfo/SingleLineInfoInlineRemoveTest.java
@@ -18,33 +18,31 @@
 import com.android.tools.r8.TestRuntime.CfRuntime;
 import com.android.tools.r8.naming.retrace.StackTrace;
 import com.android.tools.r8.utils.codeinspector.ClassSubject;
-import org.junit.Before;
+import org.junit.BeforeClass;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
 import org.junit.runners.Parameterized.Parameters;
 
 @RunWith(Parameterized.class)
 public class SingleLineInfoInlineRemoveTest extends TestBase {
 
-  private final TestParameters parameters;
+  private static StackTrace expectedStackTrace;
+
+  @Parameter(0)
+  public TestParameters parameters;
 
   @Parameters(name = "{0}")
   public static TestParametersCollection data() {
     return getTestParameters().withAllRuntimesAndApiLevels().build();
   }
 
-  public SingleLineInfoInlineRemoveTest(TestParameters parameters) {
-    this.parameters = parameters;
-  }
-
-  public StackTrace expectedStackTrace;
-
-  @Before
-  public void setup() throws Exception {
+  @BeforeClass
+  public static void setup() throws Exception {
     // Get the expected stack trace by running on the JVM.
     expectedStackTrace =
-        testForJvm()
+        testForJvm(getStaticTemp())
             .addTestClasspath()
             .run(CfRuntime.getSystemRuntime(), Main.class)
             .assertFailureWithErrorThatThrows(NullPointerException.class)
diff --git a/src/test/java/com/android/tools/r8/debuginfo/SingleLineInfoMultipleCallsRemoveTest.java b/src/test/java/com/android/tools/r8/debuginfo/SingleLineInfoMultipleCallsRemoveTest.java
index 6ea4a91..256336c 100644
--- a/src/test/java/com/android/tools/r8/debuginfo/SingleLineInfoMultipleCallsRemoveTest.java
+++ b/src/test/java/com/android/tools/r8/debuginfo/SingleLineInfoMultipleCallsRemoveTest.java
@@ -14,33 +14,31 @@
 import com.android.tools.r8.TestParametersCollection;
 import com.android.tools.r8.TestRuntime.CfRuntime;
 import com.android.tools.r8.naming.retrace.StackTrace;
-import org.junit.Before;
+import org.junit.BeforeClass;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
 import org.junit.runners.Parameterized.Parameters;
 
 @RunWith(Parameterized.class)
 public class SingleLineInfoMultipleCallsRemoveTest extends TestBase {
 
-  private final TestParameters parameters;
+  private static StackTrace expectedStackTrace;
+
+  @Parameter(0)
+  public TestParameters parameters;
 
   @Parameters(name = "{0}")
   public static TestParametersCollection data() {
     return getTestParameters().withAllRuntimesAndApiLevels().build();
   }
 
-  public SingleLineInfoMultipleCallsRemoveTest(TestParameters parameters) {
-    this.parameters = parameters;
-  }
-
-  public StackTrace expectedStackTrace;
-
-  @Before
-  public void setup() throws Exception {
+  @BeforeClass
+  public static void setup() throws Exception {
     // Get the expected stack trace by running on the JVM.
     expectedStackTrace =
-        testForJvm()
+        testForJvm(getStaticTemp())
             .addTestClasspath()
             .run(CfRuntime.getSystemRuntime(), Main.class)
             .assertFailureWithErrorThatThrows(NullPointerException.class)
diff --git a/src/test/java/com/android/tools/r8/debuginfo/SingleLineInfoMultipleInlineTest.java b/src/test/java/com/android/tools/r8/debuginfo/SingleLineInfoMultipleInlineTest.java
index 562146f..e1815c6 100644
--- a/src/test/java/com/android/tools/r8/debuginfo/SingleLineInfoMultipleInlineTest.java
+++ b/src/test/java/com/android/tools/r8/debuginfo/SingleLineInfoMultipleInlineTest.java
@@ -18,33 +18,31 @@
 import com.android.tools.r8.TestRuntime.CfRuntime;
 import com.android.tools.r8.naming.retrace.StackTrace;
 import com.android.tools.r8.utils.codeinspector.ClassSubject;
-import org.junit.Before;
+import org.junit.BeforeClass;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
 import org.junit.runners.Parameterized.Parameters;
 
 @RunWith(Parameterized.class)
 public class SingleLineInfoMultipleInlineTest extends TestBase {
 
-  private final TestParameters parameters;
+  private static StackTrace expectedStackTrace;
+
+  @Parameter(0)
+  public TestParameters parameters;
 
   @Parameters(name = "{0}")
   public static TestParametersCollection data() {
     return getTestParameters().withAllRuntimesAndApiLevels().build();
   }
 
-  public SingleLineInfoMultipleInlineTest(TestParameters parameters) {
-    this.parameters = parameters;
-  }
-
-  public StackTrace expectedStackTrace;
-
-  @Before
-  public void setup() throws Exception {
+  @BeforeClass
+  public static void setup() throws Exception {
     // Get the expected stack trace by running on the JVM.
     expectedStackTrace =
-        testForJvm()
+        testForJvm(getStaticTemp())
             .addTestClasspath()
             .run(CfRuntime.getSystemRuntime(), Main.class)
             .assertFailureWithErrorThatThrows(NullPointerException.class)
diff --git a/src/test/java/com/android/tools/r8/debuginfo/SingleLineInfoRemoveTest.java b/src/test/java/com/android/tools/r8/debuginfo/SingleLineInfoRemoveTest.java
index 66e65a0..0fd4142 100644
--- a/src/test/java/com/android/tools/r8/debuginfo/SingleLineInfoRemoveTest.java
+++ b/src/test/java/com/android/tools/r8/debuginfo/SingleLineInfoRemoveTest.java
@@ -21,17 +21,23 @@
 import com.android.tools.r8.utils.codeinspector.ClassSubject;
 import java.util.List;
 import org.hamcrest.CoreMatchers;
-import org.junit.Before;
+import org.junit.BeforeClass;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
 import org.junit.runners.Parameterized.Parameters;
 
 @RunWith(Parameterized.class)
 public class SingleLineInfoRemoveTest extends TestBase {
 
-  private final TestParameters parameters;
-  private final boolean customSourceFile;
+  private static StackTrace expectedStackTrace;
+
+  @Parameter(0)
+  public TestParameters parameters;
+
+  @Parameter(1)
+  public boolean customSourceFile;
 
   @Parameters(name = "{0}, custom-source-file:{1}")
   public static List<Object[]> data() {
@@ -39,18 +45,11 @@
         getTestParameters().withAllRuntimesAndApiLevels().build(), BooleanUtils.values());
   }
 
-  public SingleLineInfoRemoveTest(TestParameters parameters, boolean customSourceFile) {
-    this.parameters = parameters;
-    this.customSourceFile = customSourceFile;
-  }
-
-  public StackTrace expectedStackTrace;
-
-  @Before
-  public void setup() throws Exception {
+  @BeforeClass
+  public static void setup() throws Exception {
     // Get the expected stack trace by running on the JVM.
     expectedStackTrace =
-        testForJvm()
+        testForJvm(getStaticTemp())
             .addTestClasspath()
             .run(CfRuntime.getSystemRuntime(), Main.class)
             .assertFailure()
diff --git a/src/test/java/com/android/tools/r8/desugar/BackportedMethodMergeTest.java b/src/test/java/com/android/tools/r8/desugar/BackportedMethodMergeTest.java
index f71139f..5dacf87 100644
--- a/src/test/java/com/android/tools/r8/desugar/BackportedMethodMergeTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/BackportedMethodMergeTest.java
@@ -4,50 +4,80 @@
 
 package com.android.tools.r8.desugar;
 
-import com.android.tools.r8.CompilationFailedException;
 import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
 import com.android.tools.r8.graph.ClassAccessFlags;
 import com.android.tools.r8.transformers.ClassTransformer;
 import com.android.tools.r8.utils.AndroidApiLevel;
-import java.io.IOException;
+import com.android.tools.r8.utils.StringUtils;
 import java.nio.file.Path;
-import java.util.concurrent.ExecutionException;
 import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
 
+@RunWith(Parameterized.class)
 public class BackportedMethodMergeTest extends TestBase {
+
+  private static final String MERGE_RUN_EXPECTED_OUTPUT =
+      StringUtils.lines("42", "1078263808", "43", "1078296576");
+  private static final String MERGE_RUN_WITH_OLD_BACKPORTED_PREFIX_EXPECTED_OUTPUT =
+      StringUtils.lines("foobar");
+
+  @Parameter(0)
+  public TestParameters parameters;
+
+  @Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters()
+        .withAllRuntimes()
+        .withApiLevelsEndingAtIncluding(AndroidApiLevel.L)
+        .build();
+  }
+
+  @Test
+  public void testJvm() throws Exception {
+    parameters.assumeJvmTestParameters();
+    testForJvm(parameters)
+        .addTestClasspath()
+        .run(parameters.getRuntime(), MergeRun.class)
+        .assertSuccessWithOutput(MERGE_RUN_EXPECTED_OUTPUT);
+  }
+
   @Test
   public void testD8Merge() throws Exception {
-    String jvmOutput = testForJvm()
-        .addTestClasspath()
-        .run(MergeRun.class).getStdOut();
+    parameters.assumeDexRuntime();
+
     // See b/123242448
     Path zip1 = temp.newFile("first.zip").toPath();
     Path zip2 = temp.newFile("second.zip").toPath();
-
     testForD8()
-        .setMinApi(AndroidApiLevel.L)
+        .setMinApi(parameters)
         .addProgramClasses(MergeRun.class, MergeInputB.class)
         .compile()
         .assertNoMessages()
         .writeToZip(zip1);
     testForD8()
-        .setMinApi(AndroidApiLevel.L)
+        .setMinApi(parameters)
         .addProgramClasses(MergeInputA.class)
         .compile()
         .assertNoMessages()
         .writeToZip(zip2);
     testForD8()
         .addProgramFiles(zip1, zip2)
-        .setMinApi(AndroidApiLevel.L)
+        .setMinApi(parameters)
         .compile()
         .assertNoMessages()
-        .run(MergeRun.class)
-        .assertSuccessWithOutput(jvmOutput);
+        .run(parameters.getRuntime(), MergeRun.class)
+        .assertSuccessWithOutput(MERGE_RUN_EXPECTED_OUTPUT);
   }
 
   @Test
-  public void testMergeOldPrefix()
-      throws IOException, CompilationFailedException, ExecutionException {
+  public void testMergeOldPrefix() throws Exception {
+    parameters.assumeDexRuntime();
+
     byte[] transform = transformer($r8$java8methods$utility_MergeInputWithOldBackportedPrefix.class)
         .addClassTransformer(new ClassTransformer() {
           @Override
@@ -63,25 +93,25 @@
     Path zip1 = temp.newFile("first.zip").toPath();
     Path zip2 = temp.newFile("second.zip").toPath();
     testForD8()
-        .setMinApi(AndroidApiLevel.L)
+        .setMinApi(parameters)
         .addProgramClasses(MergeRunWithOldBackportedPrefix.class)
         .addProgramClassFileData(transform)
         .compile()
         .assertNoMessages()
         .writeToZip(zip1);
     testForD8()
-        .setMinApi(AndroidApiLevel.L)
+        .setMinApi(parameters)
         .addProgramClassFileData(transform)
         .compile()
         .assertNoMessages()
         .writeToZip(zip2);
     testForD8()
         .addProgramFiles(zip1, zip2)
-        .setMinApi(AndroidApiLevel.L)
+        .setMinApi(parameters)
         .compile()
         .assertNoMessages()
-        .run(MergeRunWithOldBackportedPrefix.class)
-        .assertSuccessWithOutputLines("foobar");
+        .run(parameters.getRuntime(), MergeRunWithOldBackportedPrefix.class)
+        .assertSuccessWithOutput(MERGE_RUN_WITH_OLD_BACKPORTED_PREFIX_EXPECTED_OUTPUT);
   }
 
 
diff --git a/src/test/java/com/android/tools/r8/desugar/DefaultLambdaMethodWithPrivateSuperClassTest.java b/src/test/java/com/android/tools/r8/desugar/DefaultLambdaMethodWithPrivateSuperClassTest.java
index de74f3f..1156c2d 100644
--- a/src/test/java/com/android/tools/r8/desugar/DefaultLambdaMethodWithPrivateSuperClassTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/DefaultLambdaMethodWithPrivateSuperClassTest.java
@@ -4,7 +4,6 @@
 
 package com.android.tools.r8.desugar;
 
-import static org.junit.Assume.assumeTrue;
 
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
@@ -35,8 +34,8 @@
 
   @Test
   public void testJvm() throws Exception {
-    assumeTrue(parameters.isCfRuntime());
-    testForJvm()
+    parameters.assumeJvmTestParameters();
+    testForJvm(parameters)
         .addInnerClasses(getClass())
         .run(parameters.getRuntime(), Main.class)
         .assertFailureWithErrorThatThrows(IllegalAccessError.class);
diff --git a/src/test/java/com/android/tools/r8/desugar/DefaultLambdaMethodWithPublicSuperClassTest.java b/src/test/java/com/android/tools/r8/desugar/DefaultLambdaMethodWithPublicSuperClassTest.java
index 317b949..7eeecf9 100644
--- a/src/test/java/com/android/tools/r8/desugar/DefaultLambdaMethodWithPublicSuperClassTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/DefaultLambdaMethodWithPublicSuperClassTest.java
@@ -4,7 +4,6 @@
 
 package com.android.tools.r8.desugar;
 
-import static org.junit.Assume.assumeTrue;
 
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
@@ -31,8 +30,8 @@
 
   @Test
   public void testJvm() throws Exception {
-    assumeTrue(parameters.isCfRuntime());
-    testForJvm()
+    parameters.assumeJvmTestParameters();
+    testForJvm(parameters)
         .addInnerClasses(getClass())
         .run(parameters.getRuntime(), Main.class)
         .assertSuccessWithOutputLines(EXPECTED);
diff --git a/src/test/java/com/android/tools/r8/desugar/DefaultLambdaWithInvokeInterfaceTestRunner.java b/src/test/java/com/android/tools/r8/desugar/DefaultLambdaWithInvokeInterfaceTestRunner.java
index 0136d59..42e6975 100644
--- a/src/test/java/com/android/tools/r8/desugar/DefaultLambdaWithInvokeInterfaceTestRunner.java
+++ b/src/test/java/com/android/tools/r8/desugar/DefaultLambdaWithInvokeInterfaceTestRunner.java
@@ -8,6 +8,8 @@
 
 import com.android.tools.r8.D8TestCompileResult;
 import com.android.tools.r8.R8TestCompileResult;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
 import com.android.tools.r8.debug.DebugTestBase;
 import com.android.tools.r8.debug.DebugTestBase.JUnit3Wrapper.Command;
 import com.android.tools.r8.debug.DebugTestConfig;
@@ -18,27 +20,77 @@
 import com.google.common.collect.ImmutableList;
 import java.util.Collections;
 import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
 
+@RunWith(Parameterized.class)
 public class DefaultLambdaWithInvokeInterfaceTestRunner extends DebugTestBase {
 
-  final Class<?> CLASS = DefaultLambdaWithInvokeInterfaceTest.class;
-  final String EXPECTED = StringUtils.lines("stateful(hest)");
+  private final Class<?> CLASS = DefaultLambdaWithInvokeInterfaceTest.class;
+  private final String EXPECTED = StringUtils.lines("stateful(hest)");
+
+  @Parameter(0)
+  public TestParameters parameters;
+
+  @Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withAllRuntimes().withApiLevel(AndroidApiLevel.K).build();
+  }
 
   @Test
   public void testJvm() throws Exception {
-    testForJvm().addTestClasspath().run(CLASS).assertSuccessWithOutput(EXPECTED);
+    parameters.assumeJvmTestParameters();
+    testForJvm(parameters)
+        .addTestClasspath()
+        .run(parameters.getRuntime(), CLASS)
+        .assertSuccessWithOutput(EXPECTED);
+  }
+
+  @Test
+  public void testR8Cf() throws Throwable {
+    parameters.assumeCfRuntime();
+    R8TestCompileResult compileResult =
+        testForR8(Backend.CF)
+            .addProgramClassesAndInnerClasses(CLASS)
+            .addDontObfuscate()
+            .noTreeShaking()
+            .debug()
+            .compile();
+    compileResult
+        // TODO(b/123506120): Add .assertNoMessages()
+        .run(parameters.getRuntime(), CLASS)
+        .assertSuccessWithOutput(EXPECTED)
+        .inspect(inspector -> assertThat(inspector.clazz(CLASS), isPresent()));
+    runDebugger(compileResult.debugConfig());
+  }
+
+  @Test
+  public void testD8() throws Throwable {
+    parameters.assumeDexRuntime();
+    D8TestCompileResult compileResult =
+        testForD8().addProgramClassesAndInnerClasses(CLASS).setMinApi(parameters).compile();
+    compileResult
+        // TODO(b/123506120): Add .assertNoMessages()
+        .run(parameters.getRuntime(), CLASS)
+        .assertSuccessWithOutput(EXPECTED)
+        .inspect(inspector -> assertThat(inspector.clazz(CLASS), isPresent()));
+    runDebugger(compileResult.debugConfig());
   }
 
   private void runDebugger(DebugTestConfig config) throws Throwable {
     MethodReference main = Reference.methodFromMethod(CLASS.getMethod("main", String[].class));
-    Command checkThis = conditional((state) ->
-        state.isCfRuntime()
-            ? Collections.singletonList(checkLocal("this"))
-            : ImmutableList.of(
-                checkNoLocal("this"),
-                checkLocal("_this")));
+    Command checkThis =
+        conditional(
+            (state) ->
+                state.isCfRuntime()
+                    ? Collections.singletonList(checkLocal("this"))
+                    : ImmutableList.of(checkNoLocal("this"), checkLocal("_this")));
 
-    runDebugTest(config, CLASS,
+    runDebugTest(
+        config,
+        CLASS,
         breakpoint(main, 27),
         run(),
         checkLine(27),
@@ -54,35 +106,4 @@
         checkThis,
         run());
   }
-
-  @Test
-  public void testR8Cf() throws Throwable {
-    R8TestCompileResult compileResult =
-        testForR8(Backend.CF)
-            .addProgramClassesAndInnerClasses(CLASS)
-            .addDontObfuscate()
-            .noTreeShaking()
-            .debug()
-            .compile();
-    compileResult
-        // TODO(b/123506120): Add .assertNoMessages()
-        .run(CLASS)
-        .assertSuccessWithOutput(EXPECTED)
-        .inspect(inspector -> assertThat(inspector.clazz(CLASS), isPresent()));
-    runDebugger(compileResult.debugConfig());
-  }
-
-  @Test
-  public void testD8() throws Throwable {
-    D8TestCompileResult compileResult = testForD8()
-        .addProgramClassesAndInnerClasses(CLASS)
-        .setMinApi(AndroidApiLevel.K)
-        .compile();
-    compileResult
-        // TODO(b/123506120): Add .assertNoMessages()
-        .run(CLASS)
-        .assertSuccessWithOutput(EXPECTED)
-        .inspect(inspector -> assertThat(inspector.clazz(CLASS), isPresent()));
-    runDebugger(compileResult.debugConfig());
-  }
 }
diff --git a/src/test/java/com/android/tools/r8/desugar/DefaultLambdaWithSelfReferenceTestRunner.java b/src/test/java/com/android/tools/r8/desugar/DefaultLambdaWithSelfReferenceTestRunner.java
index 85b999a..ef56abd 100644
--- a/src/test/java/com/android/tools/r8/desugar/DefaultLambdaWithSelfReferenceTestRunner.java
+++ b/src/test/java/com/android/tools/r8/desugar/DefaultLambdaWithSelfReferenceTestRunner.java
@@ -89,8 +89,8 @@
 
   @Test
   public void testJvm() throws Throwable {
-    assumeTrue(parameters.isCfRuntime());
-    testForJvm()
+    parameters.assumeJvmTestParameters();
+    testForJvm(parameters)
         .addProgramClassesAndInnerClasses(CLASS)
         .run(parameters.getRuntime(), CLASS)
         .assertSuccessWithOutput(EXPECTED)
diff --git a/src/test/java/com/android/tools/r8/desugar/DefaultLambdaWithUnderscoreThisTestRunner.java b/src/test/java/com/android/tools/r8/desugar/DefaultLambdaWithUnderscoreThisTestRunner.java
index ce29093..b2b2fc8 100644
--- a/src/test/java/com/android/tools/r8/desugar/DefaultLambdaWithUnderscoreThisTestRunner.java
+++ b/src/test/java/com/android/tools/r8/desugar/DefaultLambdaWithUnderscoreThisTestRunner.java
@@ -84,8 +84,8 @@
 
   @Test
   public void testJvm() throws Throwable {
-    assumeTrue(parameters.isCfRuntime());
-    testForJvm()
+    parameters.assumeJvmTestParameters();
+    testForJvm(parameters)
         .addProgramClassesAndInnerClasses(CLASS)
         .run(parameters.getRuntime(), CLASS)
         .assertSuccessWithOutput(EXPECTED)
diff --git a/src/test/java/com/android/tools/r8/desugar/DesugarMissingTypeClassTest.java b/src/test/java/com/android/tools/r8/desugar/DesugarMissingTypeClassTest.java
index f852e5f..f96c345 100644
--- a/src/test/java/com/android/tools/r8/desugar/DesugarMissingTypeClassTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/DesugarMissingTypeClassTest.java
@@ -47,7 +47,7 @@
   @Test
   public void test() throws Exception {
     if (parameters.isCfRuntime()) {
-      testForJvm()
+      testForJvm(parameters)
           .addProgramClasses(TestClass.class, MyClass.class, MissingInterface.class)
           .run(parameters.getRuntime(), TestClass.class)
           .assertSuccessWithOutput(EXPECTED);
diff --git a/src/test/java/com/android/tools/r8/desugar/DesugarMissingTypeLambdaTest.java b/src/test/java/com/android/tools/r8/desugar/DesugarMissingTypeLambdaTest.java
index 25444c6..d0dea4f 100644
--- a/src/test/java/com/android/tools/r8/desugar/DesugarMissingTypeLambdaTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/DesugarMissingTypeLambdaTest.java
@@ -48,7 +48,7 @@
   @Test
   public void test() throws Exception {
     if (parameters.isCfRuntime()) {
-      testForJvm()
+      testForJvm(parameters)
           .addProgramClasses(TestClass.class, MissingInterface.class)
           .run(parameters.getRuntime(), TestClass.class)
           .assertSuccessWithOutput(EXPECTED);
diff --git a/src/test/java/com/android/tools/r8/desugar/DesugarMissingTypeStaticInvokeTest.java b/src/test/java/com/android/tools/r8/desugar/DesugarMissingTypeStaticInvokeTest.java
index d7cad40..ccf9f8f 100644
--- a/src/test/java/com/android/tools/r8/desugar/DesugarMissingTypeStaticInvokeTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/DesugarMissingTypeStaticInvokeTest.java
@@ -49,7 +49,7 @@
   @Test
   public void test() throws Exception {
     if (parameters.isCfRuntime()) {
-      testForJvm()
+      testForJvm(parameters)
           .addProgramClasses(TestClass.class, MissingInterface.class)
           .run(parameters.getRuntime(), TestClass.class)
           .assertSuccessWithOutput(EXPECTED);
diff --git a/src/test/java/com/android/tools/r8/desugar/DesugarToClassFile.java b/src/test/java/com/android/tools/r8/desugar/DesugarToClassFile.java
index d9365c5..a71d340 100644
--- a/src/test/java/com/android/tools/r8/desugar/DesugarToClassFile.java
+++ b/src/test/java/com/android/tools/r8/desugar/DesugarToClassFile.java
@@ -6,12 +6,12 @@
 
 import static org.junit.Assert.assertTrue;
 
+import com.android.tools.r8.D8TestCompileResult;
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.TestParametersCollection;
 import com.android.tools.r8.utils.codeinspector.CodeInspector;
 import com.android.tools.r8.utils.codeinspector.FoundClassSubject;
-import java.nio.file.Path;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
@@ -54,26 +54,24 @@
   @Test
   public void test() throws Exception {
     // Use D8 to desugar with Java classfile output.
-    Path jar =
+    D8TestCompileResult desugarCompileResult =
         testForD8(Backend.CF)
             .addInnerClasses(DesugarToClassFile.class)
             .setMinApi(parameters)
             .compile()
             .inspect(this::checkHasCompanionClassIfRequired)
-            .inspect(this::checkHasLambdaClass)
-            .writeToZip();
+            .inspect(this::checkHasLambdaClass);
 
     if (parameters.getRuntime().isCf()) {
       // Run on the JVM.
-      testForJvm()
-          .addProgramFiles(jar)
+      desugarCompileResult
           .run(parameters.getRuntime(), TestClass.class)
           .assertSuccessWithOutputLines("Hello, world!", "I::foo", "J::bar", "42");
     } else {
       assert parameters.getRuntime().isDex();
       // Convert to DEX without desugaring.
       testForD8()
-          .addProgramFiles(jar)
+          .addProgramFiles(desugarCompileResult.writeToZip())
           .setMinApi(parameters)
           .disableDesugaring()
           .run(parameters.getRuntime(), TestClass.class)
diff --git a/src/test/java/com/android/tools/r8/desugar/DesugarToClassFileDeprecatedAttribute.java b/src/test/java/com/android/tools/r8/desugar/DesugarToClassFileDeprecatedAttribute.java
index a2bdaef..efcc639 100644
--- a/src/test/java/com/android/tools/r8/desugar/DesugarToClassFileDeprecatedAttribute.java
+++ b/src/test/java/com/android/tools/r8/desugar/DesugarToClassFileDeprecatedAttribute.java
@@ -9,6 +9,7 @@
 import com.android.tools.r8.ByteDataView;
 import com.android.tools.r8.ClassFileConsumer;
 import com.android.tools.r8.ClassFileConsumer.ForwardingConsumer;
+import com.android.tools.r8.D8TestCompileResult;
 import com.android.tools.r8.DiagnosticsHandler;
 import com.android.tools.r8.R8FullTestBuilder;
 import com.android.tools.r8.TestBase;
@@ -17,10 +18,11 @@
 import com.android.tools.r8.ToolHelper;
 import com.android.tools.r8.utils.InternalOptions;
 import java.nio.file.Files;
-import java.nio.file.Path;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
 import org.objectweb.asm.ClassReader;
 import org.objectweb.asm.ClassVisitor;
 import org.objectweb.asm.FieldVisitor;
@@ -30,16 +32,13 @@
 @RunWith(Parameterized.class)
 public class DesugarToClassFileDeprecatedAttribute extends TestBase {
 
-  @Parameterized.Parameters(name = "{0}")
+  @Parameters(name = "{0}")
   public static TestParametersCollection data() {
     return getTestParameters().withAllRuntimes().withAllApiLevelsAlsoForCf().build();
   }
 
-  private final TestParameters parameters;
-
-  public DesugarToClassFileDeprecatedAttribute(TestParameters parameters) {
-    this.parameters = parameters;
-  }
+  @Parameter(0)
+  public TestParameters parameters;
 
   private boolean isDeprecated(int access) {
     return (access & Opcodes.ACC_DEPRECATED) == Opcodes.ACC_DEPRECATED;
@@ -85,7 +84,7 @@
         Files.readAllBytes(ToolHelper.getClassFileForTestClass(TestClass.class)));
 
     // Use D8 to desugar with Java classfile output.
-    Path jar =
+    D8TestCompileResult desugarCompileResult =
         testForD8(Backend.CF)
             .addProgramClasses(TestClass.class)
             .setMinApi(parameters)
@@ -97,20 +96,18 @@
                     checkDeprecatedAttributes(data.getBuffer());
                   }
                 })
-            .compile()
-            .writeToZip();
+            .compile();
 
     if (parameters.getRuntime().isCf()) {
       // Run on the JVM.
-      testForJvm()
-          .addProgramFiles(jar)
+      desugarCompileResult
           .run(parameters.getRuntime(), TestClass.class)
           .assertSuccessWithOutputLines("Hello, world!");
     } else {
       assert parameters.getRuntime().isDex();
       // Convert to DEX without desugaring.
       testForD8()
-          .addProgramFiles(jar)
+          .addProgramFiles(desugarCompileResult.writeToZip())
           .setMinApi(parameters)
           .disableDesugaring()
           .run(parameters.getRuntime(), TestClass.class)
diff --git a/src/test/java/com/android/tools/r8/desugar/DesugarToClassFileInputCfVersion.java b/src/test/java/com/android/tools/r8/desugar/DesugarToClassFileInputCfVersion.java
index 5f7b139..0b08b5a 100644
--- a/src/test/java/com/android/tools/r8/desugar/DesugarToClassFileInputCfVersion.java
+++ b/src/test/java/com/android/tools/r8/desugar/DesugarToClassFileInputCfVersion.java
@@ -11,14 +11,15 @@
 import static org.objectweb.asm.Opcodes.V1_8;
 import static org.objectweb.asm.Opcodes.V9;
 
+import com.android.tools.r8.D8TestCompileResult;
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
 import com.google.common.collect.ImmutableList;
-import java.nio.file.Path;
 import java.util.List;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
 import org.junit.runners.Parameterized.Parameters;
 
 @RunWith(Parameterized.class)
@@ -31,35 +32,31 @@
         ImmutableList.of(V1_4, V1_5, V1_6, V1_7, V1_8, V9));
   }
 
-  private final TestParameters parameters;
-  private final int cfVersion;
+  @Parameter(0)
+  public TestParameters parameters;
 
-  public DesugarToClassFileInputCfVersion(TestParameters parameters, int cfVersion) {
-    this.parameters = parameters;
-    this.cfVersion = cfVersion;
-  }
+  @Parameter(1)
+  public int cfVersion;
 
   @Test
   public void test() throws Exception {
     // Use D8 to desugar with Java classfile output.
-    Path jar =
+    D8TestCompileResult desugarCompileResult =
         testForD8(Backend.CF)
             .addProgramClassFileData(transformer(TestClass.class).setVersion(cfVersion).transform())
             .setMinApi(parameters)
-            .compile()
-            .writeToZip();
+            .compile();
 
     if (parameters.getRuntime().isCf()) {
       // Run on the JVM given that Cf version is supported. When we desugar we now target 1.7 (51).
-      testForJvm()
-          .addProgramFiles(jar)
+      desugarCompileResult
           .run(parameters.getRuntime(), TestClass.class)
           .assertSuccessWithOutputLines("Hello, world!");
     } else {
       assert parameters.getRuntime().isDex();
       // Convert to DEX without desugaring.
       testForD8()
-          .addProgramFiles(jar)
+          .addProgramFiles(desugarCompileResult.writeToZip())
           .setMinApi(parameters)
           .disableDesugaring()
           .run(parameters.getRuntime(), TestClass.class)
diff --git a/src/test/java/com/android/tools/r8/desugar/InterfaceInvokePrivateTest.java b/src/test/java/com/android/tools/r8/desugar/InterfaceInvokePrivateTest.java
index 4f5e11a..d0c79d7 100644
--- a/src/test/java/com/android/tools/r8/desugar/InterfaceInvokePrivateTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/InterfaceInvokePrivateTest.java
@@ -48,7 +48,7 @@
     assumeTrue(parameters.getRuntime().isCf());
     assumeTrue(parameters.getApiLevel().isEqualTo(AndroidApiLevel.B));
 
-    testForJvm()
+    testForJvm(parameters)
         .addProgramClassFileData(transformIToPrivate(inputCfVersion))
         .addProgramClasses(TestRunner.class)
         .run(parameters.getRuntime(), TestRunner.class)
diff --git a/src/test/java/com/android/tools/r8/desugar/VirtualInvokePrivateTest.java b/src/test/java/com/android/tools/r8/desugar/VirtualInvokePrivateTest.java
index 7ce589a..0b6c4e7 100644
--- a/src/test/java/com/android/tools/r8/desugar/VirtualInvokePrivateTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/VirtualInvokePrivateTest.java
@@ -40,7 +40,7 @@
     assumeTrue(parameters.getRuntime().isCf());
     assumeTrue(parameters.getApiLevel().isEqualTo(AndroidApiLevel.B));
 
-    testForJvm()
+    testForJvm(parameters)
         .addProgramClassFileData(transformInvokeSpecialToInvokeVirtual())
         .run(parameters.getRuntime(), TestRunner.class)
         .assertSuccessWithOutput(EXPECTED_OUTPUT);
diff --git a/src/test/java/com/android/tools/r8/desugar/backports/AbstractBackportTest.java b/src/test/java/com/android/tools/r8/desugar/backports/AbstractBackportTest.java
index 55c17af..1ea71b6 100644
--- a/src/test/java/com/android/tools/r8/desugar/backports/AbstractBackportTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/backports/AbstractBackportTest.java
@@ -154,13 +154,17 @@
   }
 
   @Test
-  public void desugaring() throws Exception {
-    if (parameters.isCfRuntime()) {
-      testForJvm()
-          .apply(this::configureProgram)
-          .run(parameters.getRuntime(), testClassName)
-          .assertSuccess();
-    } else {
+  public void testJvm() throws Exception {
+    parameters.assumeJvmTestParameters();
+    testForJvm(parameters)
+        .apply(this::configureProgram)
+        .run(parameters.getRuntime(), testClassName)
+        .assertSuccess();
+  }
+
+  @Test
+  public void testD8() throws Exception {
+    parameters.assumeDexRuntime();
       testForD8()
           .setMinApi(parameters)
           .apply(this::configureProgram)
@@ -185,7 +189,6 @@
           .run(parameters.getRuntime(), testClassName)
           .assertSuccess()
           .inspect(this::assertDesugaring);
-    }
   }
 
   private void assertDesugaring(CodeInspector inspector) {
diff --git a/src/test/java/com/android/tools/r8/desugar/backports/BackportMainDexTest.java b/src/test/java/com/android/tools/r8/desugar/backports/BackportMainDexTest.java
index 7a7f23e..5369238 100644
--- a/src/test/java/com/android/tools/r8/desugar/backports/BackportMainDexTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/backports/BackportMainDexTest.java
@@ -8,7 +8,6 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
-import static org.junit.Assume.assumeTrue;
 
 import com.android.tools.r8.ByteDataView;
 import com.android.tools.r8.DexIndexedConsumer;
@@ -44,6 +43,8 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
 
 @RunWith(Parameterized.class)
 public class BackportMainDexTest extends TestBase {
@@ -56,17 +57,14 @@
   static final List<Class<?>> MAIN_DEX_LIST_CLASSES =
       ImmutableList.of(MiniAssert.class, TestClass.class, User2.class);
 
-  private final TestParameters parameters;
+  @Parameter(0)
+  public TestParameters parameters;
 
-  @Parameterized.Parameters(name = "{0}")
+  @Parameters(name = "{0}")
   public static TestParametersCollection data() {
     return getTestParameters().withAllRuntimes().withApiLevel(AndroidApiLevel.J).build();
   }
 
-  public BackportMainDexTest(TestParameters parameters) {
-    this.parameters = parameters;
-  }
-
   private String[] getRunArgs() {
     // Only call User1 methods on runtimes with native multidex.
     if (parameters.isCfRuntime()
@@ -82,8 +80,8 @@
 
   @Test
   public void testJvm() throws Exception {
-    assumeTrue(parameters.isCfRuntime());
-    testForJvm()
+    parameters.assumeJvmTestParameters();
+    testForJvm(parameters)
         .addProgramClasses(CLASSES)
         .run(parameters.getRuntime(), TestClass.class, getRunArgs())
         .assertSuccessWithOutput(EXPECTED);
@@ -101,7 +99,7 @@
 
   @Test
   public void testMainDexTracingCf() throws Exception {
-    assumeTrue(parameters.isDexRuntime());
+    parameters.assumeDexRuntime();
     GenerateMainDexListRunResult mainDexListFromCf = traceMainDex(CLASSES, Collections.emptyList());
     assertEquals(
         ListUtils.map(MAIN_DEX_LIST_CLASSES, Reference::classFromClass),
@@ -110,7 +108,7 @@
 
   @Test
   public void testMainDexTracingDex() throws Exception {
-    assumeTrue(parameters.isDexRuntime());
+    parameters.assumeDexRuntime();
     Path out = testForD8().addProgramClasses(CLASSES).setMinApi(parameters).compile().writeToZip();
     GenerateMainDexListRunResult mainDexListFromDex =
         traceMainDex(Collections.emptyList(), Collections.singleton(out));
@@ -124,7 +122,7 @@
 
   @Test
   public void testMainDexTracingDexIntermediates() throws Exception {
-    assumeTrue(parameters.isDexRuntime());
+    parameters.assumeDexRuntime();
     Path out =
         testForD8()
             .addProgramClasses(CLASSES)
@@ -143,9 +141,9 @@
 
   @Test
   public void testD8() throws Exception {
-    assumeTrue(parameters.isDexRuntime());
+    parameters.assumeDexRuntime();
     MainDexConsumer mainDexConsumer = new MainDexConsumer();
-    testForD8(parameters.getBackend())
+    testForD8()
         .addProgramClasses(CLASSES)
         .setMinApi(parameters)
         .addMainDexRules(keepMainProguardConfiguration(TestClass.class))
@@ -168,9 +166,9 @@
   }
 
   private void runD8FilePerMode(OutputMode outputMode) throws Exception {
-    assumeTrue(parameters.isDexRuntime());
+    parameters.assumeDexRuntime();
     Path perClassOutput =
-        testForD8(parameters.getBackend())
+        testForD8()
             .setOutputMode(outputMode)
             .addProgramClasses(CLASSES)
             .setMinApi(parameters)
@@ -192,7 +190,7 @@
 
   @Test
   public void testD8MergingWithTraceDex() throws Exception {
-    assumeTrue(parameters.isDexRuntime());
+    parameters.assumeDexRuntime();
     Path out1 =
         testForD8()
             .addProgramClasses(User1.class)
@@ -215,7 +213,7 @@
     List<Class<?>> classes = ImmutableList.of(TestClass.class, MiniAssert.class);
     List<Path> files = ImmutableList.of(out1, out2);
     GenerateMainDexListRunResult traceResult = traceMainDex(classes, files);
-    testForD8(parameters.getBackend())
+    testForD8()
         .addProgramClasses(classes)
         .addProgramFiles(files)
         .setMinApi(parameters)
diff --git a/src/test/java/com/android/tools/r8/desugar/buffercovariantreturntype/BufferCovariantReturnTypeTest.java b/src/test/java/com/android/tools/r8/desugar/buffercovariantreturntype/BufferCovariantReturnTypeTest.java
index 81a2fc9..43f183d 100644
--- a/src/test/java/com/android/tools/r8/desugar/buffercovariantreturntype/BufferCovariantReturnTypeTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/buffercovariantreturntype/BufferCovariantReturnTypeTest.java
@@ -14,10 +14,11 @@
 import com.android.tools.r8.utils.StringUtils;
 import java.nio.file.Path;
 import java.nio.file.Paths;
-import org.junit.Assume;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
 
 @RunWith(Parameterized.class)
 public class BufferCovariantReturnTypeTest extends TestBase {
@@ -30,9 +31,10 @@
   private static final String EXPECTED_RESULT =
       new String(new char[14]).replace("\0", EXPECTED_RESULT_PER_BUFFER);
 
-  private final TestParameters parameters;
+  @Parameter(0)
+  public TestParameters parameters;
 
-  @Parameterized.Parameters(name = "{0}")
+  @Parameters(name = "{0}")
   public static TestParametersCollection data() {
     return getTestParameters()
         .withCfRuntimesStartingFromIncluding(JDK11)
@@ -41,14 +43,10 @@
         .build();
   }
 
-  public BufferCovariantReturnTypeTest(TestParameters parameters) {
-    this.parameters = parameters;
-  }
-
   @Test
   public void testJVM() throws Exception {
-    Assume.assumeTrue(parameters.isCfRuntime());
-    testForJvm()
+    parameters.assumeJvmTestParameters();
+    testForJvm(parameters)
         .addProgramFiles(JAR)
         .run(parameters.getRuntime(), "buffercovariantreturntype.BufferCovariantReturnTypeMain")
         .assertSuccessWithOutput(EXPECTED_RESULT);
diff --git a/src/test/java/com/android/tools/r8/desugar/constantdynamic/BasicConstantDynamicTest.java b/src/test/java/com/android/tools/r8/desugar/constantdynamic/BasicConstantDynamicTest.java
index b986d0e..7bb8bc87 100644
--- a/src/test/java/com/android/tools/r8/desugar/constantdynamic/BasicConstantDynamicTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/constantdynamic/BasicConstantDynamicTest.java
@@ -41,11 +41,9 @@
 
   @Test
   public void testReference() throws Exception {
-    assumeTrue(parameters.isCfRuntime());
+    parameters.assumeJvmTestParameters();
     assumeTrue(parameters.getRuntime().asCf().isNewerThanOrEqual(CfVm.JDK11));
-    assumeTrue(parameters.getApiLevel().isEqualTo(AndroidApiLevel.B));
-
-    testForJvm()
+    testForJvm(parameters)
         .addProgramClassFileData(getTransformedClasses())
         .run(parameters.getRuntime(), MAIN_CLASS)
         .assertSuccessWithOutput(EXPECTED_OUTPUT);
diff --git a/src/test/java/com/android/tools/r8/desugar/constantdynamic/BootstrapMethodNotFoundConstantDynamicTest.java b/src/test/java/com/android/tools/r8/desugar/constantdynamic/BootstrapMethodNotFoundConstantDynamicTest.java
index dedfc73..8d82bd0 100644
--- a/src/test/java/com/android/tools/r8/desugar/constantdynamic/BootstrapMethodNotFoundConstantDynamicTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/constantdynamic/BootstrapMethodNotFoundConstantDynamicTest.java
@@ -14,7 +14,6 @@
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.TestRuntime.CfVm;
 import com.android.tools.r8.cf.CfVersion;
-import com.android.tools.r8.utils.AndroidApiLevel;
 import java.io.IOException;
 import java.util.List;
 import org.junit.Test;
@@ -38,11 +37,9 @@
 
   @Test
   public void testReference() throws Exception {
-    assumeTrue(parameters.isCfRuntime());
+    parameters.assumeJvmTestParameters();
     assumeTrue(parameters.getRuntime().asCf().isNewerThanOrEqual(CfVm.JDK11));
-    assumeTrue(parameters.getApiLevel().isEqualTo(AndroidApiLevel.B));
-
-    testForJvm()
+    testForJvm(parameters)
         .addProgramClassFileData(getTransformedClasses())
         .run(parameters.getRuntime(), MAIN_CLASS)
         .assertFailureWithErrorThatThrows(NoSuchMethodError.class);
diff --git a/src/test/java/com/android/tools/r8/desugar/constantdynamic/BootstrapMethodPrivateConstantDynamicTest.java b/src/test/java/com/android/tools/r8/desugar/constantdynamic/BootstrapMethodPrivateConstantDynamicTest.java
index eb01a29..f91c5e0 100644
--- a/src/test/java/com/android/tools/r8/desugar/constantdynamic/BootstrapMethodPrivateConstantDynamicTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/constantdynamic/BootstrapMethodPrivateConstantDynamicTest.java
@@ -14,7 +14,6 @@
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.TestRuntime.CfVm;
 import com.android.tools.r8.cf.CfVersion;
-import com.android.tools.r8.utils.AndroidApiLevel;
 import java.io.IOException;
 import java.lang.invoke.MethodHandles;
 import java.util.List;
@@ -39,11 +38,9 @@
 
   @Test
   public void testReference() throws Exception {
-    assumeTrue(parameters.isCfRuntime());
+    parameters.assumeJvmTestParameters();
     assumeTrue(parameters.getRuntime().asCf().isNewerThanOrEqual(CfVm.JDK11));
-    assumeTrue(parameters.getApiLevel().isEqualTo(AndroidApiLevel.B));
-
-    testForJvm()
+    testForJvm(parameters)
         .addProgramClassFileData(getTransformedClasses())
         .run(parameters.getRuntime(), MAIN_CLASS)
         .assertFailureWithErrorThatThrows(IncompatibleClassChangeError.class);
diff --git a/src/test/java/com/android/tools/r8/desugar/constantdynamic/BootstrapMethodVirtualConstantDynamicTest.java b/src/test/java/com/android/tools/r8/desugar/constantdynamic/BootstrapMethodVirtualConstantDynamicTest.java
index a6339c3..c006908 100644
--- a/src/test/java/com/android/tools/r8/desugar/constantdynamic/BootstrapMethodVirtualConstantDynamicTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/constantdynamic/BootstrapMethodVirtualConstantDynamicTest.java
@@ -14,7 +14,6 @@
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.TestRuntime.CfVm;
 import com.android.tools.r8.cf.CfVersion;
-import com.android.tools.r8.utils.AndroidApiLevel;
 import java.io.IOException;
 import java.lang.invoke.MethodHandles;
 import java.util.List;
@@ -39,11 +38,9 @@
 
   @Test
   public void testReference() throws Exception {
-    assumeTrue(parameters.isCfRuntime());
+    parameters.assumeJvmTestParameters();
     assumeTrue(parameters.getRuntime().asCf().isNewerThanOrEqual(CfVm.JDK11));
-    assumeTrue(parameters.getApiLevel().isEqualTo(AndroidApiLevel.B));
-
-    testForJvm()
+    testForJvm(parameters)
         .addProgramClassFileData(getTransformedClasses())
         .run(parameters.getRuntime(), MAIN_CLASS)
         .assertFailureWithErrorThatThrows(IncompatibleClassChangeError.class);
diff --git a/src/test/java/com/android/tools/r8/desugar/constantdynamic/ConstantDynamicGetDeclaredMethodsTest.java b/src/test/java/com/android/tools/r8/desugar/constantdynamic/ConstantDynamicGetDeclaredMethodsTest.java
index def1b0e..235ce97 100644
--- a/src/test/java/com/android/tools/r8/desugar/constantdynamic/ConstantDynamicGetDeclaredMethodsTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/constantdynamic/ConstantDynamicGetDeclaredMethodsTest.java
@@ -56,11 +56,9 @@
 
   @Test
   public void testReference() throws Exception {
-    assumeTrue(parameters.isCfRuntime());
+    parameters.assumeJvmTestParameters();
     assumeTrue(parameters.getRuntime().asCf().isNewerThanOrEqual(CfVm.JDK11));
-    assumeTrue(parameters.getApiLevel().isEqualTo(AndroidApiLevel.B));
-
-    testForJvm()
+    testForJvm(parameters)
         .addProgramClassFileData(getTransformedClasses())
         .run(parameters.getRuntime(), MAIN_CLASS)
         .assertSuccessWithOutput(EXPECTED_OUTPUT_WITH_METHOD_HANDLES);
diff --git a/src/test/java/com/android/tools/r8/desugar/constantdynamic/ConstantDynamicHolderTest.java b/src/test/java/com/android/tools/r8/desugar/constantdynamic/ConstantDynamicHolderTest.java
index e483817..cd8e897 100644
--- a/src/test/java/com/android/tools/r8/desugar/constantdynamic/ConstantDynamicHolderTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/constantdynamic/ConstantDynamicHolderTest.java
@@ -47,7 +47,7 @@
     assumeTrue(parameters.asCfRuntime().isNewerThanOrEqual(CfVm.JDK11));
     assumeTrue(parameters.getApiLevel().isEqualTo(AndroidApiLevel.B));
 
-    testForJvm()
+    testForJvm(parameters)
         .addProgramClassFileData(getTransformedMain())
         .run(parameters.getRuntime(), Main.class)
         .assertSuccessWithOutputLines("null");
@@ -55,7 +55,7 @@
 
   @Test
   public void testD8() throws Exception {
-    assumeTrue(parameters.isDexRuntime());
+    parameters.assumeDexRuntime();
 
     testForD8()
         .addProgramClassFileData(getTransformedMain())
@@ -84,10 +84,8 @@
   // TODO(b/198142625): Support const-dynamic in IR CF/CF.
   @Test(expected = CompilationFailedException.class)
   public void testR8Cf() throws Exception {
-    assumeTrue(parameters.isCfRuntime());
+    parameters.assumeJvmTestParameters();
     assumeTrue(parameters.asCfRuntime().isNewerThanOrEqual(CfVm.JDK11));
-    assumeTrue(parameters.getApiLevel().isEqualTo(AndroidApiLevel.B));
-
     testForR8(parameters.getBackend())
         .addProgramClassFileData(getTransformedMain())
         .setMinApi(parameters)
diff --git a/src/test/java/com/android/tools/r8/desugar/constantdynamic/ConstantDynamicInDefaultInterfaceMethodICCETest.java b/src/test/java/com/android/tools/r8/desugar/constantdynamic/ConstantDynamicInDefaultInterfaceMethodICCETest.java
index 0430da2..b6fc001 100644
--- a/src/test/java/com/android/tools/r8/desugar/constantdynamic/ConstantDynamicInDefaultInterfaceMethodICCETest.java
+++ b/src/test/java/com/android/tools/r8/desugar/constantdynamic/ConstantDynamicInDefaultInterfaceMethodICCETest.java
@@ -14,7 +14,6 @@
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.TestRuntime.CfVm;
 import com.android.tools.r8.cf.CfVersion;
-import com.android.tools.r8.utils.AndroidApiLevel;
 import java.lang.invoke.MethodHandles;
 import java.util.List;
 import org.junit.Test;
@@ -38,11 +37,9 @@
 
   @Test
   public void testReference() throws Exception {
-    assumeTrue(parameters.isCfRuntime());
+    parameters.assumeJvmTestParameters();
     assumeTrue(parameters.getRuntime().asCf().isNewerThanOrEqual(CfVm.JDK11));
-    assumeTrue(parameters.getApiLevel().isEqualTo(AndroidApiLevel.B));
-
-    testForJvm()
+    testForJvm(parameters)
         .addProgramClasses(MAIN_CLASS)
         .addProgramClassFileData(getTransformedClasses())
         .run(parameters.getRuntime(), MAIN_CLASS)
diff --git a/src/test/java/com/android/tools/r8/desugar/constantdynamic/ConstantDynamicInDefaultInterfaceMethodTest.java b/src/test/java/com/android/tools/r8/desugar/constantdynamic/ConstantDynamicInDefaultInterfaceMethodTest.java
index d7effe9..e4cf425 100644
--- a/src/test/java/com/android/tools/r8/desugar/constantdynamic/ConstantDynamicInDefaultInterfaceMethodTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/constantdynamic/ConstantDynamicInDefaultInterfaceMethodTest.java
@@ -40,11 +40,9 @@
 
   @Test
   public void testReference() throws Exception {
-    assumeTrue(parameters.isCfRuntime());
+    parameters.assumeJvmTestParameters();
     assumeTrue(parameters.getRuntime().asCf().isNewerThanOrEqual(CfVm.JDK11));
-    assumeTrue(parameters.getApiLevel().isEqualTo(AndroidApiLevel.B));
-
-    testForJvm()
+    testForJvm(parameters)
         .addProgramClasses(MAIN_CLASS)
         .addProgramClassFileData(getTransformedClasses())
         .run(parameters.getRuntime(), MAIN_CLASS)
diff --git a/src/test/java/com/android/tools/r8/desugar/constantdynamic/HierarchyConstantDynamicTest.java b/src/test/java/com/android/tools/r8/desugar/constantdynamic/HierarchyConstantDynamicTest.java
index 2760b20..1727c3f 100644
--- a/src/test/java/com/android/tools/r8/desugar/constantdynamic/HierarchyConstantDynamicTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/constantdynamic/HierarchyConstantDynamicTest.java
@@ -42,11 +42,9 @@
 
   @Test
   public void testReference() throws Exception {
-    assumeTrue(parameters.isCfRuntime());
+    parameters.assumeJvmTestParameters();
     assumeTrue(parameters.getRuntime().asCf().isNewerThanOrEqual(CfVm.JDK11));
-    assumeTrue(parameters.getApiLevel().isEqualTo(AndroidApiLevel.B));
-
-    testForJvm()
+    testForJvm(parameters)
         .addProgramClassFileData(getTransformedClasses())
         .run(parameters.getRuntime(), A.class)
         .assertSuccessWithOutput(EXPECTED_OUTPUT);
@@ -54,9 +52,8 @@
 
   @Test
   public void testD8() throws Exception {
-    assumeTrue(parameters.isDexRuntime());
-
-    testForD8(parameters.getBackend())
+    parameters.assumeDexRuntime();
+    testForD8()
         .addProgramClassFileData(getTransformedClasses())
         .setMinApi(parameters)
         .run(parameters.getRuntime(), MAIN_CLASS)
diff --git a/src/test/java/com/android/tools/r8/desugar/constantdynamic/JacocoConstantDynamicGetDeclaredMethods.java b/src/test/java/com/android/tools/r8/desugar/constantdynamic/JacocoConstantDynamicGetDeclaredMethods.java
index 899af9f..b6669cd 100644
--- a/src/test/java/com/android/tools/r8/desugar/constantdynamic/JacocoConstantDynamicGetDeclaredMethods.java
+++ b/src/test/java/com/android/tools/r8/desugar/constantdynamic/JacocoConstantDynamicGetDeclaredMethods.java
@@ -81,14 +81,13 @@
 
   @Test
   public void testJvm() throws Exception {
-    assumeTrue(
-        parameters.isCfRuntime()
-            && (parameters.getRuntime().asCf().isNewerThanOrEqual(CfVm.JDK11)));
+    parameters.assumeJvmTestParameters();
+    assumeTrue(parameters.getRuntime().asCf().isNewerThanOrEqual(CfVm.JDK11));
 
     // Run non-instrumented code with an agent causing on the fly instrumentation on the JVM.
     Path output = temp.newFolder().toPath();
     Path agentOutputOnTheFly = output.resolve("on-the-fly");
-    testForJvm()
+    testForJvm(parameters)
         .addProgramFiles(testClasses.getOriginal())
         .enableJaCoCoAgent(ToolHelper.JACOCO_AGENT, agentOutputOnTheFly)
         .run(parameters.getRuntime(), MAIN_CLASS)
@@ -97,7 +96,7 @@
 
     // Run the instrumented code.
     Path agentOutputOffline = output.resolve("offline");
-    testForJvm()
+    testForJvm(parameters)
         .addProgramFiles(testClasses.getInstrumented())
         .configureJaCoCoAgentForOfflineInstrumentedCode(ToolHelper.JACOCO_AGENT, agentOutputOffline)
         .run(parameters.getRuntime(), MAIN_CLASS)
diff --git a/src/test/java/com/android/tools/r8/desugar/constantdynamic/JacocoConstantDynamicTest.java b/src/test/java/com/android/tools/r8/desugar/constantdynamic/JacocoConstantDynamicTest.java
index 63772bd..2761139 100644
--- a/src/test/java/com/android/tools/r8/desugar/constantdynamic/JacocoConstantDynamicTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/constantdynamic/JacocoConstantDynamicTest.java
@@ -33,7 +33,8 @@
 @RunWith(Parameterized.class)
 public class JacocoConstantDynamicTest extends TestBase {
 
-  @Parameter() public TestParameters parameters;
+  @Parameter(0)
+  public TestParameters parameters;
 
   @Parameter(1)
   public boolean useConstantDynamic;
@@ -60,16 +61,15 @@
   }
 
   @Before
-  public void setUp() throws IOException {
+  public void setUp() {
     testClasses = useConstantDynamic ? testClassesConstantDynamic : testClassesNoConstantDynamic;
   }
 
   @Test
   public void testJvm() throws Exception {
+    parameters.assumeJvmTestParameters();
     assumeTrue(
-        parameters.isCfRuntime()
-            && (parameters.getRuntime().asCf().isNewerThanOrEqual(CfVm.JDK11)
-                || !useConstantDynamic));
+        parameters.getRuntime().asCf().isNewerThanOrEqual(CfVm.JDK11) || !useConstantDynamic);
 
     // Run non-instrumented code.
     testForRuntime(parameters)
@@ -80,7 +80,7 @@
     // Run non-instrumented code with an agent causing on the fly instrumentation on the JVM.
     Path output = temp.newFolder().toPath();
     Path agentOutputOnTheFly = output.resolve("on-the-fly");
-    testForJvm()
+    testForJvm(parameters)
         .addProgramFiles(testClasses.getOriginal())
         .enableJaCoCoAgent(ToolHelper.JACOCO_AGENT, agentOutputOnTheFly)
         .run(parameters.getRuntime(), MAIN_CLASS)
@@ -90,7 +90,7 @@
 
     // Run the instrumented code.
     Path agentOutputOffline = output.resolve("offline");
-    testForJvm()
+    testForJvm(parameters)
         .addProgramFiles(testClasses.getInstrumented())
         .configureJaCoCoAgentForOfflineInstrumentedCode(ToolHelper.JACOCO_AGENT, agentOutputOffline)
         .run(parameters.getRuntime(), MAIN_CLASS)
@@ -101,11 +101,11 @@
 
   @Test
   public void testD8() throws Exception {
-    assumeTrue(parameters.getRuntime().isDex());
+    parameters.assumeDexRuntime();
     if (!useConstantDynamic) {
       Path output = temp.newFolder().toPath();
       Path agentOutput = output.resolve("jacoco.exec");
-      testForD8(parameters.getBackend())
+      testForD8()
           .addProgramFiles(testClasses.getInstrumented())
           .addProgramFiles(ToolHelper.JACOCO_AGENT)
           .setMinApi(parameters)
@@ -120,7 +120,7 @@
         assertFalse(Files.exists(agentOutput));
       }
     } else {
-      testForD8(parameters.getBackend())
+      testForD8()
           .addProgramFiles(testClasses.getInstrumented())
           .addProgramFiles(ToolHelper.JACOCO_AGENT)
           .setMinApi(parameters)
diff --git a/src/test/java/com/android/tools/r8/desugar/constantdynamic/MultipleBootstrapMethodConstantDynamicTest.java b/src/test/java/com/android/tools/r8/desugar/constantdynamic/MultipleBootstrapMethodConstantDynamicTest.java
index 58988d8..0c61fb4 100644
--- a/src/test/java/com/android/tools/r8/desugar/constantdynamic/MultipleBootstrapMethodConstantDynamicTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/constantdynamic/MultipleBootstrapMethodConstantDynamicTest.java
@@ -42,11 +42,9 @@
 
   @Test
   public void testReference() throws Exception {
-    assumeTrue(parameters.isCfRuntime());
+    parameters.assumeJvmTestParameters();
     assumeTrue(parameters.getRuntime().asCf().isNewerThanOrEqual(CfVm.JDK11));
-    assumeTrue(parameters.getApiLevel().isEqualTo(AndroidApiLevel.B));
-
-    testForJvm()
+    testForJvm(parameters)
         .addProgramClassFileData(getTransformedClasses())
         .run(parameters.getRuntime(), MAIN_CLASS)
         .assertSuccessWithOutput(EXPECTED_OUTPUT);
diff --git a/src/test/java/com/android/tools/r8/desugar/constantdynamic/MultipleNamedConstantDynamicTest.java b/src/test/java/com/android/tools/r8/desugar/constantdynamic/MultipleNamedConstantDynamicTest.java
index 436c9c2..693f244c 100644
--- a/src/test/java/com/android/tools/r8/desugar/constantdynamic/MultipleNamedConstantDynamicTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/constantdynamic/MultipleNamedConstantDynamicTest.java
@@ -47,7 +47,7 @@
     assumeTrue(parameters.getRuntime().asCf().isNewerThanOrEqual(CfVm.JDK11));
     assumeTrue(parameters.getApiLevel().isEqualTo(AndroidApiLevel.B));
 
-    testForJvm()
+    testForJvm(parameters)
         .addProgramClassFileData(getTransformedClasses())
         .run(parameters.getRuntime(), MAIN_CLASS)
         .assertSuccessWithOutput(EXPECTED_OUTPUT);
diff --git a/src/test/java/com/android/tools/r8/desugar/constantdynamic/MultipleTypesConstantDynamicTest.java b/src/test/java/com/android/tools/r8/desugar/constantdynamic/MultipleTypesConstantDynamicTest.java
index 2303d46..35d0761 100644
--- a/src/test/java/com/android/tools/r8/desugar/constantdynamic/MultipleTypesConstantDynamicTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/constantdynamic/MultipleTypesConstantDynamicTest.java
@@ -46,7 +46,7 @@
     assumeTrue(parameters.getRuntime().asCf().isNewerThanOrEqual(CfVm.JDK11));
     assumeTrue(parameters.getApiLevel().isEqualTo(AndroidApiLevel.B));
 
-    testForJvm()
+    testForJvm(parameters)
         .addProgramClassFileData(getTransformedClasses())
         .run(parameters.getRuntime(), A.class)
         .assertSuccessWithOutput(EXPECTED_OUTPUT);
diff --git a/src/test/java/com/android/tools/r8/desugar/constantdynamic/SharedBootstrapMethodConstantDynamicTest.java b/src/test/java/com/android/tools/r8/desugar/constantdynamic/SharedBootstrapMethodConstantDynamicTest.java
index 19802ae..71dc4dd 100644
--- a/src/test/java/com/android/tools/r8/desugar/constantdynamic/SharedBootstrapMethodConstantDynamicTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/constantdynamic/SharedBootstrapMethodConstantDynamicTest.java
@@ -56,7 +56,7 @@
     assumeTrue(parameters.asCfRuntime().isNewerThanOrEqual(CfVm.JDK11));
     assumeTrue(parameters.getApiLevel().isEqualTo(AndroidApiLevel.B));
 
-    testForJvm()
+    testForJvm(parameters)
         .addProgramClassFileData(getTransformedClasses())
         .run(parameters.getRuntime(), MAIN_CLASS)
         .assertSuccessWithOutput(EXPECTED_OUTPUT);
@@ -80,7 +80,7 @@
 
   @Test
   public void testD8Cf() throws Exception {
-    assumeTrue(parameters.isCfRuntime());
+    parameters.assumeCfRuntime();
     testForD8(parameters.getBackend())
         .addProgramClassFileData(getTransformedClasses())
         .setMinApi(parameters)
@@ -111,8 +111,8 @@
 
   @Test
   public void testD8() throws Exception {
-    assumeTrue(parameters.isDexRuntime());
-    testForD8(parameters.getBackend())
+    parameters.assumeDexRuntime();
+    testForD8()
         .addProgramClassFileData(getTransformedClasses())
         .setMinApi(parameters)
         .setDiagnosticsLevelModifier(
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DefaultMethodOverrideConflictWithLibrary2Test.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DefaultMethodOverrideConflictWithLibrary2Test.java
index 5e79404..be7017e 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DefaultMethodOverrideConflictWithLibrary2Test.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DefaultMethodOverrideConflictWithLibrary2Test.java
@@ -82,7 +82,7 @@
       assertTrue(method.isDefault());
     }
     if (parameters.isCfRuntime()) {
-      testForJvm()
+      testForJvm(parameters)
           .addProgramClasses(getClasses())
           .addProgramClassFileData(getTransforms())
           .run(parameters.getRuntime(), Main.class)
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DefaultMethodOverrideConflictWithLibraryTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DefaultMethodOverrideConflictWithLibraryTest.java
index b608d74..a088901 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DefaultMethodOverrideConflictWithLibraryTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DefaultMethodOverrideConflictWithLibraryTest.java
@@ -84,7 +84,7 @@
       }
     }
     if (parameters.isCfRuntime()) {
-      testForJvm()
+      testForJvm(parameters)
           .addProgramClasses(CLASSES)
           .addProgramClassFileData(getTransforms())
           .run(parameters.getRuntime(), Main.class)
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DefaultMethodOverrideInLibraryTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DefaultMethodOverrideInLibraryTest.java
index 0230e38..1beb0ae 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DefaultMethodOverrideInLibraryTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DefaultMethodOverrideInLibraryTest.java
@@ -74,7 +74,7 @@
       assertFalse(spliterator.isDefault());
     }
     if (parameters.isCfRuntime()) {
-      testForJvm()
+      testForJvm(parameters)
           .addInnerClasses(DefaultMethodOverrideInLibraryTest.class)
           .run(parameters.getRuntime(), Main.class)
           .assertSuccessWithOutput(EXPECTED);
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/J$ExtensionTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/J$ExtensionTest.java
index 250be0e..29baa44 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/J$ExtensionTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/J$ExtensionTest.java
@@ -104,7 +104,7 @@
     String stderr;
     if (parameters.isCfRuntime()) {
       stderr =
-          testForJvm()
+          testForJvm(parameters)
               .addProgramFiles(compiledClasses)
               .run(parameters.getRuntime(), MAIN_CLASS_NAME)
               .assertFailure()
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/MinimalInterfaceSuperTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/MinimalInterfaceSuperTest.java
index 20e61c2..8dbaa32 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/MinimalInterfaceSuperTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/MinimalInterfaceSuperTest.java
@@ -52,7 +52,7 @@
   @Test
   public void testMinimalInterfaceSuper() throws Exception {
     if (parameters.isCfRuntime()) {
-      testForJvm()
+      testForJvm(parameters)
           .addInnerClasses(MinimalInterfaceSuperTest.class)
           .run(parameters.getRuntime(), Main.class)
           .assertSuccessWithOutput(EXPECTED_OUTPUT);
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/MonthTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/MonthTest.java
index 0fbcc8c..2ac24dc 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/MonthTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/MonthTest.java
@@ -65,7 +65,7 @@
   @Test
   public void testMonth() throws Exception {
     if (parameters.isCfRuntime()) {
-      testForJvm()
+      testForJvm(parameters)
           .addInnerClasses(MonthTest.class)
           .run(parameters.getRuntime(), MonthTest.Main.class)
           .assertSuccessWithOutput(getExpectedResult(parameters));
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/NoDefaultMethodOverrideInLibraryTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/NoDefaultMethodOverrideInLibraryTest.java
index 696d737..263dbd7 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/NoDefaultMethodOverrideInLibraryTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/NoDefaultMethodOverrideInLibraryTest.java
@@ -78,7 +78,7 @@
       }
     }
     if (parameters.isCfRuntime()) {
-      testForJvm()
+      testForJvm(parameters)
           .addInnerClasses(NoDefaultMethodOverrideInLibraryTest.class)
           .run(parameters.getRuntime(), Main.class)
           .assertSuccessWithOutput(EXPECTED);
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/WrapperPlacementTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/WrapperPlacementTest.java
index 424009b..658b2f3 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/WrapperPlacementTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/WrapperPlacementTest.java
@@ -65,7 +65,7 @@
         parameters.isCfRuntime()
             && libraryDesugaringSpecification == JDK8
             && compilationSpecification.isProgramShrink());
-    testForJvm()
+    testForJvm(parameters)
         .addAndroidBuildVersion()
         .addProgramClassesAndInnerClasses(MyArrays1.class)
         .addProgramClassesAndInnerClasses(MyArrays2.class)
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdk11/FileLockTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdk11/FileLockTest.java
index ae36385..2ea0a50 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdk11/FileLockTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdk11/FileLockTest.java
@@ -82,7 +82,7 @@
       // Reference runtime, we use Jdk 11 since this is Jdk 11 desugared library, not that Jdk 8
       // behaves differently on this test.
       Assume.assumeTrue(parameters.isCfRuntime(CfVm.JDK11) && !ToolHelper.isWindows());
-      testForJvm()
+      testForJvm(parameters)
           .addInnerClasses(getClass())
           .run(parameters.getRuntime(), TestClass.class, "10000")
           .assertSuccessWithOutput(EXPECTED_RESULT);
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdk11/FilesAttributes2Test.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdk11/FilesAttributes2Test.java
index 8bbd564..d1b48f6 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdk11/FilesAttributes2Test.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdk11/FilesAttributes2Test.java
@@ -165,7 +165,7 @@
       // Reference runtime, we use Jdk 11 since this is Jdk 11 desugared library, not that Jdk 8
       // behaves differently on this test.
       Assume.assumeTrue(parameters.isCfRuntime(CfVm.JDK11) && !ToolHelper.isWindows());
-      testForJvm()
+      testForJvm(parameters)
           .addInnerClasses(getClass())
           .run(parameters.getRuntime(), TestClass.class)
           .assertSuccessWithOutput(getExpectedResult());
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdk11/FilesAttributesTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdk11/FilesAttributesTest.java
index 2ccaa08..4c0b7d9 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdk11/FilesAttributesTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdk11/FilesAttributesTest.java
@@ -149,7 +149,7 @@
       // Reference runtime, we use Jdk 11 since this is Jdk 11 desugared library, not that Jdk 8
       // behaves differently on this test.
       Assume.assumeTrue(parameters.isCfRuntime(CfVm.JDK11) && !ToolHelper.isWindows());
-      testForJvm()
+      testForJvm(parameters)
           .addInnerClasses(getClass())
           .run(parameters.getRuntime(), TestClass.class)
           .assertSuccessWithOutput(getExpectedResult());
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdk11/FilesCreateTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdk11/FilesCreateTest.java
index 5f7fd4b..2a301f1 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdk11/FilesCreateTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdk11/FilesCreateTest.java
@@ -101,7 +101,7 @@
       // Reference runtime, we use Jdk 11 since this is Jdk 11 desugared library, not that Jdk 8
       // behaves differently on this test.
       Assume.assumeTrue(parameters.isCfRuntime(CfVm.JDK11) && !ToolHelper.isWindows());
-      testForJvm()
+      testForJvm(parameters)
           .addInnerClasses(getClass())
           .run(parameters.getRuntime(), TestClass.class)
           .assertSuccessWithOutput(getExpectedResult());
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdk11/FilesInOutTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdk11/FilesInOutTest.java
index f1aacd6..c16ec8b 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdk11/FilesInOutTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdk11/FilesInOutTest.java
@@ -197,7 +197,7 @@
       // Reference runtime, we use Jdk 11 since this is Jdk 11 desugared library, not that Jdk 8
       // behaves differently on this test.
       Assume.assumeTrue(parameters.isCfRuntime(CfVm.JDK11) && !ToolHelper.isWindows());
-      testForJvm()
+      testForJvm(parameters)
           .addInnerClasses(getClass())
           .run(parameters.getRuntime(), TestClass.class)
           .assertSuccessWithOutput(getExpectedResult());
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdk11/FilesMoveCopyTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdk11/FilesMoveCopyTest.java
index 9656a73..eed1149 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdk11/FilesMoveCopyTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdk11/FilesMoveCopyTest.java
@@ -131,7 +131,7 @@
       // Reference runtime, we use Jdk 11 since this is Jdk 11 desugared library, not that Jdk 8
       // behaves differently on this test.
       Assume.assumeTrue(parameters.isCfRuntime(CfVm.JDK11) && !ToolHelper.isWindows());
-      testForJvm()
+      testForJvm(parameters)
           .addInnerClasses(getClass())
           .run(parameters.getRuntime(), TestClass.class)
           .assertSuccessWithOutput(EXPECTED_RESULT);
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdk11/FilesSymLinkTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdk11/FilesSymLinkTest.java
index aa43822..4ec83cb 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdk11/FilesSymLinkTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdk11/FilesSymLinkTest.java
@@ -71,7 +71,7 @@
       // Reference runtime, we use Jdk 11 since this is Jdk 11 desugared library, not that Jdk 8
       // behaves differently on this test.
       Assume.assumeTrue(parameters.isCfRuntime(CfVm.JDK11) && !ToolHelper.isWindows());
-      testForJvm()
+      testForJvm(parameters)
           .addInnerClasses(getClass())
           .run(parameters.getRuntime(), TestClass.class, "10000")
           .assertSuccessWithOutput(EXPECTED_RESULT);
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdk11/FilesVisitTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdk11/FilesVisitTest.java
index 4d7cccc..50f1721 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdk11/FilesVisitTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdk11/FilesVisitTest.java
@@ -85,7 +85,7 @@
       // Reference runtime, we use Jdk 11 since this is Jdk 11 desugared library, not that Jdk 8
       // behaves differently on this test.
       Assume.assumeTrue(parameters.isCfRuntime(CfVm.JDK11) && !ToolHelper.isWindows());
-      testForJvm()
+      testForJvm(parameters)
           .addInnerClasses(getClass())
           .run(parameters.getRuntime(), TestClass.class)
           .assertSuccessWithOutput(EXPECTED_RESULT);
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdk11/FilesWatchEventTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdk11/FilesWatchEventTest.java
index 38ea6d4..a78018e 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdk11/FilesWatchEventTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdk11/FilesWatchEventTest.java
@@ -73,7 +73,7 @@
       // Reference runtime, we use Jdk 11 since this is Jdk 11 desugared library, not that Jdk 8
       // behaves differently on this test.
       Assume.assumeTrue(parameters.isCfRuntime(CfVm.JDK11) && !ToolHelper.isWindows());
-      testForJvm()
+      testForJvm(parameters)
           .addInnerClasses(getClass())
           .run(parameters.getRuntime(), TestClass.class)
           .assertSuccessWithOutput(EXPECTED_RESULT);
diff --git a/src/test/java/com/android/tools/r8/desugar/enclosingmethod/EnclosingMethodRewriteTest.java b/src/test/java/com/android/tools/r8/desugar/enclosingmethod/EnclosingMethodRewriteTest.java
index 8d662c8..50920ee 100644
--- a/src/test/java/com/android/tools/r8/desugar/enclosingmethod/EnclosingMethodRewriteTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/enclosingmethod/EnclosingMethodRewriteTest.java
@@ -83,7 +83,7 @@
   @Test
   public void testJVMOutput() throws Exception {
     parameters.assumeJvmTestParameters();
-    testForJvm()
+    testForJvm(parameters)
         .addTestClasspath()
         .run(parameters.getRuntime(), MAIN)
         .assertSuccessWithOutputLines(EXPECTED);
diff --git a/src/test/java/com/android/tools/r8/desugar/graph/CompilationDependentSetTest.java b/src/test/java/com/android/tools/r8/desugar/graph/CompilationDependentSetTest.java
index 514fde2..258805a 100644
--- a/src/test/java/com/android/tools/r8/desugar/graph/CompilationDependentSetTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/graph/CompilationDependentSetTest.java
@@ -57,7 +57,7 @@
   @Test
   public void test() throws Exception {
     if (parameters.isCfRuntime()) {
-      testForJvm()
+      testForJvm(parameters)
           .addProgramClasses(I.class, A.class, B.class, TestClass.class)
           .run(parameters.getRuntime(), TestClass.class)
           .assertSuccessWithOutputLines("Hello World!");
diff --git a/src/test/java/com/android/tools/r8/desugar/graph/InterfaceBridgeDependencyTest.java b/src/test/java/com/android/tools/r8/desugar/graph/InterfaceBridgeDependencyTest.java
index cccd43b..6c11011 100644
--- a/src/test/java/com/android/tools/r8/desugar/graph/InterfaceBridgeDependencyTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/graph/InterfaceBridgeDependencyTest.java
@@ -69,7 +69,7 @@
   @Test
   public void test() throws Exception {
     if (parameters.isCfRuntime()) {
-      testForJvm()
+      testForJvm(parameters)
           .addProgramClasses(I.class, J.class, K.class, TestClass.class)
           .run(parameters.getRuntime(), TestClass.class)
           .assertSuccessWithOutput(EXPECTED);
diff --git a/src/test/java/com/android/tools/r8/desugar/graph/InterfaceToImplementingClassDependencyTest.java b/src/test/java/com/android/tools/r8/desugar/graph/InterfaceToImplementingClassDependencyTest.java
index 87a33f9..aab7123 100644
--- a/src/test/java/com/android/tools/r8/desugar/graph/InterfaceToImplementingClassDependencyTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/graph/InterfaceToImplementingClassDependencyTest.java
@@ -63,7 +63,7 @@
   @Test
   public void test() throws Exception {
     if (parameters.isCfRuntime()) {
-      testForJvm()
+      testForJvm(parameters)
           .addProgramClasses(I.class, A.class, TestClass.class)
           .run(parameters.getRuntime(), TestClass.class)
           .assertSuccessWithOutputLines("Hello World!");
diff --git a/src/test/java/com/android/tools/r8/desugar/graph/LambdaDependencyTest.java b/src/test/java/com/android/tools/r8/desugar/graph/LambdaDependencyTest.java
index 9c8a99a..cdb01f6 100644
--- a/src/test/java/com/android/tools/r8/desugar/graph/LambdaDependencyTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/graph/LambdaDependencyTest.java
@@ -53,7 +53,7 @@
   @Test
   public void test() throws Exception {
     if (parameters.isCfRuntime()) {
-      testForJvm()
+      testForJvm(parameters)
           .addProgramClasses(I.class, A.class, TestClass.class)
           .run(parameters.getRuntime(), TestClass.class)
           .assertSuccessWithOutputLines("lambda!");
diff --git a/src/test/java/com/android/tools/r8/desugar/graph/NestDependencyTest.java b/src/test/java/com/android/tools/r8/desugar/graph/NestDependencyTest.java
index 7bf1ab9..df53dc1 100644
--- a/src/test/java/com/android/tools/r8/desugar/graph/NestDependencyTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/graph/NestDependencyTest.java
@@ -57,7 +57,7 @@
   @Test
   public void test() throws Exception {
     if (parameters.isCfRuntime()) {
-      testForJvm()
+      testForJvm(parameters)
           .addProgramClassFileData(inNest(Host.class), inNest(Member1.class), inNest(Member2.class))
           .addProgramClasses(TestClass.class)
           .run(parameters.getRuntime(), TestClass.class)
diff --git a/src/test/java/com/android/tools/r8/desugar/jdk8272564/Jdk8272564InvalidCode.java b/src/test/java/com/android/tools/r8/desugar/jdk8272564/Jdk8272564InvalidCode.java
index be271ed..26339fb 100644
--- a/src/test/java/com/android/tools/r8/desugar/jdk8272564/Jdk8272564InvalidCode.java
+++ b/src/test/java/com/android/tools/r8/desugar/jdk8272564/Jdk8272564InvalidCode.java
@@ -41,7 +41,7 @@
   @Test
   public void testRuntime() throws Exception {
     assumeTrue(isDefaultCfParameters());
-    testForJvm()
+    testForJvm(parameters)
         .addProgramClasses(I.class)
         .addProgramClassFileData(getTransformedClass())
         .run(parameters.getRuntime(), A.class)
diff --git a/src/test/java/com/android/tools/r8/desugar/jdk8272564/Jdk8272564Test.java b/src/test/java/com/android/tools/r8/desugar/jdk8272564/Jdk8272564Test.java
index 1948366..08e9523 100644
--- a/src/test/java/com/android/tools/r8/desugar/jdk8272564/Jdk8272564Test.java
+++ b/src/test/java/com/android/tools/r8/desugar/jdk8272564/Jdk8272564Test.java
@@ -132,7 +132,7 @@
   @Test
   public void testJvm() throws Exception {
     assumeTrue(isDefaultCfParameters());
-    testForJvm()
+    testForJvm(parameters)
         .addRunClasspathFiles(Jdk8272564.jar())
         .run(parameters.getRuntime(), Jdk8272564.Main.typeName())
         .assertSuccess();
diff --git a/src/test/java/com/android/tools/r8/desugar/lambdas/LambdaEqualityTest.java b/src/test/java/com/android/tools/r8/desugar/lambdas/LambdaEqualityTest.java
index 90fed59..dd5f654 100644
--- a/src/test/java/com/android/tools/r8/desugar/lambdas/LambdaEqualityTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/lambdas/LambdaEqualityTest.java
@@ -3,7 +3,6 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.desugar.lambdas;
 
-import static org.junit.Assume.assumeTrue;
 
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
@@ -83,7 +82,7 @@
 
   @Test
   public void testJvm() throws Exception {
-    assumeTrue(parameters.isCfRuntime());
+    parameters.assumeJvmTestParameters();
     testForRuntime(parameters)
         .addInnerClasses(LambdaEqualityTest.class)
         .run(parameters.getRuntime(), TestClass.class)
diff --git a/src/test/java/com/android/tools/r8/desugar/lambdas/LambdaInStacktraceTest.java b/src/test/java/com/android/tools/r8/desugar/lambdas/LambdaInStacktraceTest.java
index 13b6b05..851d489 100644
--- a/src/test/java/com/android/tools/r8/desugar/lambdas/LambdaInStacktraceTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/lambdas/LambdaInStacktraceTest.java
@@ -75,7 +75,7 @@
   @Test
   public void testJvm() throws Exception {
     parameters.assumeJvmTestParameters();
-    testForJvm()
+    testForJvm(parameters)
         .addInnerClasses(LambdaInStacktraceTest.class)
         .run(parameters.getRuntime(), TestRunner.class, Boolean.toString(false))
         .assertSuccess()
diff --git a/src/test/java/com/android/tools/r8/desugar/lambdas/LambdaJava17Test.java b/src/test/java/com/android/tools/r8/desugar/lambdas/LambdaJava17Test.java
index c516b32..e9c6102 100644
--- a/src/test/java/com/android/tools/r8/desugar/lambdas/LambdaJava17Test.java
+++ b/src/test/java/com/android/tools/r8/desugar/lambdas/LambdaJava17Test.java
@@ -47,8 +47,8 @@
 
   @Test
   public void testReference() throws Exception {
-    Assume.assumeTrue(parameters.isCfRuntime());
-    testForJvm()
+    parameters.assumeJvmTestParameters();
+    testForJvm(parameters)
         .addProgramFiles(JDK17_JAR)
         .run(parameters.getRuntime(), MAIN)
         .assertSuccessWithOutputLines(EXPECTED_RESULT);
diff --git a/src/test/java/com/android/tools/r8/desugar/lambdas/LambdaMethodsWithModifiedAccessTest.java b/src/test/java/com/android/tools/r8/desugar/lambdas/LambdaMethodsWithModifiedAccessTest.java
index 8a4743e..a63b129 100644
--- a/src/test/java/com/android/tools/r8/desugar/lambdas/LambdaMethodsWithModifiedAccessTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/lambdas/LambdaMethodsWithModifiedAccessTest.java
@@ -7,7 +7,6 @@
 import static com.android.tools.r8.utils.codeinspector.Matchers.isPrivate;
 import static com.android.tools.r8.utils.codeinspector.Matchers.isPublic;
 import static org.hamcrest.MatcherAssert.assertThat;
-import static org.junit.Assume.assumeTrue;
 
 import com.android.tools.r8.CompilationFailedException;
 import com.android.tools.r8.TestBase;
@@ -68,8 +67,8 @@
 
   @Test
   public void testJvm() throws Exception {
-    assumeTrue(parameters.isCfRuntime());
-    testForJvm()
+    parameters.assumeJvmTestParameters();
+    testForJvm(parameters)
         .addProgramClasses(TestClass.class)
         .addProgramClassFileData(getTransformedLambdaTest())
         .run(parameters.getRuntime(), TestClass.class)
@@ -85,8 +84,8 @@
   //     || (implHandle.type.isInvokeDirect() && isPublicizedInstanceMethod(target));
   @Test(expected = CompilationFailedException.class)
   public void testD8() throws Exception {
-    assumeTrue(parameters.isDexRuntime());
-    testForD8(parameters.getBackend())
+    parameters.assumeDexRuntime();
+    testForD8()
         .addProgramClasses(TestClass.class)
         .addProgramClassFileData(getTransformedLambdaTest())
         .setMinApi(parameters)
diff --git a/src/test/java/com/android/tools/r8/desugar/lambdas/LambdaNamingConflictTest.java b/src/test/java/com/android/tools/r8/desugar/lambdas/LambdaNamingConflictTest.java
index 6882f73..8e818a2 100644
--- a/src/test/java/com/android/tools/r8/desugar/lambdas/LambdaNamingConflictTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/lambdas/LambdaNamingConflictTest.java
@@ -3,7 +3,6 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.desugar.lambdas;
 
-import static org.junit.Assume.assumeTrue;
 
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
@@ -42,8 +41,8 @@
 
   @Test
   public void testJvm() throws Exception {
-    assumeTrue(parameters.isCfRuntime());
-    testForJvm()
+    parameters.assumeJvmTestParameters();
+    testForJvm(parameters)
         .addProgramClasses(I.class)
         .addProgramClassFileData(getConflictingNameClass())
         .addProgramClassFileData(getTransformedMainClass())
diff --git a/src/test/java/com/android/tools/r8/desugar/lambdas/LegacyLambdaMergeTest.java b/src/test/java/com/android/tools/r8/desugar/lambdas/LegacyLambdaMergeTest.java
index 51b0242..31823c7 100644
--- a/src/test/java/com/android/tools/r8/desugar/lambdas/LegacyLambdaMergeTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/lambdas/LegacyLambdaMergeTest.java
@@ -38,8 +38,8 @@
 
   @Test
   public void testReference() throws Exception {
-    assumeTrue(parameters.isCfRuntime());
-    testForJvm()
+    parameters.assumeJvmTestParameters();
+    testForJvm(parameters)
         .addProgramClassFileData(getTransformedMain())
         // Add the lambda twice (JVM just picks the first).
         .addProgramClassFileData(getTransformedLambda())
diff --git a/src/test/java/com/android/tools/r8/desugar/lambdas/OverlappingLambdaMethodInSubclassWithSameNameTest.java b/src/test/java/com/android/tools/r8/desugar/lambdas/OverlappingLambdaMethodInSubclassWithSameNameTest.java
index b890947..a2edc18 100644
--- a/src/test/java/com/android/tools/r8/desugar/lambdas/OverlappingLambdaMethodInSubclassWithSameNameTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/lambdas/OverlappingLambdaMethodInSubclassWithSameNameTest.java
@@ -3,7 +3,6 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.desugar.lambdas;
 
-import static org.junit.Assume.assumeTrue;
 
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
@@ -36,7 +35,7 @@
 
   @Test
   public void testJvm() throws Exception {
-    assumeTrue(parameters.isCfRuntime());
+    parameters.assumeJvmTestParameters();
     testForRuntime(parameters)
         .addProgramClasses(
             MAIN_CLASS,
diff --git a/src/test/java/com/android/tools/r8/desugar/nest/NestBasedAccessToNativeMethodTest.java b/src/test/java/com/android/tools/r8/desugar/nest/NestBasedAccessToNativeMethodTest.java
index be1214b..b5eff1f 100644
--- a/src/test/java/com/android/tools/r8/desugar/nest/NestBasedAccessToNativeMethodTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/nest/NestBasedAccessToNativeMethodTest.java
@@ -5,7 +5,6 @@
 package com.android.tools.r8.desugar.nest;
 
 import static com.android.tools.r8.TestRuntime.CfVm.JDK11;
-import static org.junit.Assume.assumeTrue;
 
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
@@ -38,7 +37,7 @@
 
   @Test
   public void testD8() throws Exception {
-    assumeTrue(parameters.isDexRuntime());
+    parameters.assumeDexRuntime();
     testForD8()
         .addProgramClassFileData(getProgramClassFileData())
         .setMinApi(parameters)
diff --git a/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/FullNestOnProgramPathTest.java b/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/FullNestOnProgramPathTest.java
index 9737f85..f90b2cf 100644
--- a/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/FullNestOnProgramPathTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/FullNestOnProgramPathTest.java
@@ -70,7 +70,7 @@
   public void testAllNestsJavaAndD8() throws Exception {
     for (String nestID : NEST_IDS) {
       if (parameters.isCfRuntime()) {
-        testForJvm()
+        testForJvm(parameters)
             .addProgramFiles(JAR)
             .run(parameters.getRuntime(), getMainClass(nestID))
             .assertSuccessWithOutput(getExpectedResult(nestID));
diff --git a/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/NestAttributesInDexRewriteInvokeInterfaceTest.java b/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/NestAttributesInDexRewriteInvokeInterfaceTest.java
index c491627..ba294c2 100644
--- a/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/NestAttributesInDexRewriteInvokeInterfaceTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/NestAttributesInDexRewriteInvokeInterfaceTest.java
@@ -51,8 +51,8 @@
 
   @Test
   public void testRuntime() throws Exception {
-    assumeTrue(parameters.isCfRuntime());
-    testForJvm()
+    parameters.assumeJvmTestParameters();
+    testForJvm(parameters)
         .addProgramClassFileData(
             dumpHost(),
             dumpMember1(),
@@ -75,7 +75,7 @@
 
   @Test
   public void testD8() throws Exception {
-    assumeTrue(parameters.isDexRuntime());
+    parameters.assumeDexRuntime();
     // TODO(b/247047415): Update test when a DEX VM natively supporting nests is added.
     assertFalse(parameters.getApiLevel().getLevel() > 33);
     testForD8()
diff --git a/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/NestAttributesInDexRewriteInvokeSuperTest.java b/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/NestAttributesInDexRewriteInvokeSuperTest.java
index b505020..e297523 100644
--- a/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/NestAttributesInDexRewriteInvokeSuperTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/NestAttributesInDexRewriteInvokeSuperTest.java
@@ -50,7 +50,7 @@
         parameters.isCfRuntime()
             && parameters.asCfRuntime().isNewerThanOrEqual(CfVm.JDK11)
             && parameters.getApiLevel().isEqualTo(AndroidApiLevel.B));
-    testForJvm()
+    testForJvm(parameters)
         .addProgramClassFileData(dumpHost(), dumpMember(), dumpSubMember())
         .run(parameters.getRuntime(), "Host")
         .assertSuccessWithOutputLines(EXPECTED_OUTPUT_LINES);
@@ -67,7 +67,7 @@
 
   @Test
   public void testD8() throws Exception {
-    assumeTrue(parameters.isDexRuntime());
+    parameters.assumeDexRuntime();
     // TODO(b/247047415): Update test when a DEX VM natively supporting nests is added.
     assertFalse(parameters.getApiLevel().getLevel() > 33);
     testForD8()
diff --git a/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/NestAttributesInDexRewriteInvokeVirtualTest.java b/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/NestAttributesInDexRewriteInvokeVirtualTest.java
index 6701a25..91c0e74 100644
--- a/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/NestAttributesInDexRewriteInvokeVirtualTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/NestAttributesInDexRewriteInvokeVirtualTest.java
@@ -50,7 +50,7 @@
         parameters.isCfRuntime()
             && parameters.asCfRuntime().isNewerThanOrEqual(CfVm.JDK11)
             && parameters.getApiLevel().isEqualTo(AndroidApiLevel.B));
-    testForJvm()
+    testForJvm(parameters)
         .addProgramClassFileData(dumpHost(), dumpMember1(), dumpMember2())
         .run(parameters.getRuntime(), "Host")
         .assertSuccessWithOutputLines(EXPECTED_OUTPUT_LINES);
@@ -67,7 +67,7 @@
 
   @Test
   public void testD8() throws Exception {
-    assumeTrue(parameters.isDexRuntime());
+    parameters.assumeDexRuntime();
     // TODO(b/247047415): Update test when a DEX VM natively supporting nests is added.
     assertFalse(parameters.getApiLevel().getLevel() > 33);
     testForD8()
diff --git a/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/NestAttributesInDexShrinkingFieldsTest.java b/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/NestAttributesInDexShrinkingFieldsTest.java
index d39faf3..73fdf45 100644
--- a/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/NestAttributesInDexShrinkingFieldsTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/NestAttributesInDexShrinkingFieldsTest.java
@@ -46,7 +46,7 @@
         parameters.isCfRuntime()
             && isRuntimeWithNestSupport(parameters.asCfRuntime())
             && parameters.getApiLevel().isEqualTo(AndroidApiLevel.B));
-    testForJvm()
+    testForJvm(parameters)
         .addProgramClassFileData(
             dumpHost(ACC_PRIVATE), dumpMember1(ACC_PRIVATE), dumpMember2(ACC_PRIVATE))
         .run(parameters.getRuntime(), "Host")
diff --git a/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/NestAttributesInDexShrinkingMethodsTest.java b/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/NestAttributesInDexShrinkingMethodsTest.java
index de46609..03ee74b 100644
--- a/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/NestAttributesInDexShrinkingMethodsTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/NestAttributesInDexShrinkingMethodsTest.java
@@ -45,7 +45,7 @@
         parameters.isCfRuntime()
             && isRuntimeWithNestSupport(parameters.asCfRuntime())
             && parameters.getApiLevel().isEqualTo(AndroidApiLevel.B));
-    testForJvm()
+    testForJvm(parameters)
         .addProgramClassFileData(
             dumpHost(ACC_PRIVATE), dumpMember1(ACC_PRIVATE), dumpMember2(ACC_PRIVATE))
         .run(parameters.getRuntime(), "Host")
diff --git a/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/NestAttributesInDexTest.java b/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/NestAttributesInDexTest.java
index 2267ab4..86d6d0f 100644
--- a/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/NestAttributesInDexTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/NestAttributesInDexTest.java
@@ -82,7 +82,7 @@
         parameters.isCfRuntime()
             && isRuntimeWithNestSupport(parameters.asCfRuntime())
             && parameters.getApiLevel().isEqualTo(AndroidApiLevel.B));
-    testForJvm()
+    testForJvm(parameters)
         .addProgramClassFileData(getTransformedClasses())
         .addProgramClasses(OtherHost.class)
         .run(parameters.getRuntime(), TestClass.class)
@@ -108,8 +108,8 @@
 
   @Test
   public void testD8() throws Exception {
-    assumeTrue(parameters.isDexRuntime());
-    testForD8(parameters.getBackend())
+    parameters.assumeDexRuntime();
+    testForD8()
         .addProgramClassFileData(getTransformedClasses())
         .addProgramClasses(OtherHost.class)
         .setMinApi(parameters)
diff --git a/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/NestLambdaJava17Test.java b/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/NestLambdaJava17Test.java
index 9f883b8..2f9f601 100644
--- a/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/NestLambdaJava17Test.java
+++ b/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/NestLambdaJava17Test.java
@@ -14,26 +14,23 @@
 import com.android.tools.r8.utils.StringUtils;
 import java.nio.file.Path;
 import java.nio.file.Paths;
-import org.junit.Assume;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
 import org.junit.runners.Parameterized.Parameters;
 
 @RunWith(Parameterized.class)
 public class NestLambdaJava17Test extends TestBase {
 
-  public NestLambdaJava17Test(TestParameters parameters) {
-    this.parameters = parameters;
-  }
-
   private static final Path JDK17_JAR =
       Paths.get(ToolHelper.TESTS_BUILD_DIR, "examplesJava17").resolve("nest" + JAR_EXTENSION);
   private static final String MAIN = "nest.NestLambda";
   private static final String EXPECTED_RESULT =
       StringUtils.lines("printed: inner", "printed from itf: here");
 
-  private final TestParameters parameters;
+  @Parameter(0)
+  public TestParameters parameters;
 
   @Parameters(name = "{0}")
   public static TestParametersCollection data() {
@@ -46,8 +43,8 @@
 
   @Test
   public void testReference() throws Exception {
-    Assume.assumeTrue(parameters.isCfRuntime());
-    testForJvm()
+    parameters.assumeJvmTestParameters();
+    testForJvm(parameters)
         .addProgramFiles(JDK17_JAR)
         .run(parameters.getRuntime(), MAIN)
         .assertSuccessWithOutput(EXPECTED_RESULT);
diff --git a/src/test/java/com/android/tools/r8/desugar/records/EmptyRecordAnnotationTest.java b/src/test/java/com/android/tools/r8/desugar/records/EmptyRecordAnnotationTest.java
index 56e1862..b1a21a7 100644
--- a/src/test/java/com/android/tools/r8/desugar/records/EmptyRecordAnnotationTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/records/EmptyRecordAnnotationTest.java
@@ -51,7 +51,7 @@
   @Test
   public void testD8AndJvm() throws Exception {
     if (isDefaultCfParameters()) {
-      testForJvm()
+      testForJvm(parameters)
           .addProgramClassFileData(PROGRAM_DATA)
           .run(parameters.getRuntime(), MAIN_TYPE)
           .assertSuccessWithOutput(EXPECTED_RESULT_CF);
diff --git a/src/test/java/com/android/tools/r8/desugar/records/EmptyRecordTest.java b/src/test/java/com/android/tools/r8/desugar/records/EmptyRecordTest.java
index aee7d34..d4faaf6 100644
--- a/src/test/java/com/android/tools/r8/desugar/records/EmptyRecordTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/records/EmptyRecordTest.java
@@ -50,7 +50,7 @@
   public void testD8AndJvm() throws Exception {
     assumeFalse("Only applicable for R8", enableMinification);
     if (parameters.isCfRuntime()) {
-      testForJvm()
+      testForJvm(parameters)
           .addProgramClassFileData(PROGRAM_DATA)
           .run(parameters.getRuntime(), MAIN_TYPE)
           .assertSuccessWithOutput(EXPECTED_RESULT_D8);
diff --git a/src/test/java/com/android/tools/r8/desugar/records/RecordClasspathTest.java b/src/test/java/com/android/tools/r8/desugar/records/RecordClasspathTest.java
index 2d434ff..8864aa7 100644
--- a/src/test/java/com/android/tools/r8/desugar/records/RecordClasspathTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/records/RecordClasspathTest.java
@@ -69,7 +69,7 @@
   @Test
   public void testD8AndJvm() throws Exception {
     if (parameters.isCfRuntime()) {
-      testForJvm()
+      testForJvm(parameters)
           .addProgramClasses(TestClass.class)
           .addClasspathClassFileData(getClasspathData())
           .run(parameters.getRuntime(), TestClass.class)
diff --git a/src/test/java/com/android/tools/r8/desugar/records/RecordInstanceOfTest.java b/src/test/java/com/android/tools/r8/desugar/records/RecordInstanceOfTest.java
index 860d42a..0a3c852 100644
--- a/src/test/java/com/android/tools/r8/desugar/records/RecordInstanceOfTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/records/RecordInstanceOfTest.java
@@ -41,7 +41,7 @@
   @Test
   public void testD8AndJvm() throws Exception {
     if (parameters.isCfRuntime()) {
-      testForJvm()
+      testForJvm(parameters)
           .addProgramClassFileData(PROGRAM_DATA)
           .run(parameters.getRuntime(), MAIN_TYPE)
           .assertSuccessWithOutput(EXPECTED_RESULT);
diff --git a/src/test/java/com/android/tools/r8/desugar/records/RecordInvokeCustomTest.java b/src/test/java/com/android/tools/r8/desugar/records/RecordInvokeCustomTest.java
index 175ac55..b03856e 100644
--- a/src/test/java/com/android/tools/r8/desugar/records/RecordInvokeCustomTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/records/RecordInvokeCustomTest.java
@@ -58,7 +58,7 @@
   @Test
   public void testD8AndJvm() throws Exception {
     if (parameters.isCfRuntime()) {
-      testForJvm()
+      testForJvm(parameters)
           .addProgramClassFileData(PROGRAM_DATA)
           .run(parameters.getRuntime(), MAIN_TYPE)
           .assertSuccessWithOutput(EXPECTED_RESULT_D8);
diff --git a/src/test/java/com/android/tools/r8/desugar/records/RecordReflectionTest.java b/src/test/java/com/android/tools/r8/desugar/records/RecordReflectionTest.java
index 0e958c7..4d0c926 100644
--- a/src/test/java/com/android/tools/r8/desugar/records/RecordReflectionTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/records/RecordReflectionTest.java
@@ -45,7 +45,8 @@
 
   @Test
   public void testJvm() throws Exception {
-    testForJvm()
+    parameters.assumeJvmTestParameters();
+    testForJvm(parameters)
         .addProgramClassFileData(PROGRAM_DATA)
         .run(parameters.getRuntime(), MAIN_TYPE)
         .assertSuccessWithOutput(EXPECTED_RESULT);
diff --git a/src/test/java/com/android/tools/r8/desugar/records/RecordWithMembersTest.java b/src/test/java/com/android/tools/r8/desugar/records/RecordWithMembersTest.java
index ee83835..5bcdd5e 100644
--- a/src/test/java/com/android/tools/r8/desugar/records/RecordWithMembersTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/records/RecordWithMembersTest.java
@@ -43,7 +43,7 @@
   @Test
   public void testD8AndJvm() throws Exception {
     if (parameters.isCfRuntime()) {
-      testForJvm()
+      testForJvm(parameters)
           .addProgramClassFileData(PROGRAM_DATA)
           .run(parameters.getRuntime(), MAIN_TYPE)
           .assertSuccessWithOutput(EXPECTED_RESULT);
diff --git a/src/test/java/com/android/tools/r8/desugar/records/RecordWithNonMaterializableConstClassTest.java b/src/test/java/com/android/tools/r8/desugar/records/RecordWithNonMaterializableConstClassTest.java
index b83d865..2f60f2a 100644
--- a/src/test/java/com/android/tools/r8/desugar/records/RecordWithNonMaterializableConstClassTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/records/RecordWithNonMaterializableConstClassTest.java
@@ -56,7 +56,7 @@
   }
 
   @Test
-  public void testD8AndJvm() throws Exception {
+  public void testD8() throws Exception {
     testForD8(parameters.getBackend())
         .addProgramClassFileData(PROGRAM_DATA)
         .addProgramClassFileData(EXTRA_DATA)
diff --git a/src/test/java/com/android/tools/r8/desugar/records/SimpleRecordTest.java b/src/test/java/com/android/tools/r8/desugar/records/SimpleRecordTest.java
index 1b217b7..7dbeae0 100644
--- a/src/test/java/com/android/tools/r8/desugar/records/SimpleRecordTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/records/SimpleRecordTest.java
@@ -48,7 +48,7 @@
   @Test
   public void testReference() throws Exception {
     assumeTrue(isCfRuntimeWithNativeRecordSupport());
-    testForJvm()
+    testForJvm(parameters)
         .addProgramClassFileData(PROGRAM_DATA)
         .run(parameters.getRuntime(), MAIN_TYPE)
         .assertSuccessWithOutput(EXPECTED_RESULT);
diff --git a/src/test/java/com/android/tools/r8/desugar/records/UnusedRecordFieldTest.java b/src/test/java/com/android/tools/r8/desugar/records/UnusedRecordFieldTest.java
index beee05f..e845260 100644
--- a/src/test/java/com/android/tools/r8/desugar/records/UnusedRecordFieldTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/records/UnusedRecordFieldTest.java
@@ -7,12 +7,13 @@
 import com.android.tools.r8.R8FullTestBuilder;
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
 import com.android.tools.r8.TestRuntime.CfVm;
 import com.android.tools.r8.utils.StringUtils;
-import java.util.List;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
 
 @RunWith(Parameterized.class)
 public class UnusedRecordFieldTest extends TestBase {
@@ -22,30 +23,29 @@
   private static final String MAIN_TYPE = RecordTestUtils.getMainType(RECORD_NAME);
   private static final String EXPECTED_RESULT = StringUtils.lines("Hello!");
 
-  private final TestParameters parameters;
-
-  public UnusedRecordFieldTest(TestParameters parameters) {
-    this.parameters = parameters;
-  }
+  @Parameter(0)
+  public TestParameters parameters;
 
   @Parameterized.Parameters(name = "{0}")
-  public static List<Object[]> data() {
-    return buildParameters(
-        getTestParameters()
-            .withCfRuntimesStartingFromIncluding(CfVm.JDK17)
-            .withDexRuntimes()
-            .withAllApiLevelsAlsoForCf()
-            .build());
+  public static TestParametersCollection data() {
+    return getTestParameters()
+        .withCfRuntimesStartingFromIncluding(CfVm.JDK17)
+        .withDexRuntimes()
+        .withAllApiLevelsAlsoForCf()
+        .build();
   }
 
   @Test
-  public void testD8AndJvm() throws Exception {
-    if (parameters.isCfRuntime()) {
-      testForJvm()
-          .addProgramClassFileData(PROGRAM_DATA)
-          .run(parameters.getRuntime(), MAIN_TYPE)
-          .assertSuccessWithOutput(EXPECTED_RESULT);
+  public void testJvm() throws Exception {
+    parameters.assumeJvmTestParameters();
+    testForJvm(parameters)
+        .addProgramClassFileData(PROGRAM_DATA)
+        .run(parameters.getRuntime(), MAIN_TYPE)
+        .assertSuccessWithOutput(EXPECTED_RESULT);
     }
+
+  @Test
+  public void testD8() throws Exception {
     testForD8(parameters.getBackend())
         .addProgramClassFileData(PROGRAM_DATA)
         .setMinApi(parameters)
diff --git a/src/test/java/com/android/tools/r8/desugar/records/UnusedRecordMethodTest.java b/src/test/java/com/android/tools/r8/desugar/records/UnusedRecordMethodTest.java
index 89d4717..e78d25b 100644
--- a/src/test/java/com/android/tools/r8/desugar/records/UnusedRecordMethodTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/records/UnusedRecordMethodTest.java
@@ -7,12 +7,14 @@
 import com.android.tools.r8.R8FullTestBuilder;
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
 import com.android.tools.r8.TestRuntime.CfVm;
 import com.android.tools.r8.utils.StringUtils;
-import java.util.List;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
 
 @RunWith(Parameterized.class)
 public class UnusedRecordMethodTest extends TestBase {
@@ -22,30 +24,29 @@
   private static final String MAIN_TYPE = RecordTestUtils.getMainType(RECORD_NAME);
   private static final String EXPECTED_RESULT = StringUtils.lines("Hello!");
 
-  private final TestParameters parameters;
+  @Parameter(0)
+  public TestParameters parameters;
 
-  public UnusedRecordMethodTest(TestParameters parameters) {
-    this.parameters = parameters;
-  }
-
-  @Parameterized.Parameters(name = "{0}")
-  public static List<Object[]> data() {
-    return buildParameters(
-        getTestParameters()
-            .withCfRuntimesStartingFromIncluding(CfVm.JDK17)
-            .withDexRuntimes()
-            .withAllApiLevelsAlsoForCf()
-            .build());
+  @Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters()
+        .withCfRuntimesStartingFromIncluding(CfVm.JDK17)
+        .withDexRuntimes()
+        .withAllApiLevelsAlsoForCf()
+        .build();
   }
 
   @Test
-  public void testD8AndJvm() throws Exception {
-    if (parameters.isCfRuntime()) {
-      testForJvm()
-          .addProgramClassFileData(PROGRAM_DATA)
-          .run(parameters.getRuntime(), MAIN_TYPE)
-          .assertSuccessWithOutput(EXPECTED_RESULT);
+  public void testJvm() throws Exception {
+    parameters.assumeJvmTestParameters();
+    testForJvm(parameters)
+        .addProgramClassFileData(PROGRAM_DATA)
+        .run(parameters.getRuntime(), MAIN_TYPE)
+        .assertSuccessWithOutput(EXPECTED_RESULT);
     }
+
+  @Test
+  public void testD8() throws Exception {
     testForD8(parameters.getBackend())
         .addProgramClassFileData(PROGRAM_DATA)
         .setMinApi(parameters)
diff --git a/src/test/java/com/android/tools/r8/desugar/records/UnusedRecordReflectionTest.java b/src/test/java/com/android/tools/r8/desugar/records/UnusedRecordReflectionTest.java
index 71973f5..9dba59e 100644
--- a/src/test/java/com/android/tools/r8/desugar/records/UnusedRecordReflectionTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/records/UnusedRecordReflectionTest.java
@@ -7,12 +7,14 @@
 import com.android.tools.r8.R8FullTestBuilder;
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
 import com.android.tools.r8.TestRuntime.CfVm;
 import com.android.tools.r8.utils.StringUtils;
-import java.util.List;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
 
 @RunWith(Parameterized.class)
 public class UnusedRecordReflectionTest extends TestBase {
@@ -22,30 +24,29 @@
   private static final String MAIN_TYPE = RecordTestUtils.getMainType(RECORD_NAME);
   private static final String EXPECTED_RESULT = StringUtils.lines("null", "null");
 
-  private final TestParameters parameters;
+  @Parameter(0)
+  public TestParameters parameters;
 
-  public UnusedRecordReflectionTest(TestParameters parameters) {
-    this.parameters = parameters;
-  }
-
-  @Parameterized.Parameters(name = "{0}")
-  public static List<Object[]> data() {
-    return buildParameters(
-        getTestParameters()
-            .withCfRuntimesStartingFromIncluding(CfVm.JDK17)
-            .withDexRuntimes()
-            .withAllApiLevelsAlsoForCf()
-            .build());
+  @Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters()
+        .withCfRuntimesStartingFromIncluding(CfVm.JDK17)
+        .withDexRuntimes()
+        .withAllApiLevelsAlsoForCf()
+        .build();
   }
 
   @Test
   public void testD8AndJvm() throws Exception {
-    if (parameters.isCfRuntime()) {
-      testForJvm()
-          .addProgramClassFileData(PROGRAM_DATA)
-          .run(parameters.getRuntime(), MAIN_TYPE)
-          .assertSuccessWithOutput(EXPECTED_RESULT);
+    parameters.assumeJvmTestParameters();
+    testForJvm(parameters)
+        .addProgramClassFileData(PROGRAM_DATA)
+        .run(parameters.getRuntime(), MAIN_TYPE)
+        .assertSuccessWithOutput(EXPECTED_RESULT);
     }
+
+  @Test
+  public void testD8() throws Exception {
     testForD8(parameters.getBackend())
         .addProgramClassFileData(PROGRAM_DATA)
         .setMinApi(parameters)
diff --git a/src/test/java/com/android/tools/r8/desugar/sealed/PermittedSubclassesAttributeInDexTest.java b/src/test/java/com/android/tools/r8/desugar/sealed/PermittedSubclassesAttributeInDexTest.java
index 458c593..c940038 100644
--- a/src/test/java/com/android/tools/r8/desugar/sealed/PermittedSubclassesAttributeInDexTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/sealed/PermittedSubclassesAttributeInDexTest.java
@@ -47,7 +47,7 @@
         parameters.isCfRuntime()
             && parameters.asCfRuntime().isNewerThanOrEqual(CfVm.JDK17)
             && parameters.getApiLevel().isEqualTo(AndroidApiLevel.B));
-    testForJvm()
+    testForJvm(parameters)
         .addProgramClassFileData(getTransformedClasses())
         .addProgramClasses(Sub1.class, Sub2.class)
         .run(parameters.getRuntime(), TestClass.class)
@@ -64,8 +64,8 @@
 
   @Test
   public void testD8() throws Exception {
-    assumeTrue(parameters.isDexRuntime());
-    testForD8(parameters.getBackend())
+    parameters.assumeDexRuntime();
+    testForD8()
         .addProgramClassFileData(getTransformedClasses())
         .addProgramClasses(Sub1.class, Sub2.class)
         .setMinApi(parameters)
diff --git a/src/test/java/com/android/tools/r8/desugar/sealed/SealedAttributeClasspathTest.java b/src/test/java/com/android/tools/r8/desugar/sealed/SealedAttributeClasspathTest.java
index 54e3117..f9a504c 100644
--- a/src/test/java/com/android/tools/r8/desugar/sealed/SealedAttributeClasspathTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/sealed/SealedAttributeClasspathTest.java
@@ -4,7 +4,6 @@
 
 package com.android.tools.r8.desugar.sealed;
 
-import static org.junit.Assume.assumeTrue;
 
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestCompilerBuilder;
@@ -40,7 +39,7 @@
 
   @Test
   public void testD8() throws Exception {
-    assumeTrue(parameters.isDexRuntime());
+    parameters.assumeDexRuntime();
     runTest(testForD8(parameters.getBackend()));
   }
 
diff --git a/src/test/java/com/android/tools/r8/desugar/sealed/SealedAttributeLibraryTest.java b/src/test/java/com/android/tools/r8/desugar/sealed/SealedAttributeLibraryTest.java
index bf78e04..ab44ceb 100644
--- a/src/test/java/com/android/tools/r8/desugar/sealed/SealedAttributeLibraryTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/sealed/SealedAttributeLibraryTest.java
@@ -4,7 +4,6 @@
 
 package com.android.tools.r8.desugar.sealed;
 
-import static org.junit.Assume.assumeTrue;
 
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestCompilerBuilder;
@@ -41,7 +40,7 @@
 
   @Test
   public void testD8() throws Exception {
-    assumeTrue(parameters.isDexRuntime());
+    parameters.assumeDexRuntime();
     runTest(testForD8(parameters.getBackend()));
   }
 
diff --git a/src/test/java/com/android/tools/r8/desugar/sealed/SealedAttributeTest.java b/src/test/java/com/android/tools/r8/desugar/sealed/SealedAttributeTest.java
index afce761..9aae17a 100644
--- a/src/test/java/com/android/tools/r8/desugar/sealed/SealedAttributeTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/sealed/SealedAttributeTest.java
@@ -40,7 +40,7 @@
   @Test
   public void testJvm() throws Exception {
     assumeTrue(parameters.isCfRuntime() && parameters.asCfRuntime().isNewerThanOrEqual(CfVm.JDK17));
-    testForJvm()
+    testForJvm(parameters)
         .addRunClasspathFiles(Sealed.jar())
         .run(parameters.getRuntime(), Sealed.Main.typeName())
         .assertSuccessWithOutput(EXPECTED);
diff --git a/src/test/java/com/android/tools/r8/desugar/twr/CheckTwrOutputForJavaCompilersTest.java b/src/test/java/com/android/tools/r8/desugar/twr/CheckTwrOutputForJavaCompilersTest.java
index baf39e2..cc6a5ca 100644
--- a/src/test/java/com/android/tools/r8/desugar/twr/CheckTwrOutputForJavaCompilersTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/twr/CheckTwrOutputForJavaCompilersTest.java
@@ -56,7 +56,7 @@
         javac(parameters.getRuntime().asCf())
             .addSourceFiles(ToolHelper.getSourceFileForTestClass(TwrTestSource.class))
             .compile();
-    testForJvm()
+    testForJvm(parameters)
         .addProgramFiles(javacOut)
         .run(parameters.getRuntime(), TwrTestSource.class)
         .assertSuccessWithOutput(EXPECTED)
diff --git a/src/test/java/com/android/tools/r8/desugar/twr/TwrCloseResourceDuplicationTest.java b/src/test/java/com/android/tools/r8/desugar/twr/TwrCloseResourceDuplicationTest.java
index 04021e6..78a7fb7 100644
--- a/src/test/java/com/android/tools/r8/desugar/twr/TwrCloseResourceDuplicationTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/twr/TwrCloseResourceDuplicationTest.java
@@ -84,8 +84,8 @@
 
   @Test
   public void testJvm() throws Exception {
-    assumeTrue(parameters.isCfRuntime());
-    testForJvm()
+    parameters.assumeJvmTestParameters();
+    testForJvm(parameters)
         .addProgramFiles(getProgramInputs())
         .run(parameters.getRuntime(), MAIN.typeName(), getZipFile())
         .assertSuccessWithOutput(EXPECTED);
diff --git a/src/test/java/com/android/tools/r8/desugaring/interfacemethods/DefaultInterfaceMethodDesugaringImpossibleTest.java b/src/test/java/com/android/tools/r8/desugaring/interfacemethods/DefaultInterfaceMethodDesugaringImpossibleTest.java
index a1c258a..3be277e 100644
--- a/src/test/java/com/android/tools/r8/desugaring/interfacemethods/DefaultInterfaceMethodDesugaringImpossibleTest.java
+++ b/src/test/java/com/android/tools/r8/desugaring/interfacemethods/DefaultInterfaceMethodDesugaringImpossibleTest.java
@@ -6,7 +6,6 @@
 import static org.hamcrest.CoreMatchers.containsString;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
-import static org.junit.Assume.assumeTrue;
 
 import com.android.tools.r8.CompilationFailedException;
 import com.android.tools.r8.TestBase;
@@ -56,8 +55,8 @@
 
   @Test
   public void testJVM() throws Exception {
-    assumeTrue(parameters.isCfRuntime());
-    testForJvm()
+    parameters.assumeJvmTestParameters();
+    testForJvm(parameters)
         .addProgramClasses(getProgramClasses())
         .addProgramClassFileData(getProgramClassData())
         .run(parameters.getRuntime(), TestClass.class)
@@ -66,7 +65,7 @@
 
   @Test
   public void testD8() throws Exception {
-    assumeTrue(parameters.isDexRuntime());
+    parameters.assumeDexRuntime();
     try {
       testForD8()
           .addProgramClasses(getProgramClasses())
diff --git a/src/test/java/com/android/tools/r8/desugaring/interfacemethods/DefaultInterfaceMethodDesugaringWithPrivateStaticResolutionTest.java b/src/test/java/com/android/tools/r8/desugaring/interfacemethods/DefaultInterfaceMethodDesugaringWithPrivateStaticResolutionTest.java
index 7e653d3..49d8b4b 100644
--- a/src/test/java/com/android/tools/r8/desugaring/interfacemethods/DefaultInterfaceMethodDesugaringWithPrivateStaticResolutionTest.java
+++ b/src/test/java/com/android/tools/r8/desugaring/interfacemethods/DefaultInterfaceMethodDesugaringWithPrivateStaticResolutionTest.java
@@ -3,7 +3,6 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.desugaring.interfacemethods;
 
-import static org.junit.Assume.assumeTrue;
 
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
@@ -32,8 +31,8 @@
 
   @Test
   public void testJVM() throws Exception {
-    assumeTrue(parameters.isCfRuntime());
-    testForJvm()
+    parameters.assumeJvmTestParameters();
+    testForJvm(parameters)
         .addTestClasspath()
         .run(parameters.getRuntime(), TestClass.class)
         .assertSuccessWithOutput(EXPECTED);
@@ -41,7 +40,7 @@
 
   @Test
   public void testD8() throws Exception {
-    assumeTrue(parameters.isDexRuntime());
+    parameters.assumeDexRuntime();
     testForD8()
         .addInnerClasses(DefaultInterfaceMethodDesugaringWithPrivateStaticResolutionTest.class)
         .setMinApi(parameters)
diff --git a/src/test/java/com/android/tools/r8/desugaring/interfacemethods/DefaultInterfaceMethodDesugaringWithPublicStaticResolutionOnClassTest.java b/src/test/java/com/android/tools/r8/desugaring/interfacemethods/DefaultInterfaceMethodDesugaringWithPublicStaticResolutionOnClassTest.java
index 1a905b1..01dd9df 100644
--- a/src/test/java/com/android/tools/r8/desugaring/interfacemethods/DefaultInterfaceMethodDesugaringWithPublicStaticResolutionOnClassTest.java
+++ b/src/test/java/com/android/tools/r8/desugaring/interfacemethods/DefaultInterfaceMethodDesugaringWithPublicStaticResolutionOnClassTest.java
@@ -4,7 +4,6 @@
 package com.android.tools.r8.desugaring.interfacemethods;
 
 import static org.junit.Assert.assertTrue;
-import static org.junit.Assume.assumeTrue;
 
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
@@ -54,8 +53,8 @@
 
   @Test
   public void testJVM() throws Exception {
-    assumeTrue(parameters.isCfRuntime());
-    testForJvm()
+    parameters.assumeJvmTestParameters();
+    testForJvm(parameters)
         .addProgramClasses(getProgramClasses())
         .addProgramClassFileData(getProgramClassData())
         .run(parameters.getRuntime(), TestClass.class)
diff --git a/src/test/java/com/android/tools/r8/desugaring/interfacemethods/DefaultInterfaceMethodDesugaringWithPublicStaticResolutionTest.java b/src/test/java/com/android/tools/r8/desugaring/interfacemethods/DefaultInterfaceMethodDesugaringWithPublicStaticResolutionTest.java
index 2bfef83..2ebb188 100644
--- a/src/test/java/com/android/tools/r8/desugaring/interfacemethods/DefaultInterfaceMethodDesugaringWithPublicStaticResolutionTest.java
+++ b/src/test/java/com/android/tools/r8/desugaring/interfacemethods/DefaultInterfaceMethodDesugaringWithPublicStaticResolutionTest.java
@@ -4,7 +4,6 @@
 package com.android.tools.r8.desugaring.interfacemethods;
 
 import static org.junit.Assert.assertTrue;
-import static org.junit.Assume.assumeTrue;
 
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
@@ -51,8 +50,8 @@
 
   @Test
   public void testJVM() throws Exception {
-    assumeTrue(parameters.isCfRuntime());
-    testForJvm()
+    parameters.assumeJvmTestParameters();
+    testForJvm(parameters)
         .addProgramClasses(getProgramClasses())
         .addProgramClassFileData(getProgramClassData())
         .run(parameters.getRuntime(), TestClass.class)
diff --git a/src/test/java/com/android/tools/r8/desugaring/interfacemethods/InvokeSuperInDefaultInterfaceMethodTest.java b/src/test/java/com/android/tools/r8/desugaring/interfacemethods/InvokeSuperInDefaultInterfaceMethodTest.java
index b15c928..b80cfb8 100644
--- a/src/test/java/com/android/tools/r8/desugaring/interfacemethods/InvokeSuperInDefaultInterfaceMethodTest.java
+++ b/src/test/java/com/android/tools/r8/desugaring/interfacemethods/InvokeSuperInDefaultInterfaceMethodTest.java
@@ -7,26 +7,48 @@
 import com.android.tools.r8.NeverClassInline;
 import com.android.tools.r8.NoVerticalClassMerging;
 import com.android.tools.r8.TestBase;
-import com.android.tools.r8.utils.AndroidApiLevel;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
 import com.android.tools.r8.utils.StringUtils;
 import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
 
+@RunWith(Parameterized.class)
 public class InvokeSuperInDefaultInterfaceMethodTest extends TestBase {
 
+  private static final String EXPECTED_OUTPUT =
+      StringUtils.lines("I.m()", "J.m()", "JImpl.m()", "I.m()", "KImpl.m()");
+
+  @Parameter(0)
+  public TestParameters parameters;
+
+  @Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withAllRuntimesAndApiLevels().build();
+  }
+
   @Test
-  public void test() throws Exception {
-    String expectedOutput = StringUtils.lines("I.m()", "J.m()", "JImpl.m()", "I.m()", "KImpl.m()");
+  public void testJvm() throws Exception {
+    parameters.assumeJvmTestParameters();
+    testForJvm(parameters)
+        .addTestClasspath()
+        .run(parameters.getRuntime(), TestClass.class)
+        .assertSuccessWithOutput(EXPECTED_OUTPUT);
+  }
 
-    testForJvm().addTestClasspath().run(TestClass.class).assertSuccessWithOutput(expectedOutput);
-
-    testForR8(Backend.DEX)
+  @Test
+  public void testR8() throws Exception {
+    testForR8(parameters.getBackend())
         .addInnerClasses(InvokeSuperInDefaultInterfaceMethodTest.class)
         .addKeepMainRule(TestClass.class)
         .enableNeverClassInliningAnnotations()
         .enableNoVerticalClassMergingAnnotations()
-        .setMinApi(AndroidApiLevel.M)
-        .run(TestClass.class)
-        .assertSuccessWithOutput(expectedOutput);
+        .setMinApi(parameters)
+        .run(parameters.getRuntime(), TestClass.class)
+        .assertSuccessWithOutput(EXPECTED_OUTPUT);
   }
 
   static class TestClass {
diff --git a/src/test/java/com/android/tools/r8/desugaring/interfacemethods/MethodParametersTest.java b/src/test/java/com/android/tools/r8/desugaring/interfacemethods/MethodParametersTest.java
index 828e2ce..ecf5c8d 100644
--- a/src/test/java/com/android/tools/r8/desugaring/interfacemethods/MethodParametersTest.java
+++ b/src/test/java/com/android/tools/r8/desugaring/interfacemethods/MethodParametersTest.java
@@ -73,8 +73,8 @@
 
   @Test
   public void testJvm() throws Exception {
-    assumeTrue(parameters.isCfRuntime());
-    testForJvm()
+    parameters.assumeJvmTestParameters();
+    testForJvm(parameters)
         .addProgramFiles(compiledWithParameters.get())
         .addInnerClasses(getClass())
         .run(parameters.getRuntime(), TestRunner.class)
diff --git a/src/test/java/com/android/tools/r8/dex/whitespaceinidentifiers/WhiteSpaceInIdentifiersTest.java b/src/test/java/com/android/tools/r8/dex/whitespaceinidentifiers/WhiteSpaceInIdentifiersTest.java
index 070867d..c3b55fe 100644
--- a/src/test/java/com/android/tools/r8/dex/whitespaceinidentifiers/WhiteSpaceInIdentifiersTest.java
+++ b/src/test/java/com/android/tools/r8/dex/whitespaceinidentifiers/WhiteSpaceInIdentifiersTest.java
@@ -214,7 +214,7 @@
   @Test
   public void testJvmStackTrace() throws Exception {
     parameters.assumeCfRuntime();
-    testForJvm()
+    testForJvm(parameters)
         .addProgramClassFileData(getTransformed())
         .run(parameters.asCfRuntime(), TestClass.class, "some-argument")
         .assertFailureWithErrorThatThrows(RuntimeException.class)
diff --git a/src/test/java/com/android/tools/r8/enumunboxing/EnumWithNonDefaultForwardingConstructorTest.java b/src/test/java/com/android/tools/r8/enumunboxing/EnumWithNonDefaultForwardingConstructorTest.java
index 67dd73e..8cd9479 100644
--- a/src/test/java/com/android/tools/r8/enumunboxing/EnumWithNonDefaultForwardingConstructorTest.java
+++ b/src/test/java/com/android/tools/r8/enumunboxing/EnumWithNonDefaultForwardingConstructorTest.java
@@ -5,7 +5,6 @@
 package com.android.tools.r8.enumunboxing;
 
 import static org.junit.Assume.assumeFalse;
-import static org.junit.Assume.assumeTrue;
 
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestBuilder;
@@ -38,8 +37,8 @@
   @Test
   public void testJvm() throws Exception {
     assumeFalse(enableEnumUnboxing);
-    assumeTrue(parameters.isCfRuntime());
-    testForJvm()
+    parameters.assumeJvmTestParameters();
+    testForJvm(parameters)
         .apply(this::addProgramClasses)
         .run(parameters.getRuntime(), TestClass.class)
         .assertSuccessWithOutputLines("42");
diff --git a/src/test/java/com/android/tools/r8/files/AarInputTest.java b/src/test/java/com/android/tools/r8/files/AarInputTest.java
index f712f17..bf37add 100644
--- a/src/test/java/com/android/tools/r8/files/AarInputTest.java
+++ b/src/test/java/com/android/tools/r8/files/AarInputTest.java
@@ -47,7 +47,7 @@
   @Test
   public void allowAarProgramInputD8() throws Exception {
     if (parameters.isCfRuntime()) {
-      testForJvm()
+      testForJvm(parameters)
           .addProgramClasses(TestClass.class)
           .run(parameters.getRuntime(), TestClass.class)
           .assertSuccessWithOutputLines("Hello!");
diff --git a/src/test/java/com/android/tools/r8/graph/MethodWithoutCodeAttributeTest.java b/src/test/java/com/android/tools/r8/graph/MethodWithoutCodeAttributeTest.java
index cc67424..fe1bdad 100644
--- a/src/test/java/com/android/tools/r8/graph/MethodWithoutCodeAttributeTest.java
+++ b/src/test/java/com/android/tools/r8/graph/MethodWithoutCodeAttributeTest.java
@@ -53,7 +53,7 @@
   @Test
   public void testJVMOutput() throws Exception {
     parameters.assumeJvmTestParameters();
-    testForJvm()
+    testForJvm(parameters)
         .addProgramClassFileData(TestDump.dump())
         .run(parameters.getRuntime(), MAIN)
         .assertFailureWithErrorThatMatches(
diff --git a/src/test/java/com/android/tools/r8/graph/genericsignature/GenericSignatureKeepReferencesPruneTest.java b/src/test/java/com/android/tools/r8/graph/genericsignature/GenericSignatureKeepReferencesPruneTest.java
index 082fece..575bb5f 100644
--- a/src/test/java/com/android/tools/r8/graph/genericsignature/GenericSignatureKeepReferencesPruneTest.java
+++ b/src/test/java/com/android/tools/r8/graph/genericsignature/GenericSignatureKeepReferencesPruneTest.java
@@ -51,10 +51,10 @@
 
   @Test
   public void testJvm() throws Exception {
-    assumeTrue(parameters.isCfRuntime());
+    parameters.assumeJvmTestParameters();
     assumeTrue(isCompat);
     assumeTrue(!minify);
-    testForJvm()
+    testForJvm(parameters)
         .addProgramClasses(I.class, Foo.class, J.class, K.class, L.class)
         .addProgramClassesAndInnerClasses(Main.class)
         .run(parameters.getRuntime(), Main.class)
diff --git a/src/test/java/com/android/tools/r8/graph/genericsignature/GenericSignatureStaticMethodTest.java b/src/test/java/com/android/tools/r8/graph/genericsignature/GenericSignatureStaticMethodTest.java
index 90e9febe..9d549b9 100644
--- a/src/test/java/com/android/tools/r8/graph/genericsignature/GenericSignatureStaticMethodTest.java
+++ b/src/test/java/com/android/tools/r8/graph/genericsignature/GenericSignatureStaticMethodTest.java
@@ -41,8 +41,8 @@
 
   @Test
   public void testJvm() throws Exception {
-    assumeTrue(parameters.isCfRuntime());
-    testForJvm()
+    parameters.assumeJvmTestParameters();
+    testForJvm(parameters)
         .addProgramClassFileData(
             transformer(Main.class)
                 .removeInnerClasses()
diff --git a/src/test/java/com/android/tools/r8/graph/invokespecial/InvokeSpecialToVirtualMethodTest.java b/src/test/java/com/android/tools/r8/graph/invokespecial/InvokeSpecialToVirtualMethodTest.java
index 1b26ce0..adaf1fb 100644
--- a/src/test/java/com/android/tools/r8/graph/invokespecial/InvokeSpecialToVirtualMethodTest.java
+++ b/src/test/java/com/android/tools/r8/graph/invokespecial/InvokeSpecialToVirtualMethodTest.java
@@ -4,9 +4,7 @@
 package com.android.tools.r8.graph.invokespecial;
 
 import static com.android.tools.r8.utils.DescriptorUtils.getBinaryNameFromJavaType;
-import static org.hamcrest.CoreMatchers.containsString;
 import static org.junit.Assert.assertEquals;
-import static org.junit.Assume.assumeTrue;
 
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
@@ -37,8 +35,8 @@
 
   @Test
   public void testJvm() throws Exception {
-    assumeTrue(parameters.isCfRuntime());
-    testForJvm()
+    parameters.assumeJvmTestParameters();
+    testForJvm(parameters)
         .addProgramClasses(Base.class, Bar.class, TestClass.class)
         .addProgramClassFileData(getFooTransform())
         .run(parameters.getRuntime(), TestClass.class)
@@ -47,7 +45,7 @@
 
   @Test
   public void testD8() throws Exception {
-    assumeTrue(parameters.isDexRuntime());
+    parameters.assumeDexRuntime();
     testForD8()
         .addProgramClasses(Base.class, Bar.class, TestClass.class)
         .addProgramClassFileData(getFooTransform())
diff --git a/src/test/java/com/android/tools/r8/graph/invokevirtual/InvokeVirtualPrivateBaseWithDefaultDirectInvokeTest.java b/src/test/java/com/android/tools/r8/graph/invokevirtual/InvokeVirtualPrivateBaseWithDefaultDirectInvokeTest.java
index bc49ff9..ff40c0a 100644
--- a/src/test/java/com/android/tools/r8/graph/invokevirtual/InvokeVirtualPrivateBaseWithDefaultDirectInvokeTest.java
+++ b/src/test/java/com/android/tools/r8/graph/invokevirtual/InvokeVirtualPrivateBaseWithDefaultDirectInvokeTest.java
@@ -39,7 +39,7 @@
   @Test
   public void testJvm() throws Exception {
     assumeTrue(isDefaultCfParameters());
-    testForJvm()
+    testForJvm(parameters)
         .addInnerClasses(getClass())
         .run(parameters.getRuntime(), Main.class)
         .apply(r -> assertResultIsCorrect(r, true));
diff --git a/src/test/java/com/android/tools/r8/graph/invokevirtual/InvokeVirtualPrivateBaseWithDefaultTest.java b/src/test/java/com/android/tools/r8/graph/invokevirtual/InvokeVirtualPrivateBaseWithDefaultTest.java
index eb63443..8638616 100644
--- a/src/test/java/com/android/tools/r8/graph/invokevirtual/InvokeVirtualPrivateBaseWithDefaultTest.java
+++ b/src/test/java/com/android/tools/r8/graph/invokevirtual/InvokeVirtualPrivateBaseWithDefaultTest.java
@@ -4,7 +4,6 @@
 
 package com.android.tools.r8.graph.invokevirtual;
 
-import static org.junit.Assume.assumeTrue;
 
 import com.android.tools.r8.NoVerticalClassMerging;
 import com.android.tools.r8.TestBase;
@@ -32,8 +31,8 @@
 
   @Test
   public void testJvm() throws Exception {
-    assumeTrue(parameters.isCfRuntime());
-    testForJvm()
+    parameters.assumeJvmTestParameters();
+    testForJvm(parameters)
         .addInnerClasses(getClass())
         .run(parameters.getRuntime(), Main.class)
         .assertFailureWithErrorThatThrows(IllegalAccessError.class);
diff --git a/src/test/java/com/android/tools/r8/inspection/FieldFlagsAndValueInspectionTest.java b/src/test/java/com/android/tools/r8/inspection/FieldFlagsAndValueInspectionTest.java
index 304594c..38e7f99 100644
--- a/src/test/java/com/android/tools/r8/inspection/FieldFlagsAndValueInspectionTest.java
+++ b/src/test/java/com/android/tools/r8/inspection/FieldFlagsAndValueInspectionTest.java
@@ -38,7 +38,7 @@
   @Test
   public void testD8() throws Exception {
     if (parameters.isCfRuntime()) {
-      testForJvm()
+      testForJvm(parameters)
           .addProgramClasses(TestClass.class)
           .run(parameters.getRuntime(), TestClass.class)
           .assertSuccessWithOutput(EXPECTED);
diff --git a/src/test/java/com/android/tools/r8/inspection/FieldValueTypesInspectionTest.java b/src/test/java/com/android/tools/r8/inspection/FieldValueTypesInspectionTest.java
index 5726780..0f78402 100644
--- a/src/test/java/com/android/tools/r8/inspection/FieldValueTypesInspectionTest.java
+++ b/src/test/java/com/android/tools/r8/inspection/FieldValueTypesInspectionTest.java
@@ -47,7 +47,7 @@
   @Test
   public void testD8() throws Exception {
     if (parameters.isCfRuntime()) {
-      testForJvm()
+      testForJvm(parameters)
           .addProgramClasses(TestClass.class)
           .run(parameters.getRuntime(), TestClass.class)
           .assertSuccessWithOutput(EXPECTED);
diff --git a/src/test/java/com/android/tools/r8/inspection/InspectionApiTest.java b/src/test/java/com/android/tools/r8/inspection/InspectionApiTest.java
index e419668..6359c80 100644
--- a/src/test/java/com/android/tools/r8/inspection/InspectionApiTest.java
+++ b/src/test/java/com/android/tools/r8/inspection/InspectionApiTest.java
@@ -41,7 +41,7 @@
   @Test
   public void testD8() throws Exception {
     if (parameters.isCfRuntime()) {
-      testForJvm()
+      testForJvm(parameters)
           .addProgramClasses(TestClass.class)
           .run(parameters.getRuntime(), TestClass.class)
           .assertSuccessWithOutput(EXPECTED);
diff --git a/src/test/java/com/android/tools/r8/internal/Regression127524985.java b/src/test/java/com/android/tools/r8/internal/Regression127524985.java
index 62134d4..229ce71 100644
--- a/src/test/java/com/android/tools/r8/internal/Regression127524985.java
+++ b/src/test/java/com/android/tools/r8/internal/Regression127524985.java
@@ -44,8 +44,8 @@
 
   @Test
   public void testJvm() throws Throwable {
-    assumeTrue(parameters.isCfRuntime());
-    testForJvm()
+    parameters.assumeJvmTestParameters();
+    testForJvm(parameters)
         .addClasspath(JAR)
         .run(parameters.getRuntime(), MAIN)
         .assertSuccessWithOutput(EXPECTED);
diff --git a/src/test/java/com/android/tools/r8/ir/analysis/type/ConstrainedPrimitiveTypeTest.java b/src/test/java/com/android/tools/r8/ir/analysis/type/ConstrainedPrimitiveTypeTest.java
index fbb1c3d..693fb24 100644
--- a/src/test/java/com/android/tools/r8/ir/analysis/type/ConstrainedPrimitiveTypeTest.java
+++ b/src/test/java/com/android/tools/r8/ir/analysis/type/ConstrainedPrimitiveTypeTest.java
@@ -23,11 +23,15 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
 
 @RunWith(Parameterized.class)
 public class ConstrainedPrimitiveTypeTest extends AnalysisTestBase {
 
-  @Parameterized.Parameters(name = "{0}")
+  private static final String EXPECTED_OUTPUT =
+      StringUtils.lines("1", "2", "3", "1.0", "1.0", "2.0", "1", "1", "2", "1.0", "1.0", "2.0");
+
+  @Parameters(name = "{0}")
   public static TestParametersCollection data() {
     return getTestParameters().withAllRuntimesAndApiLevels().build();
   }
@@ -37,19 +41,23 @@
   }
 
   @Test
-  public void testOutput() throws Exception {
-    String expectedOutput =
-        StringUtils.lines("1", "2", "3", "1.0", "1.0", "2.0", "1", "1", "2", "1.0", "1.0", "2.0");
+  public void testJvmOutput() throws Exception {
+    parameters.assumeJvmTestParameters();
+    testForJvm(parameters)
+        .addTestClasspath()
+        .run(parameters.getRuntime(), TestClass.class)
+        .assertSuccessWithOutput(EXPECTED_OUTPUT);
+  }
 
-    testForJvm().addTestClasspath().run(TestClass.class).assertSuccessWithOutput(expectedOutput);
-
+  @Test
+  public void testR8Output() throws Exception {
     testForR8(parameters.getBackend())
         .addInnerClasses(ConstrainedPrimitiveTypeTest.class)
         .addKeepMainRule(TestClass.class)
         .enableInliningAnnotations()
         .setMinApi(parameters)
         .run(parameters.getRuntime(), TestClass.class)
-        .assertSuccessWithOutput(expectedOutput);
+        .assertSuccessWithOutput(EXPECTED_OUTPUT);
   }
 
   @Test
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/AlwaysThrowNullTest.java b/src/test/java/com/android/tools/r8/ir/optimize/AlwaysThrowNullTest.java
index a21c174..fcf8304 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/AlwaysThrowNullTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/AlwaysThrowNullTest.java
@@ -178,7 +178,7 @@
   @Test
   public void testJvmOutput() throws Exception {
     parameters.assumeJvmTestParameters();
-    testForJvm()
+    testForJvm(parameters)
         .addTestClasspath()
         .run(parameters.getRuntime(), MAIN)
         .assertSuccessWithOutput(JAVA_OUTPUT);
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/B116282409.java b/src/test/java/com/android/tools/r8/ir/optimize/B116282409.java
index bb59573..e706afa 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/B116282409.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/B116282409.java
@@ -5,20 +5,15 @@
 package com.android.tools.r8.ir.optimize;
 
 import static org.hamcrest.CoreMatchers.containsString;
-import static org.hamcrest.MatcherAssert.assertThat;
-import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotEquals;
 
 import com.android.tools.r8.CompilationFailedException;
-import com.android.tools.r8.ToolHelper;
-import com.android.tools.r8.ToolHelper.DexVm;
-import com.android.tools.r8.ToolHelper.ProcessResult;
+import com.android.tools.r8.R8TestCompileResult;
+import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.jasmin.JasminBuilder;
 import com.android.tools.r8.jasmin.JasminBuilder.ClassBuilder;
 import com.android.tools.r8.jasmin.JasminTestBase;
 import com.android.tools.r8.utils.AbortException;
-import com.android.tools.r8.utils.AndroidApp;
 import com.android.tools.r8.utils.BooleanUtils;
 import com.google.common.collect.ImmutableList;
 import java.util.Arrays;
@@ -27,34 +22,36 @@
 import java.util.stream.Collectors;
 import org.hamcrest.BaseMatcher;
 import org.hamcrest.Description;
+import org.junit.BeforeClass;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.rules.ExpectedException;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
 import org.junit.runners.Parameterized.Parameters;
 
 @RunWith(Parameterized.class)
 public class B116282409 extends JasminTestBase {
 
-  private final Backend backend;
+  private static List<byte[]> programClassFileData;
 
-  private final boolean enableVerticalClassMerging;
+  @Parameter(0)
+  public TestParameters parameters;
+
+  @Parameter(1)
+  public boolean enableVerticalClassMerging;
 
   @Rule public ExpectedException exception = ExpectedException.none();
 
-  @Parameters(name = "Backend: {0}, vertical class merging: {1}")
+  @Parameters(name = "{0}, vertical class merging: {1}")
   public static Collection<Object[]> data() {
-    return buildParameters(ToolHelper.getBackends(), BooleanUtils.values());
+    return buildParameters(
+        getTestParameters().withAllRuntimesAndApiLevels().build(), BooleanUtils.values());
   }
 
-  public B116282409(Backend backend, boolean enableVerticalClassMerging) {
-    this.backend = backend;
-    this.enableVerticalClassMerging = enableVerticalClassMerging;
-  }
-
-  @Test
-  public void test() throws Exception {
+  @BeforeClass
+  public static void setup() throws Exception {
     JasminBuilder jasminBuilder = new JasminBuilder();
 
     // Create a class A with a default constructor that prints "In A.<init>()".
@@ -93,7 +90,21 @@
         "invokevirtual java/io/PrintStream/println(I)V",
         "return");
 
-    // Build app.
+    programClassFileData = jasminBuilder.buildClasses();
+  }
+
+  @Test
+  public void testJvm() throws Exception {
+    parameters.assumeJvmTestParameters();
+    testForJvm(parameters)
+        .addProgramClassFileData(programClassFileData)
+        .run(parameters.getRuntime(), "TestClass")
+        .assertFailureWithErrorThatThrows(VerifyError.class)
+        .assertFailureWithErrorThatMatches(containsString("Call to wrong initialization method"));
+  }
+
+  @Test
+  public void testR8() throws Exception {
     if (enableVerticalClassMerging) {
       exception.expect(CompilationFailedException.class);
       exception.expectCause(
@@ -104,40 +115,36 @@
                   + "`-keep,allowobfuscation class A`."));
     }
 
-    AndroidApp output =
-        compileWithR8(
-            jasminBuilder.build(),
-            keepMainProguardConfiguration("TestClass"),
-            options -> options.enableVerticalClassMerging = enableVerticalClassMerging,
-            backend);
+    R8TestCompileResult compileResult =
+        testForR8(parameters.getBackend())
+            .addProgramClassFileData(programClassFileData)
+            .addKeepMainRule("TestClass")
+            .addOptionsModification(
+                options -> options.enableVerticalClassMerging = enableVerticalClassMerging)
+            .allowDiagnosticWarningMessages()
+            .setMinApi(parameters)
+            .compile();
+
     assertFalse(enableVerticalClassMerging);
 
-    // Run app.
-    ProcessResult vmResult = runOnVMRaw(output, "TestClass", backend);
-    if (backend == Backend.CF) {
-      // Verify that the input code does not run with java.
-      ProcessResult javaResult = runOnJavaRaw(jasminBuilder, "TestClass");
-      assertNotEquals(0, javaResult.exitCode);
-      assertThat(javaResult.stderr, containsString("VerifyError"));
-      assertThat(javaResult.stderr, containsString("Call to wrong initialization method"));
-
-      // The same should be true for the generated program.
-      assertNotEquals(0, vmResult.exitCode);
-      assertThat(vmResult.stderr, containsString("VerifyError"));
-      assertThat(vmResult.stderr, containsString("Call to wrong initialization method"));
-    } else {
-      assert backend == Backend.DEX;
-      if (ToolHelper.getDexVm().isOlderThanOrEqual(DexVm.ART_4_4_4_HOST)) {
-        assertNotEquals(0, vmResult.exitCode);
-        assertThat(
-            vmResult.stderr,
-            containsString("VFY: invoke-direct <init> on super only allowed for 'this' in <init>"));
-      } else {
-        assertEquals(0, vmResult.exitCode);
-        assertEquals(
-            String.join(System.lineSeparator(), "In A.<init>()", "42", ""), vmResult.stdout);
-      }
-    }
+    compileResult
+        .run(parameters.getRuntime(), "TestClass")
+        .applyIf(
+            parameters.isCfRuntime(),
+            runResult ->
+                runResult
+                    .assertFailureWithErrorThatThrows(VerifyError.class)
+                    .assertFailureWithErrorThatMatches(
+                        containsString("Call to wrong initialization method")),
+            runResult -> {
+              if (parameters.getDexRuntimeVersion().isDalvik()) {
+                runResult.assertFailureWithErrorThatMatches(
+                    containsString(
+                        "VFY: invoke-direct <init> on super only allowed for 'this' in <init>"));
+              } else {
+                runResult.assertSuccessWithOutputLines("In A.<init>()", "42");
+              }
+            });
   }
 
   private static class CustomExceptionMatcher extends BaseMatcher<Throwable> {
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/B132749793.java b/src/test/java/com/android/tools/r8/ir/optimize/B132749793.java
index 34f0d16..ef5e847 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/B132749793.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/B132749793.java
@@ -3,7 +3,6 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.ir.optimize;
 
-import static org.junit.Assume.assumeTrue;
 
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
@@ -41,10 +40,10 @@
 
   @Test
   public void testJvm() throws Exception {
-    assumeTrue(parameters.isCfRuntime());
-    testForJvm()
-        .addProgramClasses(TestB132749793.class, InterfaceWithStaticAndDefault.class,
-            HasStaticField.class)
+    parameters.assumeJvmTestParameters();
+    testForJvm(parameters)
+        .addProgramClasses(
+            TestB132749793.class, InterfaceWithStaticAndDefault.class, HasStaticField.class)
         .run(parameters.getRuntime(), TestB132749793.class)
         .assertSuccessWithOutputLines(EXPECTED);
   }
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/CatchHandlerRemovalTest.java b/src/test/java/com/android/tools/r8/ir/optimize/CatchHandlerRemovalTest.java
index 14fc7af..3f336fd 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/CatchHandlerRemovalTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/CatchHandlerRemovalTest.java
@@ -5,38 +5,45 @@
 
 import com.android.tools.r8.NeverInline;
 import com.android.tools.r8.TestBase;
-import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
 import org.junit.runners.Parameterized.Parameters;
 
 @RunWith(Parameterized.class)
 public class CatchHandlerRemovalTest extends TestBase {
 
-  private final Backend backend;
+  private static final String EXPECTED_OUTPUT = "In TestClass.method()";
 
-  @Parameters(name = "Backend: {0}")
-  public static Backend[] data() {
-    return ToolHelper.getBackends();
-  }
+  @Parameter(0)
+  public TestParameters parameters;
 
-  public CatchHandlerRemovalTest(Backend backend) {
-    this.backend = backend;
+  @Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withAllRuntimesAndApiLevels().build();
   }
 
   @Test
-  public void test() throws Exception {
-    String expected = "In TestClass.method()";
+  public void testJvm() throws Exception {
+    parameters.assumeJvmTestParameters();
+    testForJvm(parameters)
+        .addTestClasspath()
+        .run(parameters.getRuntime(), TestClass.class)
+        .assertSuccessWithOutput(EXPECTED_OUTPUT);
+  }
 
-    testForJvm().addTestClasspath().run(TestClass.class).assertSuccessWithOutput(expected);
-
-    testForR8(backend)
+  @Test
+  public void testR8() throws Exception {
+    testForR8(parameters.getBackend())
         .addInnerClasses(CatchHandlerRemovalTest.class)
         .addKeepMainRule(TestClass.class)
         .enableInliningAnnotations()
-        .run(TestClass.class)
-        .assertSuccessWithOutput(expected)
+        .setMinApi(parameters)
+        .run(parameters.getRuntime(), TestClass.class)
+        .assertSuccessWithOutput(EXPECTED_OUTPUT)
         .inspector();
   }
 
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/InterfaceClInit.java b/src/test/java/com/android/tools/r8/ir/optimize/InterfaceClInit.java
index 151425d..f9b82bb 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/InterfaceClInit.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/InterfaceClInit.java
@@ -3,7 +3,6 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.ir.optimize;
 
-import static org.junit.Assume.assumeTrue;
 
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
@@ -38,8 +37,8 @@
 
   @Test
   public void testJvm() throws Exception {
-    assumeTrue(parameters.isCfRuntime());
-    testForJvm()
+    parameters.assumeJvmTestParameters();
+    testForJvm(parameters)
         .addProgramClasses(TestClass.class, InterfaceWithStaticBlock.class, UsedFromStatic.class)
         .run(parameters.getRuntime(), TestClass.class)
         .assertSuccessWithOutputLines(EXPECTED);
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/ObjectsRequireNonNullTest.java b/src/test/java/com/android/tools/r8/ir/optimize/ObjectsRequireNonNullTest.java
index 0b1fa3e..7f82bcf 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/ObjectsRequireNonNullTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/ObjectsRequireNonNullTest.java
@@ -60,7 +60,7 @@
   @Test
   public void testJvmOutput() throws Exception {
     parameters.assumeJvmTestParameters();
-    testForJvm()
+    testForJvm(parameters)
         .addTestClasspath()
         .run(parameters.getRuntime(), MAIN)
         .assertSuccessWithOutput(JAVA_OUTPUT);
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/RedundantConstNumberRemovalTest.java b/src/test/java/com/android/tools/r8/ir/optimize/RedundantConstNumberRemovalTest.java
index d23e107..d50fb21 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/RedundantConstNumberRemovalTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/RedundantConstNumberRemovalTest.java
@@ -56,7 +56,10 @@
             "true", "true", "true", "true", "true");
 
     if (parameters.getBackend() == Backend.CF) {
-      testForJvm().addTestClasspath().run(TestClass.class).assertSuccessWithOutput(expectedOutput);
+      testForJvm(parameters)
+          .addTestClasspath()
+          .run(TestClass.class)
+          .assertSuccessWithOutput(expectedOutput);
     }
 
     R8TestRunResult result =
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/SubsumedCatchHandlerTest.java b/src/test/java/com/android/tools/r8/ir/optimize/SubsumedCatchHandlerTest.java
index 0134f78..ba0d275 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/SubsumedCatchHandlerTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/SubsumedCatchHandlerTest.java
@@ -11,7 +11,8 @@
 
 import com.android.tools.r8.NeverInline;
 import com.android.tools.r8.TestBase;
-import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
 import com.android.tools.r8.cf.code.CfTryCatch;
 import com.android.tools.r8.graph.CfCode;
 import com.android.tools.r8.graph.Code;
@@ -24,11 +25,14 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
 import org.junit.runners.Parameterized.Parameters;
 
 @RunWith(Parameterized.class)
 public class SubsumedCatchHandlerTest extends TestBase {
 
+  private static final String EXPECTED = "In bar() -> 0";
+
   static class TestClass {
 
     public static void main(String[] args) {
@@ -64,30 +68,33 @@
     }
   }
 
-  @Parameters(name = "Backend: {0}")
-  public static Backend[] data() {
-    return ToolHelper.getBackends();
+  @Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withAllRuntimesAndApiLevels().build();
   }
 
-  private final Backend backend;
+  @Parameter(0)
+  public TestParameters parameters;
 
-  public SubsumedCatchHandlerTest(Backend backend) {
-    this.backend = backend;
+  @Test
+  public void testJvm() throws Exception {
+    parameters.assumeJvmTestParameters();
+    testForJvm(parameters)
+        .addTestClasspath()
+        .run(parameters.getRuntime(), TestClass.class)
+        .assertSuccessWithOutput(EXPECTED);
   }
 
   @Test
-  public void test() throws Exception {
-    String expected = "In bar() -> 0";
-
-    testForJvm().addTestClasspath().run(TestClass.class).assertSuccessWithOutput(expected);
-
+  public void testR8() throws Exception {
     CodeInspector inspector =
-        testForR8(backend)
+        testForR8(parameters.getBackend())
             .addInnerClasses(SubsumedCatchHandlerTest.class)
             .addKeepMainRule(TestClass.class)
             .enableInliningAnnotations()
-            .run(TestClass.class)
-            .assertSuccessWithOutput(expected)
+            .setMinApi(parameters)
+            .run(parameters.getRuntime(), TestClass.class)
+            .assertSuccessWithOutput(EXPECTED)
             .inspector();
 
     ClassSubject classSubject = inspector.clazz(TestClass.class);
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/canonicalization/ConstClassCanonicalizationTest.java b/src/test/java/com/android/tools/r8/ir/optimize/canonicalization/ConstClassCanonicalizationTest.java
index 4544be5..059d0b7 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/canonicalization/ConstClassCanonicalizationTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/canonicalization/ConstClassCanonicalizationTest.java
@@ -116,7 +116,7 @@
   public void testJVMOutput() throws Exception {
     assumeTrue(isCompat);
     parameters.assumeJvmTestParameters();
-    testForJvm()
+    testForJvm(parameters)
         .addTestClasspath()
         .run(parameters.getRuntime(), MAIN)
         .assertSuccessWithOutput(JAVA_OUTPUT);
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/canonicalization/DexItemBasedConstStringCanonicalizationTest.java b/src/test/java/com/android/tools/r8/ir/optimize/canonicalization/DexItemBasedConstStringCanonicalizationTest.java
index 6a48915..a8bd35a 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/canonicalization/DexItemBasedConstStringCanonicalizationTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/canonicalization/DexItemBasedConstStringCanonicalizationTest.java
@@ -63,7 +63,7 @@
     assumeTrue(
         "Only run JVM reference on CF runtimes",
         parameters.isCfRuntime() && !enableMinification);
-    testForJvm()
+    testForJvm(parameters)
         .addTestClasspath()
         .run(parameters.getRuntime(), MAIN)
         .assertSuccessWithOutput(JAVA_OUTPUT);
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/checkcast/ArrayInterfaceArrayCheckCastTest.java b/src/test/java/com/android/tools/r8/ir/optimize/checkcast/ArrayInterfaceArrayCheckCastTest.java
index 607c30a..aadda8e 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/checkcast/ArrayInterfaceArrayCheckCastTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/checkcast/ArrayInterfaceArrayCheckCastTest.java
@@ -3,7 +3,6 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.ir.optimize.checkcast;
 
-import static org.junit.Assume.assumeTrue;
 
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
@@ -32,8 +31,8 @@
 
   @Test
   public void testD8() throws Exception {
-    assumeTrue(parameters.isDexRuntime());
-    testForD8(parameters.getBackend())
+    parameters.assumeDexRuntime();
+    testForD8()
         .addInnerClasses(getClass())
         .setMinApi(parameters)
         .run(parameters.getRuntime(), TestClass.class)
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/checkcast/CheckCastRemovalTest.java b/src/test/java/com/android/tools/r8/ir/optimize/checkcast/CheckCastRemovalTest.java
index 21a8719..9b65830 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/checkcast/CheckCastRemovalTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/checkcast/CheckCastRemovalTest.java
@@ -3,41 +3,32 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.ir.optimize.checkcast;
 
-import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
 
-import com.android.tools.r8.ToolHelper;
-import com.android.tools.r8.ToolHelper.ProcessResult;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
 import com.android.tools.r8.jasmin.JasminBuilder;
 import com.android.tools.r8.jasmin.JasminBuilder.ClassBuilder;
 import com.android.tools.r8.jasmin.JasminTestBase;
-import com.android.tools.r8.naming.MemberNaming.MethodSignature;
-import com.android.tools.r8.utils.AndroidApp;
 import com.android.tools.r8.utils.codeinspector.InstructionSubject;
 import com.android.tools.r8.utils.codeinspector.MethodSubject;
-import com.google.common.collect.ImmutableList;
-import java.io.IOException;
-import java.util.Collections;
-import java.util.Iterator;
-import java.util.List;
-import java.util.concurrent.ExecutionException;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
 
 @RunWith(Parameterized.class)
 public class CheckCastRemovalTest extends JasminTestBase {
 
-  @Parameterized.Parameters(name = "Backend: {0}")
-  public static Backend[] data() {
-    return ToolHelper.getBackends();
-  }
+  private static final String CLASS_NAME = "Example";
 
-  private final Backend backend;
-  private final String CLASS_NAME = "Example";
+  @Parameter(0)
+  public TestParameters parameters;
 
-  public CheckCastRemovalTest(Backend backend) {
-    this.backend = backend;
+  @Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withAllRuntimesAndApiLevels().build();
   }
 
   @Test
@@ -45,7 +36,7 @@
     JasminBuilder builder = new JasminBuilder();
     ClassBuilder classBuilder = builder.addClass(CLASS_NAME);
     classBuilder.addDefaultConstructor();
-    MethodSignature main = classBuilder.addMainMethod(
+    classBuilder.addMainMethod(
         ".limit stack 3",
         ".limit locals 1",
         "new Example",
@@ -54,13 +45,14 @@
         "checkcast Example", // Gone
         "return");
 
-    List<String> pgConfigs = ImmutableList.of(
-        "-keep class " + CLASS_NAME + " { *; }",
-        "-dontshrink");
-    AndroidApp app = compileWithR8(builder, pgConfigs, o -> o.enableClassInlining = false, backend);
-
-    checkCheckCasts(app, main, null);
-    checkRuntime(builder, app, CLASS_NAME);
+    testForR8(parameters.getBackend())
+        .addProgramClassFileData(builder.buildClasses())
+        .addKeepMainRule(CLASS_NAME)
+        .setMinApi(parameters)
+        .compile()
+        .inspect(inspector -> checkCheckCasts(inspector.clazz(CLASS_NAME).mainMethod()))
+        .run(parameters.getRuntime(), CLASS_NAME)
+        .assertSuccessWithEmptyOutput();
   }
 
   @Test
@@ -74,7 +66,7 @@
     ClassBuilder a = builder.addClass("A", "B");
     a.addDefaultConstructor();
     ClassBuilder classBuilder = builder.addClass(CLASS_NAME);
-    MethodSignature main = classBuilder.addMainMethod(
+    classBuilder.addMainMethod(
         ".limit stack 3",
         ".limit locals 1",
         "new A",
@@ -84,24 +76,21 @@
         "checkcast C", // Gone
         "return");
 
-    List<String> pgConfigs = ImmutableList.of(
-        "-keep class " + CLASS_NAME + " { *; }",
-        "-keep class A { *; }",
-        "-keep class B { *; }",
-        "-keep class C { *; }",
-        "-dontshrink");
-    AndroidApp app =
-        compileWithR8(builder, pgConfigs, opts -> opts.enableClassInlining = false, backend);
-
-    checkCheckCasts(app, main, null);
-    checkRuntime(builder, app, CLASS_NAME);
+    testForR8(parameters.getBackend())
+        .addProgramClassFileData(builder.buildClasses())
+        .addKeepClassAndMembersRules(CLASS_NAME, "A", "B", "C")
+        .setMinApi(parameters)
+        .compile()
+        .inspect(inspector -> checkCheckCasts(inspector.clazz(CLASS_NAME).mainMethod()))
+        .run(parameters.getRuntime(), CLASS_NAME)
+        .assertSuccessWithEmptyOutput();
   }
 
   @Test
   public void bothUpAndDowncast() throws Exception {
     JasminBuilder builder = new JasminBuilder();
     ClassBuilder classBuilder = builder.addClass(CLASS_NAME);
-    MethodSignature main = classBuilder.addMainMethod(
+    classBuilder.addMainMethod(
         ".limit stack 4",
         ".limit locals 1",
         "iconst_1",
@@ -110,21 +99,22 @@
         "iconst_0",
         "ldc \"a string\"",
         "aastore",
-        "checkcast [Ljava/lang/Object;",  // This upcast can be removed.
+        "checkcast [Ljava/lang/Object;", // This upcast can be removed.
         "iconst_0",
         "aaload",
-        "checkcast java/lang/String",  // Then, this downcast can be removed, too.
+        "checkcast java/lang/String", // Then, this downcast can be removed, too.
         "invokevirtual java/lang/String/length()I",
         "return");
+
     // That is, both checkcasts should be removed together or kept together.
-
-    List<String> pgConfigs = ImmutableList.of(
-        "-keep class " + CLASS_NAME + " { *; }",
-        "-dontshrink");
-    AndroidApp app = compileWithR8(builder, pgConfigs, null, backend);
-
-    checkCheckCasts(app, main, null);
-    checkRuntime(builder, app, CLASS_NAME);
+    testForR8(parameters.getBackend())
+        .addProgramClassFileData(builder.buildClasses())
+        .addKeepMainRule(CLASS_NAME)
+        .setMinApi(parameters)
+        .compile()
+        .inspect(inspector -> checkCheckCasts(inspector.clazz(CLASS_NAME).mainMethod()))
+        .run(parameters.getRuntime(), CLASS_NAME)
+        .assertSuccessWithEmptyOutput();
   }
 
   @Test
@@ -132,7 +122,7 @@
     JasminBuilder builder = new JasminBuilder();
     ClassBuilder classBuilder = builder.addClass(CLASS_NAME);
     classBuilder.addField("public", "fld", "Ljava/lang/String;", null);
-    MethodSignature main = classBuilder.addMainMethod(
+    classBuilder.addMainMethod(
         ".limit stack 3",
         ".limit locals 1",
         "aconst_null",
@@ -140,65 +130,17 @@
         "getfield Example.fld Ljava/lang/String;",
         "return");
 
-    List<String> pgConfigs = ImmutableList.of(
-        "-keep class " + CLASS_NAME + " { *; }",
-        "-dontshrink");
-    AndroidApp app = compileWithR8(builder, pgConfigs, null, backend);
-
-    checkCheckCasts(app, main, null);
-    checkRuntimeException(builder, app, CLASS_NAME, "NullPointerException");
+    testForR8(parameters.getBackend())
+        .addProgramClassFileData(builder.buildClasses())
+        .addKeepClassAndMembersRules(CLASS_NAME)
+        .setMinApi(parameters)
+        .compile()
+        .inspect(inspector -> checkCheckCasts(inspector.clazz(CLASS_NAME).mainMethod()))
+        .run(parameters.getRuntime(), CLASS_NAME)
+        .assertFailureWithErrorThatThrows(NullPointerException.class);
   }
 
-  private void checkCheckCasts(AndroidApp app, MethodSignature main, String maybeType)
-      throws ExecutionException, IOException {
-    MethodSubject method = getMethodSubject(app, CLASS_NAME, main);
-    assertTrue(method.isPresent());
-
-    // Make sure there is only a single CheckCast with specified type, or no CheckCasts (if
-    // maybeType == null).
-    Iterator<InstructionSubject> iterator = method.iterateInstructions();
-    boolean found = maybeType == null;
-    while (iterator.hasNext()) {
-      InstructionSubject instruction = iterator.next();
-      if (!instruction.isCheckCast()) {
-        continue;
-      }
-      assertTrue(!found && instruction.isCheckCast(maybeType));
-      found = true;
-    }
-    assertTrue(found);
-  }
-
-  private void checkRuntime(JasminBuilder builder, AndroidApp app, String className)
-      throws Exception {
-    String normalOutput = runOnJava(builder, className);
-    String optimizedOutput;
-    if (backend == Backend.DEX) {
-      optimizedOutput = runOnArt(app, className);
-    } else {
-      assert backend == Backend.CF;
-      optimizedOutput = runOnJava(app, className);
-    }
-    assertEquals(normalOutput, optimizedOutput);
-  }
-
-  private void checkRuntimeException(
-      JasminBuilder builder, AndroidApp app, String className, String exceptionName)
-      throws Exception {
-    ProcessResult javaOutput = runOnJavaRaw(builder, className);
-    assertEquals(1, javaOutput.exitCode);
-    assertTrue(javaOutput.stderr.contains(exceptionName));
-
-    ProcessResult output;
-
-    if (backend == Backend.DEX) {
-      output = runOnArtRaw(app, className);
-    } else {
-      assert backend == Backend.CF;
-      output = runOnJavaRaw(app, className, Collections.emptyList());
-    }
-
-    assertEquals(1, output.exitCode);
-    assertTrue(output.stderr.contains(exceptionName));
+  private void checkCheckCasts(MethodSubject method) {
+    assertTrue(method.streamInstructions().noneMatch(InstructionSubject::isCheckCast));
   }
 }
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/checkcast/IllegalAccessErrorTest.java b/src/test/java/com/android/tools/r8/ir/optimize/checkcast/IllegalAccessErrorTest.java
index 2687c27..a77b5bb 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/checkcast/IllegalAccessErrorTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/checkcast/IllegalAccessErrorTest.java
@@ -3,17 +3,14 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.ir.optimize.checkcast;
 
-import static org.junit.Assert.assertEquals;
-
 import com.android.tools.r8.AsmTestBase;
-import com.android.tools.r8.ToolHelper;
-import com.android.tools.r8.ToolHelper.ProcessResult;
-import com.android.tools.r8.utils.AndroidApp;
-import com.google.common.collect.ImmutableList;
-import java.util.List;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
 
 class NonAccessible {
   // because it's package-private
@@ -21,43 +18,41 @@
 
 @RunWith(Parameterized.class)
 public class IllegalAccessErrorTest extends AsmTestBase {
-  private final Backend backend;
 
-  @Parameterized.Parameters(name = "backend: {0}")
-  public static Backend[] data() {
-    return ToolHelper.getBackends();
-  }
+  private static final String EXPECTED_OUTPUT = "null";
+  private static final String MAIN = "Test";
 
+  @Parameter(0)
+  public TestParameters parameters;
 
-  public IllegalAccessErrorTest(Backend backend) {
-    this.backend = backend;
+  @Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withAllRuntimesAndApiLevels().build();
   }
 
   @Test
-  public void runTest() throws Exception {
-    String main = "Test";
-    AndroidApp input =
-        buildAndroidApp(
-            IllegalAccessErrorTestDump.dump(),
-            ToolHelper.getClassAsBytes(NonAccessible.class));
-    AndroidApp processedApp =
-        compileWithR8(input, keepMainProguardConfiguration(main), null, backend);
+  public void testJvm() throws Exception {
+    parameters.assumeJvmTestParameters();
+    testForJvm(parameters)
+        .addProgramClasses(NonAccessible.class)
+        .addProgramClassFileData(IllegalAccessErrorTestDump.dump())
+        .run(parameters.getRuntime(), MAIN)
+        .assertSuccessWithOutputLines(EXPECTED_OUTPUT);
+  }
 
-    List<byte[]> classBytes = ImmutableList.of(
-        IllegalAccessErrorTestDump.dump(),
-        ToolHelper.getClassAsBytes(NonAccessible.class)
-    );
-    ProcessResult javaOutput = runOnJavaRaw(main, classBytes, ImmutableList.of());
-    assertEquals(0, javaOutput.exitCode);
-
-    ProcessResult output = runOnVMRaw(processedApp, main, backend);
-    assertEquals(0, output.exitCode);
-    if (backend == Backend.DEX) {
-      assertEquals(IllegalAccessErrorTestDump.MESSAGE, output.stdout.trim());
-    } else {
-      assert backend == Backend.CF;
-      assertEquals(javaOutput.stdout.trim(), output.stdout.trim());
-      assertEquals("null", output.stdout.trim());
-    }
+  @Test
+  public void testR8() throws Exception {
+    testForR8(parameters.getBackend())
+        .addProgramClasses(NonAccessible.class)
+        .addProgramClassFileData(IllegalAccessErrorTestDump.dump())
+        .addKeepMainRule(MAIN)
+        .setMinApi(parameters)
+        .compile()
+        .run(parameters.getRuntime(), MAIN)
+        .applyIf(
+            parameters.isCfRuntime(),
+            runResult -> runResult.assertSuccessWithOutputLines(EXPECTED_OUTPUT),
+            runResult ->
+                runResult.assertSuccessWithOutputLines(IllegalAccessErrorTestDump.MESSAGE));
   }
 }
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/checkcast/InterfaceArrayCheckCastTest.java b/src/test/java/com/android/tools/r8/ir/optimize/checkcast/InterfaceArrayCheckCastTest.java
index 4899ef2..e3cface 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/checkcast/InterfaceArrayCheckCastTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/checkcast/InterfaceArrayCheckCastTest.java
@@ -3,7 +3,6 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.ir.optimize.checkcast;
 
-import static org.junit.Assume.assumeTrue;
 
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
@@ -32,8 +31,8 @@
 
   @Test
   public void testD8() throws Exception {
-    assumeTrue(parameters.isDexRuntime());
-    testForD8(parameters.getBackend())
+    parameters.assumeDexRuntime();
+    testForD8()
         .addInnerClasses(getClass())
         .setMinApi(parameters)
         .run(parameters.getRuntime(), TestClass.class)
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/checkcast/NullCheckCastTest.java b/src/test/java/com/android/tools/r8/ir/optimize/checkcast/NullCheckCastTest.java
index 587936a..90f093e 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/checkcast/NullCheckCastTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/checkcast/NullCheckCastTest.java
@@ -6,23 +6,21 @@
 import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
 import static org.hamcrest.CoreMatchers.not;
 import static org.hamcrest.MatcherAssert.assertThat;
-import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
 
 import com.android.tools.r8.TestBase;
-import com.android.tools.r8.ToolHelper;
-import com.android.tools.r8.ToolHelper.ProcessResult;
-import com.android.tools.r8.utils.AndroidApp;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
 import com.android.tools.r8.utils.codeinspector.ClassSubject;
 import com.android.tools.r8.utils.codeinspector.CodeInspector;
 import com.android.tools.r8.utils.codeinspector.InstructionSubject;
 import com.android.tools.r8.utils.codeinspector.MethodSubject;
-import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Streams;
-import java.util.List;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
 
 class NullCheckCastTestMain {
   public static void main(String[] args) {
@@ -38,36 +36,38 @@
 
 @RunWith(Parameterized.class)
 public class NullCheckCastTest extends TestBase {
-  private final Backend backend;
 
-  @Parameterized.Parameters(name = "backend: {0}")
-  public static Backend[] data() {
-    return ToolHelper.getBackends();
-  }
+  private static final String EXPECTED_OUTPUT = "null";
 
-  public NullCheckCastTest(Backend backend) {
-    this.backend = backend;
+  @Parameter(0)
+  public TestParameters parameters;
+
+  @Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withAllRuntimesAndApiLevels().build();
   }
 
   @Test
-  public void runTest() throws Exception {
-    AndroidApp app = readClasses(Base.class, SubClass.class, NullCheckCastTestMain.class);
-    AndroidApp processedApp = compileWithR8(
-        app, keepMainProguardConfiguration(NullCheckCastTestMain.class), null, backend);
+  public void testJvm() throws Exception {
+    parameters.assumeJvmTestParameters();
+    testForJvm(parameters)
+        .addProgramClasses(Base.class, SubClass.class, NullCheckCastTestMain.class)
+        .run(parameters.getRuntime(), NullCheckCastTestMain.class)
+        .assertSuccessWithOutputLines(EXPECTED_OUTPUT);
+  }
 
-    List<byte[]> classBytes = ImmutableList.of(
-        ToolHelper.getClassAsBytes(Base.class),
-        ToolHelper.getClassAsBytes(SubClass.class),
-        ToolHelper.getClassAsBytes(NullCheckCastTestMain.class)
-    );
-    String main = NullCheckCastTestMain.class.getCanonicalName();
-    ProcessResult javaOutput = runOnJavaRaw(main, classBytes, ImmutableList.of());
-    assertEquals(0, javaOutput.exitCode);
-    ProcessResult output = runOnVMRaw(processedApp, main, backend);
-    assertEquals(0, output.exitCode);
-    assertEquals(javaOutput.stdout.trim(), output.stdout.trim());
+  @Test
+  public void testR8() throws Exception {
+    CodeInspector inspector =
+        testForR8(parameters.getBackend())
+            .addProgramClasses(Base.class, SubClass.class, NullCheckCastTestMain.class)
+            .addKeepMainRule(NullCheckCastTestMain.class)
+            .setMinApi(parameters)
+            .compile()
+            .run(parameters.getRuntime(), NullCheckCastTestMain.class)
+            .assertSuccessWithOutputLines(EXPECTED_OUTPUT)
+            .inspector();
 
-    CodeInspector inspector = new CodeInspector(processedApp);
     ClassSubject mainSubject = inspector.clazz(NullCheckCastTestMain.class);
     assertThat(mainSubject, isPresent());
     MethodSubject mainMethod = mainSubject.mainMethod();
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/checkcast/TrivialArrayCheckCastTest.java b/src/test/java/com/android/tools/r8/ir/optimize/checkcast/TrivialArrayCheckCastTest.java
index c885a62..25ba251 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/checkcast/TrivialArrayCheckCastTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/checkcast/TrivialArrayCheckCastTest.java
@@ -6,37 +6,59 @@
 
 import com.android.tools.r8.NeverInline;
 import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
 import com.android.tools.r8.utils.AndroidApiLevel;
 import com.android.tools.r8.utils.InternalOptions;
 import com.android.tools.r8.utils.StringUtils;
 import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
 
 /** Regression test for b/123269162. */
+@RunWith(Parameterized.class)
 public class TrivialArrayCheckCastTest extends TestBase {
 
+  private static final String EXPECTED_OUTPUT =
+      StringUtils.lines(
+          "Caught NullPointerException", "Caught NullPointerException",
+          "Caught NullPointerException", "Caught NullPointerException",
+          "Caught NullPointerException", "Caught NullPointerException",
+          "Caught NullPointerException", "Caught NullPointerException",
+          "Caught NullPointerException", "Caught NullPointerException");
+
+  @Parameter(0)
+  public TestParameters parameters;
+
+  @Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withAllRuntimesAndApiLevels().build();
+  }
+
   @Test
-  public void test() throws Exception {
-    String expectedOutput =
-        StringUtils.lines(
-            "Caught NullPointerException", "Caught NullPointerException",
-            "Caught NullPointerException", "Caught NullPointerException",
-            "Caught NullPointerException", "Caught NullPointerException",
-            "Caught NullPointerException", "Caught NullPointerException",
-            "Caught NullPointerException", "Caught NullPointerException");
+  public void testJvm() throws Exception {
+    parameters.assumeJvmTestParameters();
+    testForJvm(parameters)
+        .addTestClasspath()
+        .run(parameters.getRuntime(), TestClass.class)
+        .assertSuccessWithOutput(EXPECTED_OUTPUT);
+  }
 
-    testForJvm().addTestClasspath().run(TestClass.class).assertSuccessWithOutput(expectedOutput);
-
+  @Test
+  public void testR8() throws Exception {
     InternalOptions options = new InternalOptions();
     options.setMinApiLevel(AndroidApiLevel.I_MR1);
     assert options.canHaveArtCheckCastVerifierBug();
 
-    testForR8(Backend.DEX)
+    testForR8(parameters.getBackend())
         .addInnerClasses(TrivialArrayCheckCastTest.class)
         .addKeepMainRule(TestClass.class)
         .enableInliningAnnotations()
-        .setMinApi(AndroidApiLevel.I_MR1)
-        .run(TestClass.class)
-        .assertSuccessWithOutput(expectedOutput);
+        .setMinApi(parameters)
+        .run(parameters.getRuntime(), TestClass.class)
+        .assertSuccessWithOutput(EXPECTED_OUTPUT);
   }
 
   static class TestClass {
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/classinliner/ClassInlinerTupleBuilderConstructorsTest.java b/src/test/java/com/android/tools/r8/ir/optimize/classinliner/ClassInlinerTupleBuilderConstructorsTest.java
index f4c6c2c..29618d5 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/classinliner/ClassInlinerTupleBuilderConstructorsTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/classinliner/ClassInlinerTupleBuilderConstructorsTest.java
@@ -8,7 +8,6 @@
 import static org.hamcrest.CoreMatchers.not;
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.junit.Assert.assertEquals;
-import static org.junit.Assume.assumeTrue;
 
 import com.android.tools.r8.AlwaysClassInline;
 import com.android.tools.r8.TestParameters;
@@ -56,8 +55,8 @@
 
   @Test
   public void testJVM() throws Exception {
-    assumeTrue(parameters.isCfRuntime());
-    testForJvm()
+    parameters.assumeJvmTestParameters();
+    testForJvm(parameters)
         .addTestClasspath()
         .run(parameters.getRuntime(), TestClass.class)
         .assertSuccessWithOutput(EXPECTED);
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/fields/NonFinalFinalFieldTest.java b/src/test/java/com/android/tools/r8/ir/optimize/fields/NonFinalFinalFieldTest.java
index 4303c5d..ab7067f 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/fields/NonFinalFinalFieldTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/fields/NonFinalFinalFieldTest.java
@@ -4,7 +4,6 @@
 
 package com.android.tools.r8.ir.optimize.fields;
 
-import static org.junit.Assume.assumeTrue;
 
 import com.android.tools.r8.NeverClassInline;
 import com.android.tools.r8.TestBase;
@@ -35,8 +34,8 @@
 
   @Test
   public void testJvm() throws Exception {
-    assumeTrue(parameters.isCfRuntime());
-    testForJvm()
+    parameters.assumeJvmTestParameters();
+    testForJvm(parameters)
         .addProgramClasses(TestClass.class)
         .addProgramClassFileData(getProgramClassFileData())
         .run(parameters.getRuntime(), TestClass.class)
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/ifs/IfThrowNullPointerExceptionTest.java b/src/test/java/com/android/tools/r8/ir/optimize/ifs/IfThrowNullPointerExceptionTest.java
index ea3a8ec..b9c24d6 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/ifs/IfThrowNullPointerExceptionTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/ifs/IfThrowNullPointerExceptionTest.java
@@ -9,7 +9,6 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
-import static org.junit.Assume.assumeTrue;
 
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
@@ -44,8 +43,8 @@
 
   @Test
   public void testJVM() throws Exception {
-    assumeTrue(parameters.isCfRuntime());
-    testForJvm()
+    parameters.assumeJvmTestParameters();
+    testForJvm(parameters)
         .addTestClasspath()
         .run(parameters.getRuntime(), TestClass.class)
         .assertSuccessWithOutput(getExpectedStdout(false));
@@ -53,7 +52,7 @@
 
   @Test
   public void testD8() throws Exception {
-    assumeTrue(parameters.isDexRuntime());
+    parameters.assumeDexRuntime();
     testForD8()
         .addInnerClasses(IfThrowNullPointerExceptionTest.class)
         .release()
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/ifs/TrivialObjectEqualsTest.java b/src/test/java/com/android/tools/r8/ir/optimize/ifs/TrivialObjectEqualsTest.java
index 59f9402..43fb527 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/ifs/TrivialObjectEqualsTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/ifs/TrivialObjectEqualsTest.java
@@ -8,7 +8,6 @@
 import static com.android.tools.r8.utils.codeinspector.Matchers.isAbsent;
 import static org.hamcrest.CoreMatchers.not;
 import static org.hamcrest.MatcherAssert.assertThat;
-import static org.junit.Assume.assumeTrue;
 
 import com.android.tools.r8.NeverInline;
 import com.android.tools.r8.TestBase;
@@ -34,8 +33,8 @@
 
   @Test
   public void testD8() throws Exception {
-    assumeTrue(parameters.isDexRuntime());
-    testForD8(parameters.getBackend())
+    parameters.assumeDexRuntime();
+    testForD8()
         .addInnerClasses(getClass())
         .setMinApi(parameters)
         .compile()
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/inliner/InlineMappingOnSameLineTest.java b/src/test/java/com/android/tools/r8/ir/optimize/inliner/InlineMappingOnSameLineTest.java
index c4a0b9d..d26643f 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/inliner/InlineMappingOnSameLineTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/inliner/InlineMappingOnSameLineTest.java
@@ -42,7 +42,7 @@
     runTest(
         ImmutableList.of("-keepattributes SourceFile,LineNumberTable"),
         (StackTrace actualStackTrace, StackTrace retracedStackTrace) -> {
-          assertThat(retracedStackTrace, isSame(expectedStackTrace));
+          assertThat(retracedStackTrace, isSame(getExpectedStackTrace()));
         });
   }
 
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/inliner/InlinerTest.java b/src/test/java/com/android/tools/r8/ir/optimize/inliner/InlinerTest.java
index 8ebf049..a5f3f05 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/inliner/InlinerTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/inliner/InlinerTest.java
@@ -7,54 +7,37 @@
 import static com.android.tools.r8.utils.codeinspector.Matchers.isAbsent;
 import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
 import static org.hamcrest.MatcherAssert.assertThat;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.fail;
 
 import com.android.tools.r8.TestBase;
-import com.android.tools.r8.ToolHelper;
-import com.android.tools.r8.ToolHelper.ProcessResult;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
 import com.android.tools.r8.ir.optimize.inliner.exceptionhandling.ExceptionHandlingTestClass;
 import com.android.tools.r8.ir.optimize.inliner.interfaces.InterfaceTargetsTestClass;
-import com.android.tools.r8.ir.optimize.inliner.interfaces.InterfaceTargetsTestClass.IfaceA;
-import com.android.tools.r8.ir.optimize.inliner.interfaces.InterfaceTargetsTestClass.IfaceB;
-import com.android.tools.r8.ir.optimize.inliner.interfaces.InterfaceTargetsTestClass.IfaceC;
-import com.android.tools.r8.ir.optimize.inliner.interfaces.InterfaceTargetsTestClass.IfaceD;
-import com.android.tools.r8.ir.optimize.inliner.interfaces.InterfaceTargetsTestClass.IfaceNoImpl;
-import com.android.tools.r8.naming.MemberNaming.MethodSignature;
-import com.android.tools.r8.utils.AndroidApp;
-import com.android.tools.r8.utils.InternalOptions;
 import com.android.tools.r8.utils.codeinspector.ClassSubject;
-import com.android.tools.r8.utils.codeinspector.CodeInspector;
-import com.android.tools.r8.utils.codeinspector.MethodSubject;
-import java.nio.file.Path;
-import java.util.stream.Collectors;
-import java.util.stream.Stream;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
 
 @RunWith(Parameterized.class)
 public class InlinerTest extends TestBase {
 
-  private Backend backend;
+  @Parameter(0)
+  public TestParameters parameters;
 
-  @Parameterized.Parameters(name = "Backend: {0}")
-  public static Backend[] data() {
-    return ToolHelper.getBackends();
-  }
-
-  public InlinerTest(Backend backend) {
-    this.backend = backend;
+  @Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withAllRuntimesAndApiLevels().build();
   }
 
   @Test
   public void testExceptionHandling() throws Exception {
-    testForR8(backend)
+    testForR8(parameters.getBackend())
         .addProgramClasses(ExceptionHandlingTestClass.class)
         .addKeepMainRule(ExceptionHandlingTestClass.class)
-        .addOptionsModification(this::configure)
         .enableInliningAnnotations()
+        .setMinApi(parameters)
         .compile()
         .inspect(
             inspector -> {
@@ -71,7 +54,7 @@
                   mainClassSubject.uniqueMethodWithOriginalName("inlineeWithoutNormalExit"),
                   isAbsent());
             })
-        .run(ExceptionHandlingTestClass.class)
+        .run(parameters.getRuntime(), ExceptionHandlingTestClass.class)
         .assertSuccessWithOutputLines(
             "Test succeeded: methodWithoutCatchHandlersTest(1)",
             "Test succeeded: methodWithoutCatchHandlersTest(2)",
@@ -83,96 +66,30 @@
 
   @Test
   public void testInterfacesWithoutTargets() throws Exception {
-    byte[][] classes = {
-        ToolHelper.getClassAsBytes(InterfaceTargetsTestClass.class),
-        ToolHelper.getClassAsBytes(InterfaceTargetsTestClass.IfaceNoImpl.class),
-        ToolHelper.getClassAsBytes(InterfaceTargetsTestClass.IfaceA.class),
-        ToolHelper.getClassAsBytes(InterfaceTargetsTestClass.BaseA.class),
-        ToolHelper.getClassAsBytes(InterfaceTargetsTestClass.DerivedA.class),
-        ToolHelper.getClassAsBytes(InterfaceTargetsTestClass.IfaceB.class),
-        ToolHelper.getClassAsBytes(InterfaceTargetsTestClass.BaseB.class),
-        ToolHelper.getClassAsBytes(InterfaceTargetsTestClass.DerivedB.class),
-        ToolHelper.getClassAsBytes(InterfaceTargetsTestClass.IfaceC.class),
-        ToolHelper.getClassAsBytes(InterfaceTargetsTestClass.IfaceC2.class),
-        ToolHelper.getClassAsBytes(InterfaceTargetsTestClass.BaseC.class),
-        ToolHelper.getClassAsBytes(InterfaceTargetsTestClass.DerivedC.class),
-        ToolHelper.getClassAsBytes(InterfaceTargetsTestClass.IfaceD.class),
-        ToolHelper.getClassAsBytes(InterfaceTargetsTestClass.BaseD.class)
-    };
-    AndroidApp app = runR8(buildAndroidApp(classes), InterfaceTargetsTestClass.class);
-
-    String javaOutput = runOnJava(InterfaceTargetsTestClass.class);
-    assert backend == Backend.DEX || backend == Backend.CF;
-    String output =
-        backend == Backend.DEX
-            ? runOnArt(app, InterfaceTargetsTestClass.class)
-            : runOnJava(app, InterfaceTargetsTestClass.class);
-    assertEquals(javaOutput, output);
-
-    CodeInspector inspector = new CodeInspector(app);
-    ClassSubject clazz = inspector.clazz(InterfaceTargetsTestClass.class);
-
-    assertFalse(getMethodSubject(clazz,
-        "testInterfaceNoImpl", String.class, IfaceNoImpl.class).isPresent());
-    assertFalse(getMethodSubject(clazz,
-        "testInterfaceA", String.class, IfaceA.class).isPresent());
-    assertFalse(getMethodSubject(clazz,
-        "testInterfaceB", String.class, IfaceB.class).isPresent());
-    assertFalse(getMethodSubject(clazz,
-        "testInterfaceD", String.class, IfaceC.class).isPresent());
-    assertFalse(getMethodSubject(clazz,
-        "testInterfaceD", String.class, IfaceD.class).isPresent());
-  }
-
-  private MethodSubject getMethodSubject(
-      ClassSubject clazz, String methodName, Class retValue, Class... params) {
-    return clazz.method(new MethodSignature(methodName, retValue.getTypeName(),
-        Stream.of(params).map(Class::getTypeName).collect(Collectors.toList())));
-  }
-
-  private AndroidApp runR8(AndroidApp app, Class mainClass) throws Exception {
-    AndroidApp compiled =
-        compileWithR8(
-            app, getProguardConfig(mainClass.getCanonicalName()), this::configure, backend);
-
-    // Materialize file for execution.
-    Path generatedFile = temp.getRoot().toPath().resolve("classes.jar");
-    assert backend == Backend.DEX || backend == Backend.CF;
-    compiled.writeToZipForTesting(generatedFile, outputMode(backend));
-
-    String output =
-        backend == Backend.DEX
-            ? ToolHelper.runArtNoVerificationErrors(
-                generatedFile.toString(), mainClass.getCanonicalName())
-            : ToolHelper.runJava(generatedFile, mainClass.getCanonicalName()).stdout;
-
-    // Compare with Java.
-    ProcessResult javaResult = ToolHelper.runJava(
-        ToolHelper.getClassPathForTests(), mainClass.getCanonicalName());
-
-    if (javaResult.exitCode != 0) {
-      System.out.println(javaResult.stdout);
-      System.err.println(javaResult.stderr);
-      fail("JVM failed for: " + mainClass);
-    }
-    assertEquals(
-        backend == Backend.DEX
-            ? "JVM and ART output differ."
-            : "Outputs of source and processed programs running on JVM differ.",
-        javaResult.stdout,
-        output);
-
-    return compiled;
-  }
-
-  private String getProguardConfig(String main) {
-    return keepMainProguardConfiguration(main)
-        + "\n"
-        + "-dontobfuscate\n"
-        + "-allowaccessmodification";
-  }
-
-  private void configure(InternalOptions options) {
-    options.enableClassInlining = false;
+    testForR8(parameters.getBackend())
+        .addProgramClassesAndInnerClasses(InterfaceTargetsTestClass.class)
+        .addKeepMainRule(InterfaceTargetsTestClass.class)
+        .allowAccessModification()
+        .addDontObfuscate()
+        .noClassInlining()
+        .setMinApi(parameters)
+        .compile()
+        .inspect(
+            inspector -> {
+              ClassSubject clazz = inspector.clazz(InterfaceTargetsTestClass.class);
+              assertThat(clazz, isPresent());
+              assertThat(clazz.uniqueMethodWithOriginalName("testInterfaceNoImpl"), isAbsent());
+              assertThat(clazz.uniqueMethodWithOriginalName("testInterfaceA"), isAbsent());
+              assertThat(clazz.uniqueMethodWithOriginalName("testInterfaceB"), isAbsent());
+              assertThat(clazz.uniqueMethodWithOriginalName("testInterfaceD"), isAbsent());
+              assertThat(clazz.uniqueMethodWithOriginalName("testInterfaceD"), isAbsent());
+            })
+        .run(parameters.getRuntime(), InterfaceTargetsTestClass.class)
+        .assertSuccessWithOutputLines(
+            "testInterfaceNoImpl::OK",
+            "testInterfaceA::OK",
+            "testInterfaceB::OK",
+            "testInterfaceC::OK",
+            "testInterfaceD::OK");
   }
 }
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/inliner/InliningAfterClassInitializationTest.java b/src/test/java/com/android/tools/r8/ir/optimize/inliner/InliningAfterClassInitializationTest.java
index e083014..5905b26 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/inliner/InliningAfterClassInitializationTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/inliner/InliningAfterClassInitializationTest.java
@@ -213,7 +213,7 @@
 
   private CodeInspector buildAndRun(Class<?> mainClass, String expectedOutput) throws Exception {
     if (parameters.isCfRuntime()) {
-      testForJvm()
+      testForJvm(parameters)
           .addTestClasspath()
           .run(parameters.getRuntime(), mainClass)
           .assertSuccessWithOutput(expectedOutput);
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/inliner/InliningFromCurrentClassTest.java b/src/test/java/com/android/tools/r8/ir/optimize/inliner/InliningFromCurrentClassTest.java
index 9557ac0..eff0507 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/inliner/InliningFromCurrentClassTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/inliner/InliningFromCurrentClassTest.java
@@ -21,34 +21,40 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
 
 @RunWith(Parameterized.class)
 public class InliningFromCurrentClassTest extends TestBase {
 
-  private final TestParameters parameters;
+  private static final String EXPECTED_OUTPUT =
+      StringUtils.lines(
+          "In A.<clinit>()",
+          "In B.<clinit>()",
+          "In A.inlineable1()",
+          "In B.inlineable2()",
+          "In C.<clinit>()",
+          "In C.inlineableWithInitClass()");
 
-  @Parameterized.Parameters(name = "{0}")
+  @Parameter(0)
+  public TestParameters parameters;
+
+  @Parameters(name = "{0}")
   public static TestParametersCollection data() {
     return getTestParameters().withAllRuntimesAndApiLevels().build();
   }
 
-  public InliningFromCurrentClassTest(TestParameters parameters) {
-    this.parameters = parameters;
+  @Test
+  public void testJvm() throws Exception {
+    parameters.assumeJvmTestParameters();
+    testForJvm(parameters)
+        .addTestClasspath()
+        .run(parameters.getRuntime(), TestClass.class)
+        .assertSuccessWithOutput(EXPECTED_OUTPUT);
   }
 
   @Test
-  public void test() throws Exception {
-    String expectedOutput =
-        StringUtils.lines(
-            "In A.<clinit>()",
-            "In B.<clinit>()",
-            "In A.inlineable1()",
-            "In B.inlineable2()",
-            "In C.<clinit>()",
-            "In C.inlineableWithInitClass()");
-
-    testForJvm().addTestClasspath().run(TestClass.class).assertSuccessWithOutput(expectedOutput);
-
+  public void testR8() throws Exception {
     CodeInspector inspector =
         testForR8(parameters.getBackend())
             .addInnerClasses(InliningFromCurrentClassTest.class)
@@ -57,7 +63,7 @@
             .enableNoVerticalClassMergingAnnotations()
             .setMinApi(parameters)
             .run(parameters.getRuntime(), TestClass.class)
-            .assertSuccessWithOutput(expectedOutput)
+            .assertSuccessWithOutput(EXPECTED_OUTPUT)
             .inspector();
 
     ClassSubject classA = inspector.clazz(A.class);
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/inliner/InliningWithClassInitializerTest.java b/src/test/java/com/android/tools/r8/ir/optimize/inliner/InliningWithClassInitializerTest.java
index 4694c08..3043e74 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/inliner/InliningWithClassInitializerTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/inliner/InliningWithClassInitializerTest.java
@@ -12,28 +12,52 @@
 import com.android.tools.r8.NeverInline;
 import com.android.tools.r8.NoVerticalClassMerging;
 import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
 import com.android.tools.r8.utils.StringUtils;
 import com.android.tools.r8.utils.codeinspector.ClassSubject;
 import com.android.tools.r8.utils.codeinspector.CodeInspector;
 import com.android.tools.r8.utils.codeinspector.MethodSubject;
 import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
 
+@RunWith(Parameterized.class)
 public class InliningWithClassInitializerTest extends TestBase {
 
+  private static final String EXPECTED_OUTPUT =
+      StringUtils.lines("In A.<clinit>()", "In B.<clinit>()", "In B.other()");
+
+  @Parameter(0)
+  public TestParameters parameters;
+
+  @Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withAllRuntimesAndApiLevels().build();
+  }
+
   @Test
-  public void test() throws Exception {
-    String expectedOutput = StringUtils.lines("In A.<clinit>()", "In B.<clinit>()", "In B.other()");
+  public void testJvm() throws Exception {
+    parameters.assumeJvmTestParameters();
+    testForJvm(parameters)
+        .addTestClasspath()
+        .run(parameters.getRuntime(), TestClass.class)
+        .assertSuccessWithOutput(EXPECTED_OUTPUT);
+  }
 
-    testForJvm().addTestClasspath().run(TestClass.class).assertSuccessWithOutput(expectedOutput);
-
+  @Test
+  public void testR8() throws Exception {
     CodeInspector inspector =
-        testForR8(Backend.DEX)
+        testForR8(parameters.getBackend())
             .addInnerClasses(InliningWithClassInitializerTest.class)
             .addKeepMainRule(TestClass.class)
             .enableInliningAnnotations()
             .enableNoVerticalClassMergingAnnotations()
-            .run(TestClass.class)
-            .assertSuccessWithOutput(expectedOutput)
+            .setMinApi(parameters)
+            .run(parameters.getRuntime(), TestClass.class)
+            .assertSuccessWithOutput(EXPECTED_OUTPUT)
             .inspector();
 
     ClassSubject classA = inspector.clazz(A.class);
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/inliner/SyntheticInitClassPositionTest.java b/src/test/java/com/android/tools/r8/ir/optimize/inliner/SyntheticInitClassPositionTest.java
index 1b7f91c..0e4ad3a 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/inliner/SyntheticInitClassPositionTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/inliner/SyntheticInitClassPositionTest.java
@@ -12,38 +12,37 @@
 import com.android.tools.r8.TestParametersCollection;
 import com.android.tools.r8.TestRuntime.CfRuntime;
 import com.android.tools.r8.naming.retrace.StackTrace;
-import org.junit.Before;
+import org.junit.BeforeClass;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
 import org.junit.runners.Parameterized.Parameters;
 
 @RunWith(Parameterized.class)
 public class SyntheticInitClassPositionTest extends TestBase {
 
-  private final TestParameters parameters;
-  private StackTrace expectedStackTrace;
+  private static StackTrace expectedStackTrace;
+
+  @Parameter(0)
+  public TestParameters parameters;
 
   @Parameters(name = "{0}")
   public static TestParametersCollection data() {
-    return TestBase.getTestParameters().withAllRuntimesAndApiLevels().build();
+    return getTestParameters().withAllRuntimesAndApiLevels().build();
   }
 
-  @Before
-  public void setup() throws Exception {
+  @BeforeClass
+  public static void setup() throws Exception {
     // Get the expected stack trace by running on the JVM.
     expectedStackTrace =
-        testForJvm()
+        testForJvm(getStaticTemp())
             .addTestClasspath()
             .run(CfRuntime.getSystemRuntime(), Main.class)
             .assertFailure()
             .map(StackTrace::extractFromJvm);
   }
 
-  public SyntheticInitClassPositionTest(TestParameters parameters) {
-    this.parameters = parameters;
-  }
-
   @Test
   public void test() throws Exception {
     testForR8(parameters.getBackend())
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/inliner/SyntheticInlineNullCheckPositionTest.java b/src/test/java/com/android/tools/r8/ir/optimize/inliner/SyntheticInlineNullCheckPositionTest.java
index 0b56c68..0ad0304 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/inliner/SyntheticInlineNullCheckPositionTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/inliner/SyntheticInlineNullCheckPositionTest.java
@@ -12,49 +12,35 @@
 import com.android.tools.r8.TestParametersCollection;
 import com.android.tools.r8.TestRuntime.CfRuntime;
 import com.android.tools.r8.naming.retrace.StackTrace;
-import com.android.tools.r8.naming.retrace.StackTrace.StackTraceLine;
-import java.util.Objects;
-import org.junit.Before;
+import org.junit.BeforeClass;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
 import org.junit.runners.Parameterized.Parameters;
 
 @RunWith(Parameterized.class)
 public class SyntheticInlineNullCheckPositionTest extends TestBase {
 
-  private static final StackTraceLine REQUIRE_NON_NULL_LINE =
-      StackTraceLine.builder()
-          .setClassName(Objects.class.getTypeName())
-          .setMethodName("requireNonNull")
-          .setFileName("Objects.java")
-          .build();
+  private static StackTrace expectedStackTrace;
 
-  private final TestParameters parameters;
-  private StackTrace expectedStackTraceWithGetClass;
-  private StackTrace expectedStackTraceWithRequireNonNull;
+  @Parameter(0)
+  public TestParameters parameters;
 
   @Parameters(name = "{0}")
   public static TestParametersCollection data() {
-    return TestBase.getTestParameters().withAllRuntimesAndApiLevels().build();
+    return getTestParameters().withAllRuntimesAndApiLevels().build();
   }
 
-  @Before
-  public void setup() throws Exception {
+  @BeforeClass
+  public static void setup() throws Exception {
     // Get the expected stack trace by running on the JVM.
-    StackTrace actualStackTrace =
-        testForJvm()
+    expectedStackTrace =
+        testForJvm(getStaticTemp())
             .addTestClasspath()
             .run(CfRuntime.getSystemRuntime(), Main.class)
             .assertFailure()
             .map(StackTrace::extractFromJvm);
-    expectedStackTraceWithGetClass = actualStackTrace;
-    expectedStackTraceWithRequireNonNull =
-        StackTrace.builder().add(REQUIRE_NON_NULL_LINE).add(actualStackTrace).build();
-  }
-
-  public SyntheticInlineNullCheckPositionTest(TestParameters parameters) {
-    this.parameters = parameters;
   }
 
   @Test
@@ -68,8 +54,7 @@
         .compile()
         .run(parameters.getRuntime(), Main.class)
         .assertFailureWithErrorThatThrows(NullPointerException.class)
-        .inspectStackTrace(
-            stackTrace -> assertThat(stackTrace, isSame(expectedStackTraceWithGetClass)));
+        .inspectStackTrace(stackTrace -> assertThat(stackTrace, isSame(expectedStackTrace)));
   }
 
   static class Main {
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/inliner/whyareyounotinlining/WhyAreYouNotInliningInvokeWithUnknownTargetTest.java b/src/test/java/com/android/tools/r8/ir/optimize/inliner/whyareyounotinlining/WhyAreYouNotInliningInvokeWithUnknownTargetTest.java
index 87961dc..83cb843 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/inliner/whyareyounotinlining/WhyAreYouNotInliningInvokeWithUnknownTargetTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/inliner/whyareyounotinlining/WhyAreYouNotInliningInvokeWithUnknownTargetTest.java
@@ -9,43 +9,40 @@
 import com.android.tools.r8.NoHorizontalClassMerging;
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.utils.AndroidApiLevel;
 import com.android.tools.r8.utils.StringUtils;
 import java.io.ByteArrayOutputStream;
 import java.io.PrintStream;
-import java.util.List;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
 import org.junit.runners.Parameterized.Parameters;
 
 @RunWith(Parameterized.class)
 public class WhyAreYouNotInliningInvokeWithUnknownTargetTest extends TestBase {
 
-  private final Backend backend;
-  private final TestParameters parameters;
+  @Parameter(0)
+  public TestParameters parameters;
 
   @Parameters(name = "{0}")
-  public static List<Object[]> data() {
-    return buildParameters(Backend.values(), getTestParameters().withNoneRuntime().build());
-  }
-
-  public WhyAreYouNotInliningInvokeWithUnknownTargetTest(
-      Backend backend, TestParameters parameters) {
-    this.backend = backend;
-    this.parameters = parameters;
+  public static TestParametersCollection data() {
+    return getTestParameters().withDefaultRuntimes().withApiLevel(AndroidApiLevel.B).build();
   }
 
   @Test
   public void test() throws Exception {
     ByteArrayOutputStream baos = new ByteArrayOutputStream();
     PrintStream out = new PrintStream(baos);
-    testForR8(backend)
+    testForR8(parameters.getBackend())
         .addInnerClasses(WhyAreYouNotInliningInvokeWithUnknownTargetTest.class)
         .addKeepMainRule(TestClass.class)
         .addKeepRules("-whyareyounotinlining class " + A.class.getTypeName() + " { void m(); }")
         .addOptionsModification(options -> options.testing.whyAreYouNotInliningConsumer = out)
         .enableExperimentalWhyAreYouNotInlining()
         .enableNoHorizontalClassMergingAnnotations()
+        .setMinApi(parameters)
         .compile();
     out.close();
 
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/instanceofremoval/ArrayInstanceOfCloneableAndSerializableTest.java b/src/test/java/com/android/tools/r8/ir/optimize/instanceofremoval/ArrayInstanceOfCloneableAndSerializableTest.java
index 67f1601..68c7d64 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/instanceofremoval/ArrayInstanceOfCloneableAndSerializableTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/instanceofremoval/ArrayInstanceOfCloneableAndSerializableTest.java
@@ -6,7 +6,6 @@
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
-import static org.junit.Assume.assumeTrue;
 
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
@@ -33,8 +32,8 @@
 
   @Test
   public void testJvm() throws Exception {
-    assumeTrue(parameters.isCfRuntime());
-    testForJvm()
+    parameters.assumeJvmTestParameters();
+    testForJvm(parameters)
         .addTestClasspath()
         .run(parameters.getRuntime(), Main.class)
         .assertSuccessWithOutputLines("true", "true");
@@ -42,7 +41,7 @@
 
   @Test
   public void testD8() throws Exception {
-    assumeTrue(parameters.isDexRuntime());
+    parameters.assumeDexRuntime();
     testForD8()
         .addProgramClasses(Main.class)
         .release()
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/instanceofremoval/InstanceOfRemovalTest.java b/src/test/java/com/android/tools/r8/ir/optimize/instanceofremoval/InstanceOfRemovalTest.java
index f0e2bbb..b399efe 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/instanceofremoval/InstanceOfRemovalTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/instanceofremoval/InstanceOfRemovalTest.java
@@ -148,7 +148,7 @@
             "");
 
     if (parameters.isCfRuntime()) {
-      testForJvm()
+      testForJvm(parameters)
           .addTestClasspath()
           .run(parameters.getRuntime(), TestClass.class)
           .assertSuccessWithOutput(expected);
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/instanceofremoval/ZipFileInstanceOfAutoCloseableTest.java b/src/test/java/com/android/tools/r8/ir/optimize/instanceofremoval/ZipFileInstanceOfAutoCloseableTest.java
index 9e1b444..783d197 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/instanceofremoval/ZipFileInstanceOfAutoCloseableTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/instanceofremoval/ZipFileInstanceOfAutoCloseableTest.java
@@ -78,7 +78,7 @@
 
   @Test
   public void testD8() throws Exception {
-    assumeTrue(parameters.isDexRuntime());
+    parameters.assumeDexRuntime();
     testForD8()
         .addInnerClasses(ZipFileInstanceOfAutoCloseableTest.class)
         .setMinApi(parameters)
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/interfaces/OpenInterfaceCheckCastTest.java b/src/test/java/com/android/tools/r8/ir/optimize/interfaces/OpenInterfaceCheckCastTest.java
index b7b638e..fefbe7a 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/interfaces/OpenInterfaceCheckCastTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/interfaces/OpenInterfaceCheckCastTest.java
@@ -5,7 +5,6 @@
 package com.android.tools.r8.ir.optimize.interfaces;
 
 import static org.junit.Assert.assertEquals;
-import static org.junit.Assume.assumeTrue;
 
 import com.android.tools.r8.NeverInline;
 import com.android.tools.r8.NoVerticalClassMerging;
@@ -36,7 +35,7 @@
 
   @Test
   public void testJvm() throws Exception {
-    assumeTrue(parameters.isCfRuntime());
+    parameters.assumeJvmTestParameters();
     testForRuntime(parameters)
         .addProgramClasses(getProgramClasses())
         .addProgramClassFileData(getTransformedMainClass())
@@ -46,8 +45,8 @@
 
   @Test
   public void testD8() throws Exception {
-    assumeTrue(parameters.isDexRuntime());
-    testForD8(parameters.getBackend())
+    parameters.assumeDexRuntime();
+    testForD8()
         .addProgramClasses(getProgramClasses())
         .addProgramClassFileData(getTransformedMainClass())
         .setMinApi(parameters)
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/interfaces/OpenInterfaceInliningTest.java b/src/test/java/com/android/tools/r8/ir/optimize/interfaces/OpenInterfaceInliningTest.java
index 7ff6f8c..9b371c9 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/interfaces/OpenInterfaceInliningTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/interfaces/OpenInterfaceInliningTest.java
@@ -5,7 +5,6 @@
 package com.android.tools.r8.ir.optimize.interfaces;
 
 import static org.junit.Assert.assertEquals;
-import static org.junit.Assume.assumeTrue;
 
 import com.android.tools.r8.NoHorizontalClassMerging;
 import com.android.tools.r8.NoVerticalClassMerging;
@@ -35,7 +34,7 @@
 
   @Test
   public void testJvm() throws Exception {
-    assumeTrue(parameters.isCfRuntime());
+    parameters.assumeJvmTestParameters();
     testForRuntime(parameters)
         .addProgramClasses(getProgramClasses())
         .addProgramClassFileData(getTransformedMainClass())
@@ -45,8 +44,8 @@
 
   @Test
   public void testD8() throws Exception {
-    assumeTrue(parameters.isDexRuntime());
-    testForD8(parameters.getBackend())
+    parameters.assumeDexRuntime();
+    testForD8()
         .addProgramClasses(getProgramClasses())
         .addProgramClassFileData(getTransformedMainClass())
         .setMinApi(parameters)
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/interfaces/OpenInterfaceInstanceofTest.java b/src/test/java/com/android/tools/r8/ir/optimize/interfaces/OpenInterfaceInstanceofTest.java
index bfc71f7..2fb72d8 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/interfaces/OpenInterfaceInstanceofTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/interfaces/OpenInterfaceInstanceofTest.java
@@ -5,7 +5,6 @@
 package com.android.tools.r8.ir.optimize.interfaces;
 
 import static org.junit.Assert.assertEquals;
-import static org.junit.Assume.assumeTrue;
 
 import com.android.tools.r8.NeverInline;
 import com.android.tools.r8.NoVerticalClassMerging;
@@ -36,7 +35,7 @@
 
   @Test
   public void testJvm() throws Exception {
-    assumeTrue(parameters.isCfRuntime());
+    parameters.assumeJvmTestParameters();
     testForRuntime(parameters)
         .addProgramClasses(getProgramClasses())
         .addProgramClassFileData(getTransformedMainClass())
@@ -46,8 +45,8 @@
 
   @Test
   public void testD8() throws Exception {
-    assumeTrue(parameters.isDexRuntime());
-    testForD8(parameters.getBackend())
+    parameters.assumeDexRuntime();
+    testForD8()
         .addProgramClasses(getProgramClasses())
         .addProgramClassFileData(getTransformedMainClass())
         .setMinApi(parameters)
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/interfaces/OpenUninstantiatedInterfaceAlwaysNullTest.java b/src/test/java/com/android/tools/r8/ir/optimize/interfaces/OpenUninstantiatedInterfaceAlwaysNullTest.java
index e9d1879..8ec74ab 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/interfaces/OpenUninstantiatedInterfaceAlwaysNullTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/interfaces/OpenUninstantiatedInterfaceAlwaysNullTest.java
@@ -5,7 +5,6 @@
 package com.android.tools.r8.ir.optimize.interfaces;
 
 import static org.junit.Assert.assertEquals;
-import static org.junit.Assume.assumeTrue;
 
 import com.android.tools.r8.NoVerticalClassMerging;
 import com.android.tools.r8.TestBase;
@@ -34,7 +33,7 @@
 
   @Test
   public void testJvm() throws Exception {
-    assumeTrue(parameters.isCfRuntime());
+    parameters.assumeJvmTestParameters();
     testForRuntime(parameters)
         .addProgramClasses(getProgramClasses())
         .addProgramClassFileData(getTransformedMainClass())
@@ -44,8 +43,8 @@
 
   @Test
   public void testD8() throws Exception {
-    assumeTrue(parameters.isDexRuntime());
-    testForD8(parameters.getBackend())
+    parameters.assumeDexRuntime();
+    testForD8()
         .addProgramClasses(getProgramClasses())
         .addProgramClassFileData(getTransformedMainClass())
         .setMinApi(parameters)
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/interfaces/OpenUninstantiatedInterfaceInstanceofTest.java b/src/test/java/com/android/tools/r8/ir/optimize/interfaces/OpenUninstantiatedInterfaceInstanceofTest.java
index a278c14..6765723 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/interfaces/OpenUninstantiatedInterfaceInstanceofTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/interfaces/OpenUninstantiatedInterfaceInstanceofTest.java
@@ -5,7 +5,6 @@
 package com.android.tools.r8.ir.optimize.interfaces;
 
 import static org.junit.Assert.assertEquals;
-import static org.junit.Assume.assumeTrue;
 
 import com.android.tools.r8.NeverInline;
 import com.android.tools.r8.TestBase;
@@ -35,7 +34,7 @@
 
   @Test
   public void testJvm() throws Exception {
-    assumeTrue(parameters.isCfRuntime());
+    parameters.assumeJvmTestParameters();
     testForRuntime(parameters)
         .addProgramClasses(getProgramClasses())
         .addProgramClassFileData(getTransformedMainClass())
@@ -45,8 +44,8 @@
 
   @Test
   public void testD8() throws Exception {
-    assumeTrue(parameters.isDexRuntime());
-    testForD8(parameters.getBackend())
+    parameters.assumeDexRuntime();
+    testForD8()
         .addProgramClasses(getProgramClasses())
         .addProgramClassFileData(getTransformedMainClass())
         .setMinApi(parameters)
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/library/BooleanParseBooleanTest.java b/src/test/java/com/android/tools/r8/ir/optimize/library/BooleanParseBooleanTest.java
index 57307d5..1d4fea6 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/library/BooleanParseBooleanTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/library/BooleanParseBooleanTest.java
@@ -8,7 +8,6 @@
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
-import static org.junit.Assume.assumeTrue;
 
 import com.android.tools.r8.NeverInline;
 import com.android.tools.r8.TestBase;
@@ -39,7 +38,7 @@
 
   @Test
   public void testD8() throws Exception {
-    assumeTrue(parameters.isDexRuntime());
+    parameters.assumeDexRuntime();
     testForD8()
         .addProgramClasses(TestClass.class)
         .release()
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/membervaluepropagation/SdkIntMemberValuePropagationTest.java b/src/test/java/com/android/tools/r8/ir/optimize/membervaluepropagation/SdkIntMemberValuePropagationTest.java
index 3441921..900a30b 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/membervaluepropagation/SdkIntMemberValuePropagationTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/membervaluepropagation/SdkIntMemberValuePropagationTest.java
@@ -82,7 +82,7 @@
 
   @Test
   public void testD8() throws Exception {
-    assumeTrue(parameters.isDexRuntime());
+    parameters.assumeDexRuntime();
     assumeTrue(rule.getRule().equals(""));
     testForD8()
         .addProgramClassFileData(getTransformedMainClass())
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/outliner/b112247415/B112247415.java b/src/test/java/com/android/tools/r8/ir/optimize/outliner/b112247415/B112247415.java
index 9f3c53d..a96ba2f 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/outliner/b112247415/B112247415.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/outliner/b112247415/B112247415.java
@@ -74,7 +74,7 @@
   @Test
   public void test() throws Exception {
     if (parameters.isCfRuntime()) {
-      testForJvm()
+      testForJvm(parameters)
           .addTestClasspath()
           .run(parameters.getRuntime(), TestClass.class)
           .assertSuccessWithOutput(EXPECTED);
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/redundantarraygetelimination/RedundantArrayGetEliminationTest.java b/src/test/java/com/android/tools/r8/ir/optimize/redundantarraygetelimination/RedundantArrayGetEliminationTest.java
index d460ee8..31eb68f 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/redundantarraygetelimination/RedundantArrayGetEliminationTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/redundantarraygetelimination/RedundantArrayGetEliminationTest.java
@@ -5,7 +5,6 @@
 package com.android.tools.r8.ir.optimize.redundantarraygetelimination;
 
 import static org.junit.Assert.assertEquals;
-import static org.junit.Assume.assumeTrue;
 
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
@@ -36,8 +35,8 @@
 
   @Test
   public void testD8() throws Exception {
-    assumeTrue(parameters.isDexRuntime());
-    testForD8(parameters.getBackend())
+    parameters.assumeDexRuntime();
+    testForD8()
         .addInnerClasses(getClass())
         .release()
         .setMinApi(parameters)
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/redundantcatchrethrowelimination/RedundantCatchRethrowEliminationTest.java b/src/test/java/com/android/tools/r8/ir/optimize/redundantcatchrethrowelimination/RedundantCatchRethrowEliminationTest.java
index 22cd122..7bd798b 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/redundantcatchrethrowelimination/RedundantCatchRethrowEliminationTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/redundantcatchrethrowelimination/RedundantCatchRethrowEliminationTest.java
@@ -7,7 +7,6 @@
 import static com.android.tools.r8.utils.codeinspector.CodeMatchers.containsThrow;
 import static org.hamcrest.CoreMatchers.not;
 import static org.hamcrest.MatcherAssert.assertThat;
-import static org.junit.Assume.assumeTrue;
 
 import com.android.tools.r8.NeverInline;
 import com.android.tools.r8.TestBase;
@@ -43,8 +42,8 @@
 
   @Test
   public void testReference() throws Exception {
-    assumeTrue(parameters.isCfRuntime());
-    testForJvm()
+    parameters.assumeJvmTestParameters();
+    testForJvm(parameters)
         .addProgramClasses(Main.class, TrivialClosableContext.class, ClosableContext.class)
         .run(parameters.getRuntime(), Main.class)
         .assertSuccessWithOutput(EXPECTED);
@@ -52,8 +51,8 @@
 
   @Test
   public void testD8() throws Exception {
-    assumeTrue(parameters.isDexRuntime());
-    testForD8(parameters.getBackend())
+    parameters.assumeDexRuntime();
+    testForD8()
         .addProgramClasses(Main.class, TrivialClosableContext.class, ClosableContext.class)
         .release()
         .setMinApi(parameters)
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/reflection/ForNameTest.java b/src/test/java/com/android/tools/r8/ir/optimize/reflection/ForNameTest.java
index cdec21d..00121a7 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/reflection/ForNameTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/reflection/ForNameTest.java
@@ -92,7 +92,7 @@
   @Test
   public void testJVMOutput() throws Exception {
     parameters.assumeJvmTestParameters();
-    testForJvm()
+    testForJvm(parameters)
         .addTestClasspath()
         .run(parameters.getRuntime(), MAIN)
         .assertSuccessWithOutput(JAVA_OUTPUT);
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/reflection/GetClassTest.java b/src/test/java/com/android/tools/r8/ir/optimize/reflection/GetClassTest.java
index 3ea7922..8132920 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/reflection/GetClassTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/reflection/GetClassTest.java
@@ -150,7 +150,7 @@
     assumeTrue(
         "Only run JVM reference on CF runtimes",
         parameters.isCfRuntime() && mode == CompilationMode.DEBUG);
-    testForJvm()
+    testForJvm(parameters)
         .addInnerClasses(GetClassTest.class)
         .run(parameters.getRuntime(), MAIN)
         .assertSuccessWithOutput(JAVA_OUTPUT);
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/reflection/GetNameInClassInitializerTest.java b/src/test/java/com/android/tools/r8/ir/optimize/reflection/GetNameInClassInitializerTest.java
index c0333f0..45b83f4 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/reflection/GetNameInClassInitializerTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/reflection/GetNameInClassInitializerTest.java
@@ -53,7 +53,7 @@
     assumeTrue(
         "Only run JVM reference on CF runtimes",
         parameters.isCfRuntime() && !enableMinification);
-    testForJvm()
+    testForJvm(parameters)
         .addTestClasspath()
         .run(parameters.getRuntime(), MAIN)
         .assertSuccessWithOutput(JAVA_OUTPUT);
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/reflection/GetNameTest.java b/src/test/java/com/android/tools/r8/ir/optimize/reflection/GetNameTest.java
index 41c2d25..c8859fe 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/reflection/GetNameTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/reflection/GetNameTest.java
@@ -220,7 +220,7 @@
     assumeTrue(
         "Only run JVM reference on CF runtimes",
         parameters.isCfRuntime() && !enableMinification);
-    testForJvm()
+    testForJvm(parameters)
         .addTestClasspath()
         .run(parameters.getRuntime(), MAIN)
         .assertSuccessWithOutput(JAVA_OUTPUT);
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/reflection/GetSimpleNameTest.java b/src/test/java/com/android/tools/r8/ir/optimize/reflection/GetSimpleNameTest.java
index 5ddb261..533c75f 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/reflection/GetSimpleNameTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/reflection/GetSimpleNameTest.java
@@ -153,7 +153,7 @@
         "Only run JVM reference on CF runtimes",
         parameters.isCfRuntime() && !enableMinification);
     CodeInspector inspector = new CodeInspector(classPaths);
-    testForJvm()
+    testForJvm(parameters)
         .addTestClasspath()
         .run(parameters.getRuntime(), MAIN)
         .assertSuccessWithOutput(JVM_OUTPUT);
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/reflection/InnerClassNameTestRunner.java b/src/test/java/com/android/tools/r8/ir/optimize/reflection/InnerClassNameTestRunner.java
index 8a44abc..e88fb06 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/reflection/InnerClassNameTestRunner.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/reflection/InnerClassNameTestRunner.java
@@ -217,7 +217,7 @@
     JvmTestRunResult runResult = null;
     if (parameters.isCfRuntime()) {
       runResult =
-          testForJvm()
+          testForJvm(parameters)
               .addProgramClassFileData(InnerClassNameTestDump.dump(config, parameters))
               .run(parameters.getRuntime(), MAIN_CLASS);
     }
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/string/InvokeInterfaceToStringEqualsTest.java b/src/test/java/com/android/tools/r8/ir/optimize/string/InvokeInterfaceToStringEqualsTest.java
index d7e060c..cdb0b4d 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/string/InvokeInterfaceToStringEqualsTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/string/InvokeInterfaceToStringEqualsTest.java
@@ -4,7 +4,6 @@
 
 package com.android.tools.r8.ir.optimize.string;
 
-import static org.junit.Assume.assumeTrue;
 
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
@@ -31,8 +30,8 @@
 
   @Test
   public void testD8() throws Exception {
-    assumeTrue(parameters.isDexRuntime());
-    testForD8(parameters.getBackend())
+    parameters.assumeDexRuntime();
+    testForD8()
         .addProgramClassFileData(getTransformedMain(MainD8.class))
         .setMinApi(parameters)
         .run(parameters.getRuntime(), MainD8.class)
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/string/NameThenLengthTest.java b/src/test/java/com/android/tools/r8/ir/optimize/string/NameThenLengthTest.java
index 07d6918..0427b51 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/string/NameThenLengthTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/string/NameThenLengthTest.java
@@ -82,7 +82,7 @@
   @Test
   public void testJVMOutput() throws Exception {
     parameters.assumeJvmTestParameters();
-    testForJvm()
+    testForJvm(parameters)
         .addTestClasspath()
         .run(parameters.getRuntime(), MAIN)
         .assertSuccessWithOutput(JAVA_OUTPUT);
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/string/StringIsEmptyTest.java b/src/test/java/com/android/tools/r8/ir/optimize/string/StringIsEmptyTest.java
index b528d9f..cebee69 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/string/StringIsEmptyTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/string/StringIsEmptyTest.java
@@ -48,7 +48,7 @@
   @Test
   public void testJVMOutput() throws Exception {
     parameters.assumeJvmTestParameters();
-    testForJvm()
+    testForJvm(parameters)
         .addTestClasspath()
         .run(parameters.getRuntime(), MAIN)
         .assertSuccessWithOutput(JAVA_OUTPUT);
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/string/StringLengthTest.java b/src/test/java/com/android/tools/r8/ir/optimize/string/StringLengthTest.java
index e1b5f0f..656c54a 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/string/StringLengthTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/string/StringLengthTest.java
@@ -46,7 +46,7 @@
   @Test
   public void testJVMOutput() throws Exception {
     parameters.assumeJvmTestParameters();
-    testForJvm()
+    testForJvm(parameters)
         .addTestClasspath()
         .run(parameters.getRuntime(), MAIN)
         .assertSuccessWithOutput(JAVA_OUTPUT);
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/string/StringValueOfTest.java b/src/test/java/com/android/tools/r8/ir/optimize/string/StringValueOfTest.java
index 5eac1fc..9cb680b 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/string/StringValueOfTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/string/StringValueOfTest.java
@@ -61,7 +61,7 @@
   @Test
   public void testJVMOutput() throws Exception {
     parameters.assumeJvmTestParameters();
-    testForJvm()
+    testForJvm(parameters)
         .addTestClasspath()
         .run(parameters.getRuntime(), MAIN)
         .assertSuccessWithOutput(JAVA_OUTPUT);
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/switches/StringSwitchWitNonConstIdTest.java b/src/test/java/com/android/tools/r8/ir/optimize/switches/StringSwitchWitNonConstIdTest.java
index dfacc44..d20bbb4 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/switches/StringSwitchWitNonConstIdTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/switches/StringSwitchWitNonConstIdTest.java
@@ -4,7 +4,6 @@
 
 package com.android.tools.r8.ir.optimize.switches;
 
-import static org.junit.Assume.assumeTrue;
 
 import com.android.tools.r8.NeverInline;
 import com.android.tools.r8.TestBase;
@@ -30,7 +29,7 @@
 
   @Test
   public void testD8() throws Exception {
-    assumeTrue(parameters.isDexRuntime());
+    parameters.assumeDexRuntime();
     testForD8()
         .addProgramClasses(Main.class)
         .release()
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/switches/StringSwitchWitNonIntermediateIdValueTest.java b/src/test/java/com/android/tools/r8/ir/optimize/switches/StringSwitchWitNonIntermediateIdValueTest.java
index b562818..66f5729 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/switches/StringSwitchWitNonIntermediateIdValueTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/switches/StringSwitchWitNonIntermediateIdValueTest.java
@@ -8,7 +8,6 @@
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
-import static org.junit.Assume.assumeTrue;
 
 import com.android.tools.r8.NeverInline;
 import com.android.tools.r8.TestBase;
@@ -37,7 +36,7 @@
 
   @Test
   public void testD8() throws Exception {
-    assumeTrue(parameters.isDexRuntime());
+    parameters.assumeDexRuntime();
     testForD8()
         .addProgramClasses(Main.class)
         .addOptionsModification(options -> options.minimumStringSwitchSize = 4)
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/typechecks/InstanceOfMethodSpecializationTest.java b/src/test/java/com/android/tools/r8/ir/optimize/typechecks/InstanceOfMethodSpecializationTest.java
index 66e0b1f..57c2467 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/typechecks/InstanceOfMethodSpecializationTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/typechecks/InstanceOfMethodSpecializationTest.java
@@ -7,7 +7,6 @@
 import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
 import static org.hamcrest.CoreMatchers.not;
 import static org.hamcrest.MatcherAssert.assertThat;
-import static org.junit.Assume.assumeTrue;
 
 import com.android.tools.r8.NoHorizontalClassMerging;
 import com.android.tools.r8.TestBase;
@@ -42,8 +41,8 @@
 
   @Test
   public void testJvm() throws Exception {
-    assumeTrue(parameters.isCfRuntime());
-    testForJvm()
+    parameters.assumeJvmTestParameters();
+    testForJvm(parameters)
         .addTestClasspath()
         .run(parameters.getRuntime(), TestClass.class)
         .assertSuccessWithOutputLines(EXPECTED);
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/uninstantiatedtypes/InterfaceMethodTest.java b/src/test/java/com/android/tools/r8/ir/optimize/uninstantiatedtypes/InterfaceMethodTest.java
index 8ee5732..bfd7d91 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/uninstantiatedtypes/InterfaceMethodTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/uninstantiatedtypes/InterfaceMethodTest.java
@@ -44,7 +44,7 @@
     String expectedOutput = StringUtils.lines("In A.m()", "In B.m()");
 
     if (parameters.isCfRuntime()) {
-      testForJvm()
+      testForJvm(parameters)
           .addTestClasspath()
           .run(parameters.getRuntime(), TestClass.class)
           .assertSuccessWithOutput(expectedOutput);
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/uninstantiatedtypes/InvokeMethodWithNonNullParamCheckTest.java b/src/test/java/com/android/tools/r8/ir/optimize/uninstantiatedtypes/InvokeMethodWithNonNullParamCheckTest.java
index 0e1c220..9cd0bdc 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/uninstantiatedtypes/InvokeMethodWithNonNullParamCheckTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/uninstantiatedtypes/InvokeMethodWithNonNullParamCheckTest.java
@@ -70,7 +70,7 @@
                 + "WithDeadCatchHandler");
 
     if (parameters.isCfRuntime()) {
-      testForJvm()
+      testForJvm(parameters)
           .addTestClasspath()
           .run(parameters.getRuntime(), TestClass.class)
           .assertSuccessWithOutput(expected);
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/uninstantiatedtypes/InvokeMethodWithReceiverOptimizationTest.java b/src/test/java/com/android/tools/r8/ir/optimize/uninstantiatedtypes/InvokeMethodWithReceiverOptimizationTest.java
index 263a233..dd021a9 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/uninstantiatedtypes/InvokeMethodWithReceiverOptimizationTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/uninstantiatedtypes/InvokeMethodWithReceiverOptimizationTest.java
@@ -24,6 +24,7 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
 import org.junit.runners.Parameterized.Parameters;
 
 /**
@@ -33,8 +34,17 @@
 @RunWith(Parameterized.class)
 public class InvokeMethodWithReceiverOptimizationTest extends TestBase {
 
-  private final TestParameters parameters;
-  private final boolean enableArgumentPropagation;
+  private static final String EXPECTED_OUTPUT =
+      StringUtils.joinLines(
+          "Caught NullPointerException from testRewriteToThrowNull",
+          "Caught NullPointerException from testRewriteToThrowNullWithCatchHandlers",
+          "Caught NullPointerException from testRewriteToThrowNullWithDeadCatchHandler");
+
+  @Parameter(0)
+  public TestParameters parameters;
+
+  @Parameter(1)
+  public boolean enableArgumentPropagation;
 
   @Parameters(name = "{0}, argument propagation: {1}")
   public static List<Object[]> data() {
@@ -42,22 +52,17 @@
         getTestParameters().withAllRuntimesAndApiLevels().build(), BooleanUtils.values());
   }
 
-  public InvokeMethodWithReceiverOptimizationTest(
-      TestParameters parameters, boolean enableArgumentPropagation) {
-    this.parameters = parameters;
-    this.enableArgumentPropagation = enableArgumentPropagation;
+  @Test
+  public void testJvm() throws Exception {
+    parameters.assumeJvmTestParameters();
+    testForJvm(parameters)
+        .addTestClasspath()
+        .run(parameters.getRuntime(), TestClass.class)
+        .assertSuccessWithOutput(EXPECTED_OUTPUT);
   }
 
   @Test
-  public void test() throws Exception {
-    String expected =
-        StringUtils.joinLines(
-            "Caught NullPointerException from testRewriteToThrowNull",
-            "Caught NullPointerException from testRewriteToThrowNullWithCatchHandlers",
-            "Caught NullPointerException from testRewriteToThrowNullWithDeadCatchHandler");
-
-    testForJvm().addTestClasspath().run(TestClass.class).assertSuccessWithOutput(expected);
-
+  public void testR8() throws Exception {
     CodeInspector inspector =
         testForR8(parameters.getBackend())
             .addInnerClasses(InvokeMethodWithReceiverOptimizationTest.class)
@@ -71,7 +76,7 @@
             .addDontObfuscate()
             .setMinApi(parameters)
             .run(parameters.getRuntime(), TestClass.class)
-            .assertSuccessWithOutput(expected)
+            .assertSuccessWithOutput(EXPECTED_OUTPUT)
             .inspector();
 
     ClassSubject testClassSubject = inspector.clazz(TestClass.class);
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/uninstantiatedtypes/NestedInterfaceMethodTest.java b/src/test/java/com/android/tools/r8/ir/optimize/uninstantiatedtypes/NestedInterfaceMethodTest.java
index 837a84e..085002e 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/uninstantiatedtypes/NestedInterfaceMethodTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/uninstantiatedtypes/NestedInterfaceMethodTest.java
@@ -44,7 +44,7 @@
     String expectedOutput = StringUtils.lines("In A.m()", "In A.m()");
 
     if (parameters.isCfRuntime()) {
-      testForJvm()
+      testForJvm(parameters)
           .addTestClasspath()
           .run(parameters.getRuntime(), TestClass.class)
           .assertSuccessWithOutput(expectedOutput);
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/uninstantiatedtypes/ParameterRewritingTest.java b/src/test/java/com/android/tools/r8/ir/optimize/uninstantiatedtypes/ParameterRewritingTest.java
index 97f7fa7..9da3ee6 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/uninstantiatedtypes/ParameterRewritingTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/uninstantiatedtypes/ParameterRewritingTest.java
@@ -21,34 +21,39 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
 import org.junit.runners.Parameterized.Parameters;
 
 @RunWith(Parameterized.class)
 public class ParameterRewritingTest extends TestBase {
 
-  private final TestParameters parameters;
+  private static final String EXPECTED_OUTPUT =
+      StringUtils.lines(
+          "Factory.createStatic() -> null",
+          "Factory.createStaticWithUnused1() -> null",
+          "Factory.createStaticWithUnused2() -> null",
+          "Factory.createStaticWithUnused3() -> null",
+          "Factory.createStaticWithUnused4() -> null");
+
+  @Parameter(0)
+  public TestParameters parameters;
 
   @Parameters(name = "{0}")
   public static TestParametersCollection data() {
     return getTestParameters().withAllRuntimesAndApiLevels().build();
   }
 
-  public ParameterRewritingTest(TestParameters parameters) {
-    this.parameters = parameters;
+  @Test
+  public void testJvm() throws Exception {
+    parameters.assumeJvmTestParameters();
+    testForJvm(parameters)
+        .addTestClasspath()
+        .run(parameters.getRuntime(), TestClass.class)
+        .assertSuccessWithOutput(EXPECTED_OUTPUT);
   }
 
   @Test
-  public void test() throws Exception {
-    String expected =
-        StringUtils.lines(
-            "Factory.createStatic() -> null",
-            "Factory.createStaticWithUnused1() -> null",
-            "Factory.createStaticWithUnused2() -> null",
-            "Factory.createStaticWithUnused3() -> null",
-            "Factory.createStaticWithUnused4() -> null");
-
-    testForJvm().addTestClasspath().run(TestClass.class).assertSuccessWithOutput(expected);
-
+  public void testR8() throws Exception {
     CodeInspector inspector =
         testForR8(parameters.getBackend())
             .addInnerClasses(ParameterRewritingTest.class)
@@ -59,7 +64,7 @@
             .addDontObfuscate()
             .setMinApi(parameters)
             .run(parameters.getRuntime(), TestClass.class)
-            .assertSuccessWithOutput(expected)
+            .assertSuccessWithOutput(EXPECTED_OUTPUT)
             .inspector();
 
     ClassSubject factoryClassSubject = inspector.clazz(Factory.class);
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/uninstantiatedtypes/PrivateInstanceMethodCollisionTest.java b/src/test/java/com/android/tools/r8/ir/optimize/uninstantiatedtypes/PrivateInstanceMethodCollisionTest.java
index d47be6e..badd467 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/uninstantiatedtypes/PrivateInstanceMethodCollisionTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/uninstantiatedtypes/PrivateInstanceMethodCollisionTest.java
@@ -53,7 +53,7 @@
     String expectedOutput = StringUtils.lines("A#foo(B)", "A#foo(B, Object)");
 
     if (parameters.isCfRuntime() && !minification && !allowAccessModification) {
-      testForJvm()
+      testForJvm(parameters)
           .addTestClasspath()
           .run(parameters.getRuntime(), TestClass.class)
           .assertSuccessWithOutput(expectedOutput);
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/uninstantiatedtypes/VoidReturnTypeRewritingTest.java b/src/test/java/com/android/tools/r8/ir/optimize/uninstantiatedtypes/VoidReturnTypeRewritingTest.java
index ee007c8..1911b14 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/uninstantiatedtypes/VoidReturnTypeRewritingTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/uninstantiatedtypes/VoidReturnTypeRewritingTest.java
@@ -46,7 +46,7 @@
             "SubSubFactory.createVirtual() -> null");
 
     if (parameters.isCfRuntime()) {
-      testForJvm()
+      testForJvm(parameters)
           .addTestClasspath()
           .run(parameters.getRuntime(), TestClass.class)
           .assertSuccessWithOutput(expected);
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/PrivateInstanceMethodCollisionTest.java b/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/PrivateInstanceMethodCollisionTest.java
index b6036fc..30c55f2 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/PrivateInstanceMethodCollisionTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/PrivateInstanceMethodCollisionTest.java
@@ -53,7 +53,7 @@
     String expectedOutput = StringUtils.lines("A#foo(used)", "A#foo(used, Object)");
 
     if (parameters.isCfRuntime() && !minification && !allowAccessModification) {
-      testForJvm()
+      testForJvm(parameters)
           .addTestClasspath()
           .run(parameters.getRuntime(), TestClass.class)
           .assertSuccessWithOutput(expectedOutput);
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/UnusedArgumentsBootstrapTest.java b/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/UnusedArgumentsBootstrapTest.java
index 0d3f3cb..3abde50 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/UnusedArgumentsBootstrapTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/UnusedArgumentsBootstrapTest.java
@@ -5,32 +5,32 @@
 package com.android.tools.r8.ir.optimize.unusedarguments;
 
 import com.android.tools.r8.TestBase;
-import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
 import org.junit.runners.Parameterized.Parameters;
 
 @RunWith(Parameterized.class)
 public class UnusedArgumentsBootstrapTest extends TestBase {
 
-  private final Backend backend;
+  @Parameter(0)
+  public TestParameters parameters;
 
-  @Parameters(name = "Backend: {0}")
-  public static Backend[] data() {
-    return ToolHelper.getBackends();
-  }
-
-  public UnusedArgumentsBootstrapTest(Backend backend) {
-    this.backend = backend;
+  @Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withAllRuntimesAndApiLevels().build();
   }
 
   @Test
   public void test() throws Exception {
-    testForR8(backend)
+    testForR8(parameters.getBackend())
         .addInnerClasses(UnusedArgumentsBootstrapTest.class)
         .addKeepMainRule(TestClass.class)
-        .run(TestClass.class)
+        .setMinApi(parameters)
+        .run(parameters.getRuntime(), TestClass.class)
         .assertSuccessWithOutput("Hello");
   }
 
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/UnusedArgumentsCollisionTest.java b/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/UnusedArgumentsCollisionTest.java
index a4e68c7..d772b8f 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/UnusedArgumentsCollisionTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/UnusedArgumentsCollisionTest.java
@@ -49,7 +49,7 @@
     String expectedOutput = StringUtils.lines("Hello world", "Hello world");
 
     if (parameters.isCfRuntime() && !minification) {
-      testForJvm()
+      testForJvm(parameters)
           .addTestClasspath()
           .run(parameters.getRuntime(), TestClass.class)
           .assertSuccessWithOutput(expectedOutput);
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/UnusedArgumentsInstanceConstructorCollisionTest.java b/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/UnusedArgumentsInstanceConstructorCollisionTest.java
index 1e24b24..557eb17 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/UnusedArgumentsInstanceConstructorCollisionTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/UnusedArgumentsInstanceConstructorCollisionTest.java
@@ -5,35 +5,35 @@
 package com.android.tools.r8.ir.optimize.unusedarguments;
 
 import com.android.tools.r8.TestBase;
-import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
 import com.android.tools.r8.utils.StringUtils;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
 import org.junit.runners.Parameterized.Parameters;
 
 /** Regression test for b/127691114. */
 @RunWith(Parameterized.class)
 public class UnusedArgumentsInstanceConstructorCollisionTest extends TestBase {
 
-  private final Backend backend;
+  @Parameter(0)
+  public TestParameters parameters;
 
-  @Parameters(name = "Backend: {0}")
-  public static Backend[] parameters() {
-    return ToolHelper.getBackends();
-  }
-
-  public UnusedArgumentsInstanceConstructorCollisionTest(Backend backend) {
-    this.backend = backend;
+  @Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withAllRuntimesAndApiLevels().build();
   }
 
   @Test
   public void test() throws Exception {
     String expectedOutput = StringUtils.lines("C");
-    testForR8(backend)
+    testForR8(parameters.getBackend())
         .addInnerClasses(UnusedArgumentsInstanceConstructorCollisionTest.class)
         .addKeepMainRule(TestClass.class)
-        .run(TestClass.class)
+        .setMinApi(parameters)
+        .run(parameters.getRuntime(), TestClass.class)
         .assertSuccessWithOutput(expectedOutput);
   }
 
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/UnusedArgumentsInstanceConstructorTest.java b/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/UnusedArgumentsInstanceConstructorTest.java
index b763bb2..3132af2 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/UnusedArgumentsInstanceConstructorTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/UnusedArgumentsInstanceConstructorTest.java
@@ -44,7 +44,7 @@
     String expectedOutput = StringUtils.lines("Hello world");
 
     if (parameters.isCfRuntime()) {
-      testForJvm()
+      testForJvm(parameters)
           .addTestClasspath()
           .run(parameters.getRuntime(), TestClass.class)
           .assertSuccessWithOutput(expectedOutput);
diff --git a/src/test/java/com/android/tools/r8/jasmin/InvalidDebugInfoTests.java b/src/test/java/com/android/tools/r8/jasmin/InvalidDebugInfoTests.java
index 255264d..4609a89 100644
--- a/src/test/java/com/android/tools/r8/jasmin/InvalidDebugInfoTests.java
+++ b/src/test/java/com/android/tools/r8/jasmin/InvalidDebugInfoTests.java
@@ -22,6 +22,7 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
 import org.junit.runners.Parameterized.Parameters;
 
 @RunWith(Parameterized.class)
@@ -34,13 +35,11 @@
         BooleanUtils.values());
   }
 
-  private final TestParameters parameters;
-  private final boolean strict;
+  @Parameter(0)
+  public TestParameters parameters;
 
-  public InvalidDebugInfoTests(TestParameters parameters, boolean strict) {
-    this.parameters = parameters;
-    this.strict = strict;
-  }
+  @Parameter(1)
+  public boolean strict;
 
   private void optionsModification(InternalOptions options) {
     options.invalidDebugInfoStrict = strict;
@@ -122,8 +121,8 @@
         "  return");
 
     String expected = "42" + ToolHelper.LINE_SEPARATOR + "0" + ToolHelper.LINE_SEPARATOR;
-    if (parameters.isCfRuntime()) {
-      testForJvm()
+    if (parameters.isJvmTestParameters()) {
+      testForJvm(parameters)
           .addProgramClassFileData(builder.buildClasses())
           .run(parameters.getRuntime(), clazz.name)
           .assertSuccessWithOutput(expected);
@@ -187,8 +186,8 @@
         "  return");
 
     String expected = "42" + ToolHelper.LINE_SEPARATOR;
-    if (parameters.isCfRuntime()) {
-      testForJvm()
+    if (parameters.isJvmTestParameters()) {
+      testForJvm(parameters)
           .addProgramClassFileData(builder.buildClasses())
           .run(parameters.getRuntime(), clazz.name)
           .assertSuccessWithOutput(expected);
@@ -244,8 +243,8 @@
         "  return");
 
     String expected = StringUtils.lines("42", "7.5");
-    if (parameters.isCfRuntime()) {
-      testForJvm()
+    if (parameters.isJvmTestParameters()) {
+      testForJvm(parameters)
           .addProgramClassFileData(builder.buildClasses())
           .run(parameters.getRuntime(), clazz.name)
           .assertSuccessWithOutput(expected);
@@ -303,8 +302,8 @@
         "  return");
 
     String expected = StringUtils.lines("42", "7.5");
-    if (parameters.isCfRuntime()) {
-      testForJvm()
+    if (parameters.isJvmTestParameters()) {
+      testForJvm(parameters)
           .addProgramClassFileData(builder.buildClasses())
           .run(parameters.getRuntime(), clazz.name)
           .assertSuccessWithOutput(expected);
@@ -362,8 +361,8 @@
         "  return");
 
     String expected = StringUtils.lines("42");
-    if (parameters.isCfRuntime()) {
-      testForJvm()
+    if (parameters.isJvmTestParameters()) {
+      testForJvm(parameters)
           .addProgramClassFileData(builder.buildClasses())
           .run(parameters.getRuntime(), clazz.name)
           .assertSuccessWithOutput(expected);
@@ -429,8 +428,8 @@
         "  return");
 
     String expected = StringUtils.lines("42");
-    if (parameters.isCfRuntime()) {
-      testForJvm()
+    if (parameters.isJvmTestParameters()) {
+      testForJvm(parameters)
           .addProgramClassFileData(builder.buildClasses())
           .run(parameters.getRuntime(), clazz.name)
           .assertSuccessWithOutput(expected);
diff --git a/src/test/java/com/android/tools/r8/jasmin/Regress65432240.java b/src/test/java/com/android/tools/r8/jasmin/Regress65432240.java
index 6658dd1..a1e052b 100644
--- a/src/test/java/com/android/tools/r8/jasmin/Regress65432240.java
+++ b/src/test/java/com/android/tools/r8/jasmin/Regress65432240.java
@@ -3,45 +3,49 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.jasmin;
 
-import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
 
-import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
 import com.android.tools.r8.jasmin.JasminBuilder.ClassFileVersion;
-import com.android.tools.r8.naming.MemberNaming.MethodSignature;
-import com.android.tools.r8.utils.AndroidApp;
 import com.android.tools.r8.utils.codeinspector.CfInstructionSubject;
 import com.android.tools.r8.utils.codeinspector.ClassSubject;
-import com.android.tools.r8.utils.codeinspector.CodeInspector;
 import com.android.tools.r8.utils.codeinspector.InstructionSubject;
 import com.android.tools.r8.utils.codeinspector.MethodSubject;
 import com.google.common.collect.ImmutableList;
-import java.util.Collections;
 import java.util.Iterator;
+import java.util.List;
+import org.junit.BeforeClass;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
 
 @RunWith(Parameterized.class)
 public class Regress65432240 extends JasminTestBase {
 
-  private Backend backend;
+  private static final String EXPECTED_OUTPUT = "00";
 
-  @Parameterized.Parameters(name = "Backend: {0}")
-  public static Backend[] data() {
-    return ToolHelper.getBackends();
+  private static List<byte[]> programClassFileData;
+
+  @Parameter(0)
+  public TestParameters parameters;
+
+  @Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withAllRuntimesAndApiLevels().build();
   }
 
-  public Regress65432240(Backend backend) {
-    this.backend = backend;
-  }
-
-  @Test
-  public void testConstantNotIntoEntryBlock() throws Exception {
+  @BeforeClass
+  public static void setup() throws Exception {
     JasminBuilder builder = new JasminBuilder(ClassFileVersion.JDK_1_4);
     JasminBuilder.ClassBuilder clazz = builder.addClass("Test");
 
-    MethodSignature signature = clazz.addStaticMethod("test1", ImmutableList.of("I"), "I",
+    clazz.addStaticMethod(
+        "test1",
+        ImmutableList.of("I"),
+        "I",
         ".limit stack 3",
         ".limit locals 2",
         "  iload 0",
@@ -73,41 +77,45 @@
         "  invokevirtual java/io/PrintStream/print(Ljava/lang/String;)V",
         "  return");
 
-    String expected = runOnJava(builder, clazz.name);
+    programClassFileData = builder.buildClasses();
+  }
 
-    AndroidApp originalApplication = builder.build();
-    AndroidApp processedApplication =
-        ToolHelper.runR8(
-            ToolHelper.prepareR8CommandBuilder(originalApplication, emptyConsumer(backend))
-                .addLibraryFiles(runtimeJar(backend))
-                .setDisableTreeShaking(true)
-                .setDisableMinification(true)
-                .build());
+  @Test
+  public void testJvm() throws Exception {
+    parameters.assumeJvmTestParameters();
+    testForJvm(parameters)
+        .addProgramClassFileData(programClassFileData)
+        .run(parameters.getRuntime(), "Test")
+        .assertSuccessWithOutput(EXPECTED_OUTPUT);
+  }
 
-    CodeInspector inspector = new CodeInspector(processedApplication);
-    ClassSubject inspectedClass = inspector.clazz(clazz.name);
-    MethodSubject method = inspectedClass.method(signature);
-    assertTrue(method.isPresent());
-    Iterator<InstructionSubject> iterator = method.iterateInstructions();
-    InstructionSubject instruction = null;
-    boolean found = false;
-    while (iterator.hasNext()) {
-      instruction = iterator.next();
-      if (!(instruction instanceof CfInstructionSubject)
-          || !((CfInstructionSubject) instruction).isLoad()) {
-        found = true;
-        break;
-      }
-    }
-    assertTrue(found && instruction.isIfNez());
-
-    String result;
-    if (backend == Backend.DEX) {
-      result = runOnArt(processedApplication, clazz.name);
-    } else {
-      assert backend == Backend.CF;
-      result = runOnJava(processedApplication, clazz.name, Collections.emptyList());
-    }
-    assertEquals(expected, result);
+  @Test
+  public void testConstantNotIntoEntryBlock() throws Exception {
+    testForR8(parameters.getBackend())
+        .addProgramClassFileData(programClassFileData)
+        .addDontObfuscate()
+        .addDontShrink()
+        .setMinApi(parameters)
+        .compile()
+        .inspect(
+            inspector -> {
+              ClassSubject inspectedClass = inspector.clazz("Test");
+              MethodSubject method = inspectedClass.uniqueMethodWithOriginalName("test1");
+              assertTrue(method.isPresent());
+              Iterator<InstructionSubject> iterator = method.iterateInstructions();
+              InstructionSubject instruction = null;
+              boolean found = false;
+              while (iterator.hasNext()) {
+                instruction = iterator.next();
+                if (!(instruction instanceof CfInstructionSubject)
+                    || !((CfInstructionSubject) instruction).isLoad()) {
+                  found = true;
+                  break;
+                }
+              }
+              assertTrue(found && instruction.isIfNez());
+            })
+        .run(parameters.getRuntime(), "Test")
+        .assertSuccessWithOutput(EXPECTED_OUTPUT);
   }
 }
diff --git a/src/test/java/com/android/tools/r8/java_language/pattern_matching_for_instenceof/PattternMatchingForInstanceOfTest.java b/src/test/java/com/android/tools/r8/java_language/pattern_matching_for_instenceof/PattternMatchingForInstanceOfTest.java
index 7030b32..531499f 100644
--- a/src/test/java/com/android/tools/r8/java_language/pattern_matching_for_instenceof/PattternMatchingForInstanceOfTest.java
+++ b/src/test/java/com/android/tools/r8/java_language/pattern_matching_for_instenceof/PattternMatchingForInstanceOfTest.java
@@ -41,7 +41,7 @@
   @Test
   public void testD8AndJvm() throws Exception {
     if (parameters.isCfRuntime()) {
-      testForJvm()
+      testForJvm(parameters)
           .addRunClasspathFiles(JAR)
           .run(parameters.getRuntime(), MAIN)
           .assertSuccessWithOutputLines(EXPECTED);
@@ -65,7 +65,7 @@
     if (parameters.getBackend().isDex()) {
       builder.run(parameters.getRuntime(), MAIN).assertSuccessWithOutputLines(EXPECTED);
     } else {
-      testForJvm()
+      testForJvm(parameters)
           .addRunClasspathFiles(builder.compile().writeToZip())
           .run(parameters.getRuntime(), MAIN)
           .assertSuccessWithOutputLines(EXPECTED);
diff --git a/src/test/java/com/android/tools/r8/keepanno/KeepEdgeAnnotationsTest.java b/src/test/java/com/android/tools/r8/keepanno/KeepEdgeAnnotationsTest.java
index 7d6204b..1864fba 100644
--- a/src/test/java/com/android/tools/r8/keepanno/KeepEdgeAnnotationsTest.java
+++ b/src/test/java/com/android/tools/r8/keepanno/KeepEdgeAnnotationsTest.java
@@ -115,7 +115,7 @@
     // The source is added as a classpath name but not part of the compilation unit output.
     assertThat(inspector.clazz(source), isAbsent());
 
-    testForJvm()
+    testForJvm(parameters)
         .addProgramClassesAndInnerClasses(source)
         .addProgramFiles(out)
         .run(parameters.getRuntime(), source)
@@ -132,7 +132,7 @@
             .addClasspathFiles(KEEP_ANNO_PATH)
             .addClasspathFiles(ToolHelper.DEPS)
             .compile();
-    testForJvm()
+    testForJvm(parameters)
         .addProgramFiles(out)
         .run(parameters.getRuntime(), source)
         .assertSuccessWithOutput(getExpected())
diff --git a/src/test/java/com/android/tools/r8/kotlin/lambda/KotlinLambdaMergingCapturesKotlinStyleTest.java b/src/test/java/com/android/tools/r8/kotlin/lambda/KotlinLambdaMergingCapturesKotlinStyleTest.java
index 063691c..f4db832 100644
--- a/src/test/java/com/android/tools/r8/kotlin/lambda/KotlinLambdaMergingCapturesKotlinStyleTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/lambda/KotlinLambdaMergingCapturesKotlinStyleTest.java
@@ -64,7 +64,7 @@
     assumeFalse(allowAccessModification);
     assumeTrue(parameters.isCfRuntime());
     assumeTrue(kotlinParameters.isFirst());
-    testForJvm()
+    testForJvm(parameters)
         .addProgramFiles(getProgramFiles())
         .run(parameters.getRuntime(), getMainClassName())
         .assertSuccessWithOutput(getExpectedOutput());
diff --git a/src/test/java/com/android/tools/r8/kotlin/lambda/KotlinLambdaMergingKeepAttributesKotlinStyleTest.java b/src/test/java/com/android/tools/r8/kotlin/lambda/KotlinLambdaMergingKeepAttributesKotlinStyleTest.java
index d884748..37bb113 100644
--- a/src/test/java/com/android/tools/r8/kotlin/lambda/KotlinLambdaMergingKeepAttributesKotlinStyleTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/lambda/KotlinLambdaMergingKeepAttributesKotlinStyleTest.java
@@ -70,7 +70,7 @@
     assumeFalse(allowAccessModification);
     assumeTrue(parameters.isCfRuntime());
     assumeTrue(kotlinParameters.isFirst());
-    testForJvm()
+    testForJvm(parameters)
         .addProgramFiles(getProgramFiles())
         .run(parameters.getRuntime(), getMainClassName())
         .assertSuccessWithOutput(getExpectedOutput());
diff --git a/src/test/java/com/android/tools/r8/kotlin/lambda/KotlinLambdaMergingSingletonTest.java b/src/test/java/com/android/tools/r8/kotlin/lambda/KotlinLambdaMergingSingletonTest.java
index 1b2fa95..695849f 100644
--- a/src/test/java/com/android/tools/r8/kotlin/lambda/KotlinLambdaMergingSingletonTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/lambda/KotlinLambdaMergingSingletonTest.java
@@ -64,7 +64,7 @@
     assumeFalse(allowAccessModification);
     assumeTrue(parameters.isCfRuntime());
     assumeTrue(kotlinParameters.isFirst());
-    testForJvm()
+    testForJvm(parameters)
         .addProgramFiles(getProgramFiles())
         .run(parameters.getRuntime(), getMainClassName())
         .assertSuccessWithOutput(getExpectedOutput());
diff --git a/src/test/java/com/android/tools/r8/kotlin/lambda/KotlinLambdaMergingTrivialJavaStyleTest.java b/src/test/java/com/android/tools/r8/kotlin/lambda/KotlinLambdaMergingTrivialJavaStyleTest.java
index 948f074..0e311ce 100644
--- a/src/test/java/com/android/tools/r8/kotlin/lambda/KotlinLambdaMergingTrivialJavaStyleTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/lambda/KotlinLambdaMergingTrivialJavaStyleTest.java
@@ -65,7 +65,7 @@
     assumeFalse(allowAccessModification);
     assumeTrue(parameters.isCfRuntime());
     assumeTrue(kotlinParameters.isFirst());
-    testForJvm()
+    testForJvm(parameters)
         .addProgramFiles(getProgramFiles())
         .run(parameters.getRuntime(), getMainClassName())
         .assertSuccessWithOutput(getExpectedOutput());
diff --git a/src/test/java/com/android/tools/r8/kotlin/lambda/KotlinLambdaMergingTrivialKotlinStyleTest.java b/src/test/java/com/android/tools/r8/kotlin/lambda/KotlinLambdaMergingTrivialKotlinStyleTest.java
index 3dac45b..2dc729e 100644
--- a/src/test/java/com/android/tools/r8/kotlin/lambda/KotlinLambdaMergingTrivialKotlinStyleTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/lambda/KotlinLambdaMergingTrivialKotlinStyleTest.java
@@ -64,7 +64,7 @@
     assumeFalse(allowAccessModification);
     assumeTrue(parameters.isCfRuntime());
     assumeTrue(kotlinParameters.isFirst());
-    testForJvm()
+    testForJvm(parameters)
         .addProgramFiles(getProgramFiles())
         .run(parameters.getRuntime(), getMainClassName())
         .assertSuccessWithOutput(getExpectedOutput());
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataFirstToLatestTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataFirstToLatestTest.java
index de1e83c..0248459 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataFirstToLatestTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataFirstToLatestTest.java
@@ -141,7 +141,7 @@
             .setOutputPath(temp.newFolder().toPath())
             .noStdLib()
             .compile();
-    testForJvm()
+    testForJvm(parameters)
         .addRunClasspathFiles(stdLibJar, libJar)
         .addClasspath(output)
         .run(parameters.getRuntime(), PKG_APP + ".MainKt")
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataPrimitiveTypeRewriteTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataPrimitiveTypeRewriteTest.java
index 9406052..736520f 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataPrimitiveTypeRewriteTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataPrimitiveTypeRewriteTest.java
@@ -62,7 +62,7 @@
                 getKotlinFileInTest(DescriptorUtils.getBinaryNameFromJavaType(PKG_APP), "main"))
             .setOutputPath(temp.newFolder().toPath())
             .compile();
-    testForJvm()
+    testForJvm(parameters)
         .addRunClasspathFiles(kotlinc.getKotlinStdlibJar(), libJar)
         .addClasspath(output)
         .run(parameters.getRuntime(), PKG_APP + ".MainKt")
@@ -113,7 +113,7 @@
       return;
     }
     final JvmTestRunResult runResult =
-        testForJvm()
+        testForJvm(parameters)
             .addRunClasspathFiles(kotlinc.getKotlinStdlibJar(), libJar)
             .addClasspath(output)
             .run(parameters.getRuntime(), PKG_APP + ".MainKt");
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteAllowAccessModificationTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteAllowAccessModificationTest.java
index 6afe963..a1fe961 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteAllowAccessModificationTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteAllowAccessModificationTest.java
@@ -80,7 +80,7 @@
                 getKotlinFileInTest(DescriptorUtils.getBinaryNameFromJavaType(PKG_APP), "main"))
             .setOutputPath(temp.newFolder().toPath())
             .compile();
-    testForJvm()
+    testForJvm(parameters)
         .addRunClasspathFiles(kotlinc.getKotlinStdlibJar(), libJar)
         .addClasspath(output)
         .run(parameters.getRuntime(), PKG_APP + ".MainKt")
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteAnnotationTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteAnnotationTest.java
index 1306816..b0dd01c 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteAnnotationTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteAnnotationTest.java
@@ -89,7 +89,7 @@
                 getKotlinFileInTest(DescriptorUtils.getBinaryNameFromJavaType(PKG_APP), "main"))
             .setOutputPath(temp.newFolder().toPath())
             .compile();
-    testForJvm()
+    testForJvm(parameters)
         .addRunClasspathFiles(kotlinc.getKotlinStdlibJar(), kotlinc.getKotlinReflectJar(), libJar)
         .addClasspath(output)
         .run(parameters.getRuntime(), PKG_APP + ".MainKt")
@@ -140,7 +140,7 @@
     if (kotlinParameters.isOlderThan(KOTLINC_1_4_20)) {
       return;
     }
-    testForJvm()
+    testForJvm(parameters)
         .addRunClasspathFiles(kotlinc.getKotlinStdlibJar(), kotlinc.getKotlinReflectJar(), libJar)
         .addProgramFiles(output)
         .run(parameters.getRuntime(), PKG_APP + ".MainKt")
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteAnonymousTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteAnonymousTest.java
index a961f9e..9ab42de 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteAnonymousTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteAnonymousTest.java
@@ -56,7 +56,7 @@
             .addSourceFiles(getKotlinFileInTest(PKG_PREFIX + "/anonymous_app", "main"))
             .setOutputPath(temp.newFolder().toPath())
             .compile();
-    testForJvm()
+    testForJvm(parameters)
         .addRunClasspathFiles(kotlinc.getKotlinStdlibJar(), libJar)
         .addClasspath(output)
         .run(parameters.getRuntime(), PKG + ".anonymous_app.MainKt")
@@ -89,7 +89,7 @@
     if (kotlinParameters.isOlderThan(KOTLINC_1_4_20)) {
       return;
     }
-    testForJvm()
+    testForJvm(parameters)
         .addRunClasspathFiles(kotlinc.getKotlinStdlibJar(), libJar)
         .addClasspath(main)
         .run(parameters.getRuntime(), PKG + ".anonymous_app.MainKt")
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteBoxedTypesTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteBoxedTypesTest.java
index bcbc386..2ad78ea 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteBoxedTypesTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteBoxedTypesTest.java
@@ -47,7 +47,7 @@
             .addSourceFiles(getKotlinFileInTest(PKG_PREFIX + "/box_primitives_app", "main"))
             .setOutputPath(temp.newFolder().toPath())
             .compile();
-    testForJvm()
+    testForJvm(parameters)
         .addRunClasspathFiles(kotlinc.getKotlinStdlibJar(), libJar)
         .addClasspath(output)
         .run(parameters.getRuntime(), PKG + ".box_primitives_app.MainKt")
@@ -63,7 +63,7 @@
             .addSourceFiles(getKotlinFileInTest(PKG_PREFIX + "/box_primitives_app", "main_reflect"))
             .setOutputPath(temp.newFolder().toPath())
             .compile();
-    testForJvm()
+    testForJvm(parameters)
         .addVmArguments("-ea")
         .addRunClasspathFiles(kotlinc.getKotlinStdlibJar(), kotlinc.getKotlinReflectJar(), libJar)
         .addClasspath(output)
@@ -98,7 +98,7 @@
             .addSourceFiles(getKotlinFileInTest(PKG_PREFIX + "/box_primitives_app", "main"))
             .setOutputPath(temp.newFolder().toPath())
             .compile();
-    testForJvm()
+    testForJvm(parameters)
         .addRunClasspathFiles(kotlinc.getKotlinStdlibJar(), kotlinc.getKotlinReflectJar(), libJar)
         .addClasspath(main)
         .run(parameters.getRuntime(), PKG + ".box_primitives_app.MainKt")
@@ -125,7 +125,7 @@
             .addSourceFiles(getKotlinFileInTest(PKG_PREFIX + "/box_primitives_app", "main_reflect"))
             .setOutputPath(temp.newFolder().toPath())
             .compile();
-    testForJvm()
+    testForJvm(parameters)
         .addVmArguments("-ea")
         .addRunClasspathFiles(kotlinc.getKotlinStdlibJar(), kotlinc.getKotlinReflectJar(), libJar)
         .addClasspath(main)
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteContextReceiverTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteContextReceiverTest.java
index 102a056..b3254b9 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteContextReceiverTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteContextReceiverTest.java
@@ -82,7 +82,7 @@
             .setOutputPath(temp.newFolder().toPath())
             .enableExperimentalContextReceivers()
             .compile();
-    testForJvm()
+    testForJvm(parameters)
         .addRunClasspathFiles(
             kotlinc.getKotlinStdlibJar(),
             kotlinc.getKotlinReflectJar(),
@@ -124,7 +124,7 @@
             .setOutputPath(temp.newFolder().toPath())
             .enableExperimentalContextReceivers()
             .compile();
-    testForJvm()
+    testForJvm(parameters)
         .addRunClasspathFiles(kotlinc.getKotlinStdlibJar(), kotlinc.getKotlinReflectJar(), libJar)
         .addClasspath(main)
         .run(parameters.getRuntime(), MAIN)
@@ -184,7 +184,7 @@
             .enableExperimentalContextReceivers()
             .compile();
 
-    testForJvm()
+    testForJvm(parameters)
         .addRunClasspathFiles(kotlinc.getKotlinStdlibJar(), libJar)
         .addClasspath(output)
         .run(parameters.getRuntime(), MAIN)
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteCrossinlineAnonFunctionTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteCrossinlineAnonFunctionTest.java
index cf5d1eb..5cb9619 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteCrossinlineAnonFunctionTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteCrossinlineAnonFunctionTest.java
@@ -49,7 +49,7 @@
                 getKotlinFileInTest(DescriptorUtils.getBinaryNameFromJavaType(PKG_APP), "main"))
             .setOutputPath(temp.newFolder().toPath())
             .compile();
-    testForJvm()
+    testForJvm(parameters)
         .addRunClasspathFiles(kotlinc.getKotlinStdlibJar(), libJar)
         .addClasspath(output)
         .run(parameters.getRuntime(), PKG_APP + ".MainKt")
@@ -72,7 +72,7 @@
             .addSourceFiles(
                 getKotlinFileInTest(DescriptorUtils.getBinaryNameFromJavaType(PKG_APP), "main"))
             .compile();
-    testForJvm()
+    testForJvm(parameters)
         .addRunClasspathFiles(kotlinc.getKotlinStdlibJar(), libJar)
         .addProgramFiles(output)
         .run(parameters.getRuntime(), PKG_APP + ".MainKt")
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteCrossinlineBlockTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteCrossinlineBlockTest.java
index 5396f4d..dd071e3 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteCrossinlineBlockTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteCrossinlineBlockTest.java
@@ -53,7 +53,7 @@
                 getKotlinFileInTest(DescriptorUtils.getBinaryNameFromJavaType(PKG_APP), "main"))
             .setOutputPath(temp.newFolder().toPath())
             .compile();
-    testForJvm()
+    testForJvm(parameters)
         .addRunClasspathFiles(kotlinc.getKotlinStdlibJar(), libJar)
         .addClasspath(output)
         .run(parameters.getRuntime(), PKG_APP + ".MainKt")
@@ -77,7 +77,7 @@
                 getKotlinFileInTest(DescriptorUtils.getBinaryNameFromJavaType(PKG_APP), "main"))
             .setOutputPath(temp.newFolder().toPath())
             .compile();
-    testForJvm()
+    testForJvm(parameters)
         .addRunClasspathFiles(kotlinc.getKotlinStdlibJar(), libJar)
         .addClasspath(output)
         .run(parameters.getRuntime(), PKG_APP + ".MainKt")
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteCrossinlineConcreteFunctionTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteCrossinlineConcreteFunctionTest.java
index 52bdbb6..242c684 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteCrossinlineConcreteFunctionTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteCrossinlineConcreteFunctionTest.java
@@ -49,7 +49,7 @@
                 getKotlinFileInTest(DescriptorUtils.getBinaryNameFromJavaType(PKG_APP), "main"))
             .setOutputPath(temp.newFolder().toPath())
             .compile();
-    testForJvm()
+    testForJvm(parameters)
         .addRunClasspathFiles(kotlinc.getKotlinStdlibJar(), libJar)
         .addClasspath(output)
         .run(parameters.getRuntime(), PKG_APP + ".MainKt")
@@ -73,7 +73,7 @@
                 getKotlinFileInTest(DescriptorUtils.getBinaryNameFromJavaType(PKG_APP), "main"))
             .setOutputPath(temp.newFolder().toPath())
             .compile();
-    testForJvm()
+    testForJvm(parameters)
         .addRunClasspathFiles(kotlinc.getKotlinStdlibJar(), libJar)
         .addClasspath(output)
         .run(parameters.getRuntime(), PKG_APP + ".MainKt")
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteDelegatedPropertyTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteDelegatedPropertyTest.java
index 36efb33..44a9963 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteDelegatedPropertyTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteDelegatedPropertyTest.java
@@ -74,7 +74,7 @@
                 getKotlinFileInTest(DescriptorUtils.getBinaryNameFromJavaType(PKG_APP), "main"))
             .setOutputPath(temp.newFolder().toPath())
             .compile();
-    testForJvm()
+    testForJvm(parameters)
         .addRunClasspathFiles(kotlinc.getKotlinStdlibJar(), kotlinc.getKotlinReflectJar(), libJar)
         .addClasspath(output)
         .run(parameters.getRuntime(), PKG_APP + ".MainKt")
@@ -102,7 +102,7 @@
                 getKotlinFileInTest(DescriptorUtils.getBinaryNameFromJavaType(PKG_APP), "main"))
             .setOutputPath(temp.newFolder().toPath())
             .compile();
-    testForJvm()
+    testForJvm(parameters)
         .addRunClasspathFiles(
             kotlinc.getKotlinStdlibJar(), kotlinc.getKotlinReflectJar(), outputJar)
         .addClasspath(main)
@@ -131,7 +131,7 @@
             .setOutputPath(outputPath)
             .compileRaw();
     if (kotlinParameters.isNewerThan(KOTLINC_1_8_0)) {
-      testForJvm()
+      testForJvm(parameters)
           .addRunClasspathFiles(
               kotlinc.getKotlinStdlibJar(), kotlinc.getKotlinReflectJar(), outputJar)
           .addClasspath(outputPath)
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteFlexibleUpperBoundTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteFlexibleUpperBoundTest.java
index 8282926..4a7d3b8 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteFlexibleUpperBoundTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteFlexibleUpperBoundTest.java
@@ -65,7 +65,7 @@
             .addSourceFiles(getKotlinFileInTest(PKG_PREFIX + "/flexible_upper_bound_app", "main"))
             .setOutputPath(temp.newFolder().toPath())
             .compile();
-    testForJvm()
+    testForJvm(parameters)
         .addRunClasspathFiles(kotlinc.getKotlinStdlibJar(), libJar)
         .addClasspath(output)
         .run(parameters.getRuntime(), PKG + ".flexible_upper_bound_app.MainKt")
@@ -99,7 +99,7 @@
     if (kotlinParameters.isOlderThan(KOTLINC_1_4_20)) {
       return;
     }
-    testForJvm()
+    testForJvm(parameters)
         .addRunClasspathFiles(kotlinc.getKotlinStdlibJar(), kotlinc.getKotlinReflectJar(), libJar)
         .addClasspath(main)
         .run(parameters.getRuntime(), PKG + ".flexible_upper_bound_app.MainKt")
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInClasspathTypeTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInClasspathTypeTest.java
index ff9ff36..36adf2f 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInClasspathTypeTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInClasspathTypeTest.java
@@ -73,7 +73,7 @@
             .setOutputPath(temp.newFolder().toPath())
             .compile();
 
-    testForJvm()
+    testForJvm(parameters)
         .addRunClasspathFiles(kotlinc.getKotlinStdlibJar(), baseLibJar, extLibJar)
         .addClasspath(output)
         .run(parameters.getRuntime(), PKG + ".classpath_app.MainKt")
@@ -110,7 +110,7 @@
       return;
     }
 
-    testForJvm()
+    testForJvm(parameters)
         .addRunClasspathFiles(kotlinc.getKotlinStdlibJar(), baseLibJar, libJar)
         .addClasspath(output)
         .run(parameters.getRuntime(), PKG + ".classpath_app.MainKt")
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInCompanionTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInCompanionTest.java
index 2232747..ed897d2 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInCompanionTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInCompanionTest.java
@@ -73,7 +73,7 @@
             .setOutputPath(temp.newFolder().toPath())
             .compile();
 
-    testForJvm()
+    testForJvm(parameters)
         .addRunClasspathFiles(kotlinc.getKotlinStdlibJar(), libJar)
         .addClasspath(output)
         .run(parameters.getRuntime(), PKG + ".companion_app.MainKt")
@@ -105,7 +105,7 @@
             .setOutputPath(temp.newFolder().toPath())
             .compile();
 
-    testForJvm()
+    testForJvm(parameters)
         .addRunClasspathFiles(kotlinc.getKotlinStdlibJar(), libJar)
         .addClasspath(output)
         .run(parameters.getRuntime(), PKG + ".companion_app.MainKt")
@@ -153,7 +153,7 @@
       return;
     }
 
-    testForJvm()
+    testForJvm(parameters)
         .addRunClasspathFiles(kotlinc.getKotlinStdlibJar(), libJar)
         .addClasspath(output)
         .run(parameters.getRuntime(), PKG + ".companion_app.MainKt")
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInExtensionFunctionTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInExtensionFunctionTest.java
index eefafd8..9be3d81 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInExtensionFunctionTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInExtensionFunctionTest.java
@@ -79,7 +79,7 @@
             .setOutputPath(temp.newFolder().toPath())
             .compile();
 
-    testForJvm()
+    testForJvm(parameters)
         .addRunClasspathFiles(kotlinc.getKotlinStdlibJar(), libJar)
         .addClasspath(output)
         .run(parameters.getRuntime(), PKG + ".extension_function_app.MainKt")
@@ -125,7 +125,7 @@
       return;
     }
 
-    testForJvm()
+    testForJvm(parameters)
         .addRunClasspathFiles(kotlinc.getKotlinStdlibJar(), libJar)
         .addClasspath(output)
         .run(parameters.getRuntime(), PKG + ".extension_function_app.MainKt")
@@ -182,7 +182,7 @@
       return;
     }
 
-    testForJvm()
+    testForJvm(parameters)
         .addRunClasspathFiles(kotlinc.getKotlinStdlibJar(), libJar)
         .addClasspath(output)
         .run(parameters.getRuntime(), PKG + ".extension_function_app.MainKt")
@@ -262,7 +262,7 @@
       return;
     }
 
-    testForJvm()
+    testForJvm(parameters)
         .addRunClasspathFiles(kotlinc.getKotlinStdlibJar(), libJar)
         .addClasspath(output)
         .run(parameters.getRuntime(), PKG + ".extension_function_app.MainKt")
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInExtensionPropertyTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInExtensionPropertyTest.java
index 02aa7a2..eb187fd 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInExtensionPropertyTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInExtensionPropertyTest.java
@@ -69,7 +69,7 @@
             .setOutputPath(temp.newFolder().toPath())
             .compile();
 
-    testForJvm()
+    testForJvm(parameters)
         .addRunClasspathFiles(kotlinc.getKotlinStdlibJar(), libJar)
         .addClasspath(output)
         .run(parameters.getRuntime(), PKG + ".extension_property_app.MainKt")
@@ -112,7 +112,7 @@
       return;
     }
 
-    testForJvm()
+    testForJvm(parameters)
         .addRunClasspathFiles(kotlinc.getKotlinStdlibJar(), libJar)
         .addClasspath(output)
         .run(parameters.getRuntime(), PKG + ".extension_property_app.MainKt")
@@ -178,7 +178,7 @@
       return;
     }
 
-    testForJvm()
+    testForJvm(parameters)
         .addRunClasspathFiles(kotlinc.getKotlinStdlibJar(), libJar)
         .addClasspath(output)
         .run(parameters.getRuntime(), PKG + ".extension_property_app.MainKt")
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInFunctionTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInFunctionTest.java
index 21ec2b1..9a1a9de 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInFunctionTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInFunctionTest.java
@@ -68,7 +68,7 @@
             .setOutputPath(temp.newFolder().toPath())
             .compile();
 
-    testForJvm()
+    testForJvm(parameters)
         .addRunClasspathFiles(kotlinc.getKotlinStdlibJar(), libJar)
         .addClasspath(output)
         .run(parameters.getRuntime(), PKG + ".function_app.MainKt")
@@ -110,7 +110,7 @@
       return;
     }
 
-    testForJvm()
+    testForJvm(parameters)
         .addRunClasspathFiles(kotlinc.getKotlinStdlibJar(), libJar)
         .addClasspath(output)
         .run(parameters.getRuntime(), PKG + ".function_app.MainKt")
@@ -174,7 +174,7 @@
       return;
     }
 
-    testForJvm()
+    testForJvm(parameters)
         .addRunClasspathFiles(kotlinc.getKotlinStdlibJar(), libJar)
         .addClasspath(output)
         .run(parameters.getRuntime(), PKG + ".function_app.MainKt")
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInFunctionWithDefaultValueTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInFunctionWithDefaultValueTest.java
index 8fde8b1..ae3a616 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInFunctionWithDefaultValueTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInFunctionWithDefaultValueTest.java
@@ -64,7 +64,7 @@
             .setOutputPath(temp.newFolder().toPath())
             .compile();
 
-    testForJvm()
+    testForJvm(parameters)
         .addRunClasspathFiles(kotlinc.getKotlinStdlibJar(), libJar)
         .addClasspath(output)
         .run(parameters.getRuntime(), PKG + ".default_value_app.MainKt")
@@ -97,7 +97,7 @@
             .setOutputPath(temp.newFolder().toPath())
             .compile();
 
-    testForJvm()
+    testForJvm(parameters)
         .addRunClasspathFiles(kotlinc.getKotlinStdlibJar(), libJar)
         .addClasspath(output)
         .run(parameters.getRuntime(), PKG + ".default_value_app.MainKt")
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInFunctionWithVarargTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInFunctionWithVarargTest.java
index 18666b3..f9ef283 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInFunctionWithVarargTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInFunctionWithVarargTest.java
@@ -69,7 +69,7 @@
             .setOutputPath(temp.newFolder().toPath())
             .compile();
 
-    testForJvm()
+    testForJvm(parameters)
         .addRunClasspathFiles(kotlinc.getKotlinStdlibJar(), libJar)
         .addClasspath(output)
         .run(parameters.getRuntime(), PKG + ".vararg_app.MainKt")
@@ -104,7 +104,7 @@
       return;
     }
 
-    testForJvm()
+    testForJvm(parameters)
         .addRunClasspathFiles(kotlinc.getKotlinStdlibJar(), libJar)
         .addClasspath(output)
         .run(parameters.getRuntime(), PKG + ".vararg_app.MainKt")
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInLibraryTypeTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInLibraryTypeTest.java
index d8d7e4e..27e7927 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInLibraryTypeTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInLibraryTypeTest.java
@@ -66,7 +66,7 @@
 
   @Test
   public void smokeTest() throws Exception {
-    testForJvm()
+    testForJvm(parameters)
         .addRunClasspathFiles(
             kotlinc.getKotlinStdlibJar(), baseLibJarMap.getForConfiguration(kotlinc, targetVersion))
         .addClasspath(
@@ -104,7 +104,7 @@
                     equalTo("Resource 'META-INF/main.kotlin_module' already exists.")))
             .writeToZip();
 
-    testForJvm()
+    testForJvm(parameters)
         .addRunClasspathFiles(
             kotlinc.getKotlinStdlibJar(), baseLibJarMap.getForConfiguration(kotlinc, targetVersion))
         .addClasspath(out)
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInMultifileClassTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInMultifileClassTest.java
index 4168248..2cdb09a 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInMultifileClassTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInMultifileClassTest.java
@@ -74,7 +74,7 @@
             .setOutputPath(temp.newFolder().toPath())
             .compile();
 
-    testForJvm()
+    testForJvm(parameters)
         .addRunClasspathFiles(kotlinc.getKotlinStdlibJar(), libJar)
         .addClasspath(output)
         .run(parameters.getRuntime(), PKG + ".multifileclass_app.MainKt")
@@ -143,7 +143,7 @@
             .setOutputPath(temp.newFolder().toPath())
             .compile();
 
-    testForJvm()
+    testForJvm(parameters)
         .addRunClasspathFiles(kotlinc.getKotlinStdlibJar(), libJar)
         .addClasspath(output)
         .run(parameters.getRuntime(), PKG + ".multifileclass_app.MainKt")
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInNestedClassTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInNestedClassTest.java
index f5be48a..1716b58 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInNestedClassTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInNestedClassTest.java
@@ -63,7 +63,7 @@
             .setOutputPath(temp.newFolder().toPath())
             .compile();
 
-    testForJvm()
+    testForJvm(parameters)
         .addRunClasspathFiles(kotlinc.getKotlinStdlibJar(), libJar)
         .addClasspath(output)
         .run(parameters.getRuntime(), PKG + ".nested_app.MainKt")
@@ -99,7 +99,7 @@
       return;
     }
 
-    testForJvm()
+    testForJvm(parameters)
         .addRunClasspathFiles(kotlinc.getKotlinStdlibJar(), libJar)
         .addClasspath(output)
         .run(parameters.getRuntime(), PKG + ".nested_app.MainKt")
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInParameterTypeTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInParameterTypeTest.java
index 86408fb..3523c74 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInParameterTypeTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInParameterTypeTest.java
@@ -61,7 +61,7 @@
             .setOutputPath(temp.newFolder().toPath())
             .compile();
 
-    testForJvm()
+    testForJvm(parameters)
         .addRunClasspathFiles(kotlinc.getKotlinStdlibJar(), libJar)
         .addClasspath(output)
         .run(parameters.getRuntime(), PKG + ".parametertype_app.MainKt")
@@ -93,7 +93,7 @@
       return;
     }
 
-    testForJvm()
+    testForJvm(parameters)
         .addRunClasspathFiles(kotlinc.getKotlinStdlibJar(), libJar)
         .addClasspath(output)
         .run(parameters.getRuntime(), PKG + ".parametertype_app.MainKt")
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInPropertyTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInPropertyTest.java
index 494d25d..0517447 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInPropertyTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInPropertyTest.java
@@ -70,7 +70,7 @@
             .setOutputPath(temp.newFolder().toPath())
             .compile();
 
-    testForJvm()
+    testForJvm(parameters)
         .addRunClasspathFiles(kotlinc.getKotlinStdlibJar(), libJar)
         .addClasspath(output)
         .run(parameters.getRuntime(), PKG + ".fragile_property_only_getter.Getter_userKt")
@@ -102,7 +102,7 @@
       return;
     }
 
-    testForJvm()
+    testForJvm(parameters)
         .addRunClasspathFiles(kotlinc.getKotlinStdlibJar(), libJar)
         .addClasspath(output)
         .run(parameters.getRuntime(), PKG + ".fragile_property_only_getter.Getter_userKt")
@@ -166,7 +166,7 @@
             .setOutputPath(temp.newFolder().toPath())
             .compile();
 
-    testForJvm()
+    testForJvm(parameters)
         .addRunClasspathFiles(kotlinc.getKotlinStdlibJar(), libJar)
         .addClasspath(output)
         .run(parameters.getRuntime(), PKG + ".fragile_property_only_setter.Setter_userKt")
@@ -202,7 +202,7 @@
       return;
     }
 
-    testForJvm()
+    testForJvm(parameters)
         .addRunClasspathFiles(kotlinc.getKotlinStdlibJar(), libJar)
         .addClasspath(output)
         .run(parameters.getRuntime(), PKG + ".fragile_property_only_setter.Setter_userKt")
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInPropertyTypeTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInPropertyTypeTest.java
index c352c26..daaa710 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInPropertyTypeTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInPropertyTypeTest.java
@@ -61,7 +61,7 @@
             .setOutputPath(temp.newFolder().toPath())
             .compile();
 
-    testForJvm()
+    testForJvm(parameters)
         .addRunClasspathFiles(kotlinc.getKotlinStdlibJar(), libJar)
         .addClasspath(output)
         .run(parameters.getRuntime(), PKG + ".propertytype_app.MainKt")
@@ -91,7 +91,7 @@
       return;
     }
 
-    testForJvm()
+    testForJvm(parameters)
         .addRunClasspathFiles(kotlinc.getKotlinStdlibJar(), libJar)
         .addClasspath(output)
         .run(parameters.getRuntime(), PKG + ".propertytype_app.MainKt")
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInReturnTypeTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInReturnTypeTest.java
index 020c71d..1d76412 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInReturnTypeTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInReturnTypeTest.java
@@ -61,7 +61,7 @@
             .setOutputPath(temp.newFolder().toPath())
             .compile();
 
-    testForJvm()
+    testForJvm(parameters)
         .addRunClasspathFiles(kotlinc.getKotlinStdlibJar(), libJar)
         .addClasspath(output)
         .run(parameters.getRuntime(), PKG + ".returntype_app.MainKt")
@@ -93,7 +93,7 @@
       return;
     }
 
-    testForJvm()
+    testForJvm(parameters)
         .addRunClasspathFiles(kotlinc.getKotlinStdlibJar(), libJar)
         .addClasspath(output)
         .run(parameters.getRuntime(), PKG + ".returntype_app.MainKt")
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInSealedClassNestedTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInSealedClassNestedTest.java
index eacdadb..3b726d3 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInSealedClassNestedTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInSealedClassNestedTest.java
@@ -54,7 +54,7 @@
                 getKotlinFileInTest(DescriptorUtils.getBinaryNameFromJavaType(PKG_APP), "main"))
             .setOutputPath(temp.newFolder().toPath())
             .compile();
-    testForJvm()
+    testForJvm(parameters)
         .addRunClasspathFiles(kotlinc.getKotlinStdlibJar(), kotlinc.getKotlinReflectJar(), libJar)
         .addClasspath(output)
         .run(parameters.getRuntime(), PKG_APP + ".MainKt")
@@ -80,7 +80,7 @@
                 getKotlinFileInTest(DescriptorUtils.getBinaryNameFromJavaType(PKG_APP), "main"))
             .setOutputPath(temp.newFolder().toPath())
             .compile();
-    testForJvm()
+    testForJvm(parameters)
         .addRunClasspathFiles(kotlinc.getKotlinStdlibJar(), kotlinc.getKotlinReflectJar(), libJar)
         .addClasspath(output)
         .run(parameters.getRuntime(), PKG_APP + ".MainKt")
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInSealedClassTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInSealedClassTest.java
index b7b222f..e4243c4 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInSealedClassTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInSealedClassTest.java
@@ -64,7 +64,7 @@
             .setOutputPath(temp.newFolder().toPath())
             .compile();
 
-    testForJvm()
+    testForJvm(parameters)
         .addRunClasspathFiles(kotlinc.getKotlinStdlibJar(), libJar)
         .addClasspath(output)
         .run(parameters.getRuntime(), PKG + ".sealed_app.ValidKt")
@@ -95,7 +95,7 @@
             .setOutputPath(temp.newFolder().toPath())
             .compile();
 
-    testForJvm()
+    testForJvm(parameters)
         .addRunClasspathFiles(kotlinc.getKotlinStdlibJar(), libJar)
         .addClasspath(output)
         .run(parameters.getRuntime(), PKG + ".sealed_app.ValidKt")
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInSuperTypeTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInSuperTypeTest.java
index 14fa2e1..5346ffe 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInSuperTypeTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInSuperTypeTest.java
@@ -64,7 +64,7 @@
             .setOutputPath(temp.newFolder().toPath())
             .compile();
 
-    testForJvm()
+    testForJvm(parameters)
         .addRunClasspathFiles(kotlinc.getKotlinStdlibJar(), libJar)
         .addClasspath(output)
         .run(parameters.getRuntime(), PKG + ".supertype_app.MainKt")
@@ -94,7 +94,7 @@
       return;
     }
 
-    testForJvm()
+    testForJvm(parameters)
         .addRunClasspathFiles(kotlinc.getKotlinStdlibJar(), libJar)
         .addClasspath(output)
         .run(parameters.getRuntime(), PKG + ".supertype_app.MainKt")
@@ -144,7 +144,7 @@
       return;
     }
 
-    testForJvm()
+    testForJvm(parameters)
         .addRunClasspathFiles(kotlinc.getKotlinStdlibJar(), libJar)
         .addClasspath(output)
         .run(parameters.getRuntime(), PKG + ".supertype_app.MainKt")
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInTypeAliasTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInTypeAliasTest.java
index 2571322..b5e22d8 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInTypeAliasTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInTypeAliasTest.java
@@ -92,7 +92,7 @@
             .setOutputPath(temp.newFolder().toPath())
             .compile();
 
-    testForJvm()
+    testForJvm(parameters)
         .addRunClasspathFiles(kotlinc.getKotlinStdlibJar(), kotlinc.getKotlinReflectJar(), libJar)
         .addClasspath(output)
         .run(parameters.getRuntime(), PKG + ".typealias_app.MainKt")
@@ -141,7 +141,7 @@
       return;
     }
 
-    testForJvm()
+    testForJvm(parameters)
         .addRunClasspathFiles(kotlinc.getKotlinStdlibJar(), kotlinc.getKotlinReflectJar(), libJar)
         .addClasspath(appJar)
         .run(parameters.getRuntime(), PKG + ".typealias_app.MainKt")
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInTypeArgumentsTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInTypeArgumentsTest.java
index 36d4580..a82971c 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInTypeArgumentsTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInTypeArgumentsTest.java
@@ -106,7 +106,7 @@
             .setOutputPath(temp.newFolder().toPath())
             .compile();
 
-    testForJvm()
+    testForJvm(parameters)
         .addRunClasspathFiles(kotlinc.getKotlinStdlibJar(), libJar)
         .addClasspath(output)
         .run(parameters.getRuntime(), PKG + ".typeargument_app.MainKt")
@@ -145,7 +145,7 @@
     if (kotlinParameters.isOlderThan(KOTLINC_1_4_20)) {
       return;
     }
-    testForJvm()
+    testForJvm(parameters)
         .addRunClasspathFiles(kotlinc.getKotlinStdlibJar(), libJar)
         .addClasspath(mainJar)
         .run(parameters.getRuntime(), PKG + ".typeargument_app.MainKt")
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInlineClassIncludeDescriptorClassesTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInlineClassIncludeDescriptorClassesTest.java
index ac394af..cf513eb 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInlineClassIncludeDescriptorClassesTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInlineClassIncludeDescriptorClassesTest.java
@@ -64,7 +64,7 @@
                     PKG_PREFIX + "/inline_class_fun_descriptor_classes_app", "main"))
             .setOutputPath(temp.newFolder().toPath())
             .compile();
-    testForJvm()
+    testForJvm(parameters)
         .addRunClasspathFiles(kotlinc.getKotlinStdlibJar(), libJar)
         .addClasspath(output)
         .run(parameters.getRuntime(), PKG + ".inline_class_fun_descriptor_classes_app.MainKt")
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInlineClassTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInlineClassTest.java
index 0704ecd..b34f9bb 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInlineClassTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInlineClassTest.java
@@ -55,7 +55,7 @@
             .addSourceFiles(getKotlinFileInTest(PKG_PREFIX + "/inline_class_app", "main"))
             .setOutputPath(temp.newFolder().toPath())
             .compile();
-    testForJvm()
+    testForJvm(parameters)
         .addRunClasspathFiles(kotlinc.getKotlinStdlibJar(), libJar)
         .addClasspath(output)
         .run(parameters.getRuntime(), PKG + ".inline_class_app.MainKt")
@@ -87,7 +87,7 @@
             .addSourceFiles(getKotlinFileInTest(PKG_PREFIX + "/inline_class_app", "main"))
             .setOutputPath(temp.newFolder().toPath())
             .compile();
-    testForJvm()
+    testForJvm(parameters)
         .addRunClasspathFiles(kotlinc.getKotlinStdlibJar(), kotlinc.getKotlinReflectJar(), libJar)
         .addClasspath(main)
         .run(parameters.getRuntime(), PKG + ".inline_class_app.MainKt")
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInlinePropertyTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInlinePropertyTest.java
index 6f78827..7bc7f6d 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInlinePropertyTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInlinePropertyTest.java
@@ -46,7 +46,7 @@
             .addSourceFiles(getKotlinFileInTest(PKG_PREFIX + "/inline_property_app", "main"))
             .setOutputPath(temp.newFolder().toPath())
             .compile();
-    testForJvm()
+    testForJvm(parameters)
         .addRunClasspathFiles(kotlinc.getKotlinStdlibJar(), libJar)
         .addClasspath(output)
         .run(parameters.getRuntime(), PKG + ".inline_property_app.MainKt")
@@ -79,7 +79,7 @@
             .addSourceFiles(getKotlinFileInTest(PKG_PREFIX + "/inline_property_app", "main"))
             .setOutputPath(temp.newFolder().toPath())
             .compile();
-    testForJvm()
+    testForJvm(parameters)
         .addRunClasspathFiles(kotlinc.getKotlinStdlibJar(), kotlinc.getKotlinReflectJar(), libJar)
         .addClasspath(main)
         .run(parameters.getRuntime(), PKG + ".inline_property_app.MainKt")
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteJvmStaticTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteJvmStaticTest.java
index a1b423d..ea27573 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteJvmStaticTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteJvmStaticTest.java
@@ -66,7 +66,7 @@
                 getKotlinFileInTest(DescriptorUtils.getBinaryNameFromJavaType(PKG_APP), "main"))
             .setOutputPath(temp.newFolder().toPath())
             .compile();
-    testForJvm()
+    testForJvm(parameters)
         .addRunClasspathFiles(
             kotlinc.getKotlinStdlibJar(), kotlincLibJar.getForConfiguration(kotlinc, targetVersion))
         .addClasspath(output)
@@ -76,7 +76,7 @@
 
   @Test
   public void smokeTestJava() throws Exception {
-    testForJvm()
+    testForJvm(parameters)
         .addRunClasspathFiles(
             kotlinc.getKotlinStdlibJar(), kotlincLibJar.getForConfiguration(kotlinc, targetVersion))
         .addProgramClassFileData(MainJava.dump())
@@ -110,7 +110,7 @@
                 getKotlinFileInTest(DescriptorUtils.getBinaryNameFromJavaType(PKG_APP), "main"))
             .setOutputPath(temp.newFolder().toPath())
             .compile();
-    testForJvm()
+    testForJvm(parameters)
         .addRunClasspathFiles(kotlinc.getKotlinStdlibJar(), libJar)
         .addClasspath(output)
         .run(parameters.getRuntime(), PKG_APP + ".MainKt")
@@ -118,7 +118,7 @@
   }
 
   private void testJava(Path libJar) throws Exception {
-    testForJvm()
+    testForJvm(parameters)
         .addRunClasspathFiles(kotlinc.getKotlinStdlibJar(), libJar)
         .addProgramClassFileData(MainJava.dump())
         .run(parameters.getRuntime(), MainJava.class)
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteLocalDelegatedPropertyTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteLocalDelegatedPropertyTest.java
index 9fddbf0..783a971 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteLocalDelegatedPropertyTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteLocalDelegatedPropertyTest.java
@@ -49,7 +49,7 @@
 
   @Test
   public void smokeTest() throws Exception {
-    testForJvm()
+    testForJvm(parameters)
         .addRunClasspathFiles(kotlinc.getKotlinStdlibJar(), kotlinc.getKotlinReflectJar())
         .addClasspath(jars.getForConfiguration(kotlinc, targetVersion))
         .run(parameters.getRuntime(), PKG_APP + ".MainKt")
@@ -75,7 +75,7 @@
                         inspector,
                         (addedStrings, addedNonInitStrings) -> {}))
             .writeToZip();
-    testForJvm()
+    testForJvm(parameters)
         .addRunClasspathFiles(kotlinc.getKotlinStdlibJar(), kotlinc.getKotlinReflectJar())
         .addClasspath(outputJar)
         .run(parameters.getRuntime(), PKG_APP + ".MainKt")
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewritePrunedObjectsTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewritePrunedObjectsTest.java
index 26d9934..eab5c08 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewritePrunedObjectsTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewritePrunedObjectsTest.java
@@ -62,7 +62,7 @@
                 getKotlinFileInTest(DescriptorUtils.getBinaryNameFromJavaType(PKG_APP), "main"))
             .setOutputPath(temp.newFolder().toPath())
             .compile();
-    testForJvm()
+    testForJvm(parameters)
         .addRunClasspathFiles(kotlinc.getKotlinStdlibJar(), libJar)
         .addClasspath(output)
         .run(parameters.getRuntime(), PKG_APP + ".MainKt")
@@ -94,7 +94,7 @@
     if (kotlinParameters.isOlderThan(KOTLINC_1_4_20)) {
       return;
     }
-    testForJvm()
+    testForJvm(parameters)
         .addRunClasspathFiles(kotlinc.getKotlinStdlibJar(), libJar)
         .addProgramFiles(output)
         .run(parameters.getRuntime(), PKG_APP + ".MainKt")
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteRawTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteRawTest.java
index 6012fb0..9ad7bcf 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteRawTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteRawTest.java
@@ -73,7 +73,7 @@
             .addSourceFiles(getKotlinFileInTest(getBinaryNameFromJavaType(PKG_APP), "main"))
             .setOutputPath(temp.newFolder().toPath())
             .compile();
-    testForJvm()
+    testForJvm(parameters)
         .addRunClasspathFiles(kotlinc.getKotlinStdlibJar(), libJar, javaLibZip)
         .addClasspath(output)
         .run(parameters.getRuntime(), PKG_APP + ".MainKt")
@@ -107,7 +107,7 @@
             .addSourceFiles(getKotlinFileInTest(getBinaryNameFromJavaType(PKG_APP), "main"))
             .setOutputPath(temp.newFolder().toPath())
             .compile();
-    testForJvm()
+    testForJvm(parameters)
         .addRunClasspathFiles(
             kotlinc.getKotlinStdlibJar(), kotlinc.getKotlinReflectJar(), libJar, javaLibZip)
         .addClasspath(main)
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteRemovedCompanionTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteRemovedCompanionTest.java
index 145cb4b..435b129 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteRemovedCompanionTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteRemovedCompanionTest.java
@@ -52,7 +52,7 @@
             .setOutputPath(temp.newFolder().toPath())
             .compile();
 
-    testForJvm()
+    testForJvm(parameters)
         .addRunClasspathFiles(kotlinc.getKotlinStdlibJar(), libJar)
         .addClasspath(output)
         .run(parameters.getRuntime(), PKG + ".companion_remove_app.MainKt")
@@ -80,7 +80,7 @@
             .setOutputPath(temp.newFolder().toPath())
             .compile();
 
-    testForJvm()
+    testForJvm(parameters)
         .addRunClasspathFiles(kotlinc.getKotlinStdlibJar(), libJar)
         .addClasspath(output)
         .run(parameters.getRuntime(), PKG + ".companion_remove_app.MainKt")
@@ -107,7 +107,7 @@
             .setOutputPath(temp.newFolder().toPath())
             .compile();
 
-    testForJvm()
+    testForJvm(parameters)
         .addRunClasspathFiles(kotlinc.getKotlinStdlibJar(), libJar)
         .addClasspath(output)
         .run(parameters.getRuntime(), PKG + ".companion_remove_app.MainKt")
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteUnitPrimitiveTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteUnitPrimitiveTest.java
index 4683d0b..1c97e71 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteUnitPrimitiveTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteUnitPrimitiveTest.java
@@ -70,7 +70,7 @@
                 getKotlinFileInTest(DescriptorUtils.getBinaryNameFromJavaType(PKG_APP), "main"))
             .setOutputPath(temp.newFolder().toPath())
             .compile();
-    testForJvm()
+    testForJvm(parameters)
         .addRunClasspathFiles(
             kotlinc.getKotlinStdlibJar(),
             kotlinc.getKotlinReflectJar(),
@@ -112,7 +112,7 @@
                 getKotlinFileInTest(DescriptorUtils.getBinaryNameFromJavaType(PKG_APP), "main"))
             .setOutputPath(temp.newFolder().toPath())
             .compile();
-    testForJvm()
+    testForJvm(parameters)
         .addRunClasspathFiles(kotlinc.getKotlinStdlibJar(), kotlinc.getKotlinReflectJar(), libJar)
         .addClasspath(main)
         .run(parameters.getRuntime(), PKG_APP + ".MainKt")
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteValueClassTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteValueClassTest.java
index b65643f..5a41bec 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteValueClassTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteValueClassTest.java
@@ -65,7 +65,7 @@
                 getKotlinFileInTest(DescriptorUtils.getBinaryNameFromJavaType(PKG_APP), "main"))
             .setOutputPath(temp.newFolder().toPath())
             .compile();
-    testForJvm()
+    testForJvm(parameters)
         .addRunClasspathFiles(
             kotlinc.getKotlinStdlibJar(), kotlincLibJar.getForConfiguration(kotlinc, targetVersion))
         .addClasspath(output)
@@ -99,7 +99,7 @@
                 getKotlinFileInTest(DescriptorUtils.getBinaryNameFromJavaType(PKG_APP), "main"))
             .setOutputPath(temp.newFolder().toPath())
             .compile();
-    testForJvm()
+    testForJvm(parameters)
         .addRunClasspathFiles(kotlinc.getKotlinStdlibJar(), kotlinc.getKotlinReflectJar(), libJar)
         .addClasspath(main)
         .run(parameters.getRuntime(), PKG_APP + ".MainKt")
diff --git a/src/test/java/com/android/tools/r8/kotlin/reflection/KotlinReflectTest.java b/src/test/java/com/android/tools/r8/kotlin/reflection/KotlinReflectTest.java
index f5ab85d..61c7a61 100644
--- a/src/test/java/com/android/tools/r8/kotlin/reflection/KotlinReflectTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/reflection/KotlinReflectTest.java
@@ -6,7 +6,6 @@
 
 import static com.android.tools.r8.KotlinCompilerTool.KotlinCompilerVersion.KOTLINC_1_3_72;
 import static com.android.tools.r8.KotlinCompilerTool.KotlinCompilerVersion.KOTLINC_1_8_0;
-import static org.junit.Assume.assumeTrue;
 
 import com.android.tools.r8.DexIndexedConsumer.ArchiveConsumer;
 import com.android.tools.r8.KotlinTestBase;
@@ -57,8 +56,8 @@
 
   @Test
   public void testCf() throws Exception {
-    assumeTrue(parameters.isCfRuntime());
-    testForJvm()
+    parameters.assumeJvmTestParameters();
+    testForJvm(parameters)
         .addProgramFiles(compiledJars.getForConfiguration(kotlinc, targetVersion))
         .addProgramFiles(kotlinc.getKotlinStdlibJar())
         .addProgramFiles(kotlinc.getKotlinReflectJar())
@@ -69,7 +68,7 @@
 
   @Test
   public void testD8() throws Exception {
-    assumeTrue(parameters.isDexRuntime());
+    parameters.assumeDexRuntime();
     final File output = temp.newFile("output.zip");
     testForD8(parameters.getBackend())
         .addProgramFiles(compiledJars.getForConfiguration(kotlinc, targetVersion))
diff --git a/src/test/java/com/android/tools/r8/kotlin/reflection/ReflectiveConstructionWithInlineClassTest.java b/src/test/java/com/android/tools/r8/kotlin/reflection/ReflectiveConstructionWithInlineClassTest.java
index 16be215..9a4c93a 100644
--- a/src/test/java/com/android/tools/r8/kotlin/reflection/ReflectiveConstructionWithInlineClassTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/reflection/ReflectiveConstructionWithInlineClassTest.java
@@ -4,7 +4,6 @@
 
 package com.android.tools.r8.kotlin.reflection;
 
-import static org.junit.Assume.assumeTrue;
 
 import com.android.tools.r8.KotlinCompilerTool.KotlinCompilerVersion;
 import com.android.tools.r8.KotlinTestBase;
@@ -63,8 +62,8 @@
 
   @Test
   public void testCf() throws Exception {
-    assumeTrue(parameters.isCfRuntime());
-    testForJvm()
+    parameters.assumeJvmTestParameters();
+    testForJvm(parameters)
         .addProgramFiles(compiledJars.getForConfiguration(kotlinc, targetVersion))
         .addProgramFiles(kotlinc.getKotlinStdlibJar())
         .addProgramFiles(kotlinc.getKotlinReflectJar())
@@ -75,8 +74,8 @@
 
   @Test
   public void testD8() throws Exception {
-    assumeTrue(parameters.isDexRuntime());
-    testForD8(parameters.getBackend())
+    parameters.assumeDexRuntime();
+    testForD8()
         .addProgramFiles(compiledJars.getForConfiguration(kotlinc, targetVersion))
         .addProgramFiles(kotlinc.getKotlinStdlibJar())
         .addProgramFiles(kotlinc.getKotlinReflectJar())
diff --git a/src/test/java/com/android/tools/r8/lightir/LirRoundtripTest.java b/src/test/java/com/android/tools/r8/lightir/LirRoundtripTest.java
index a796311..6f25db7 100644
--- a/src/test/java/com/android/tools/r8/lightir/LirRoundtripTest.java
+++ b/src/test/java/com/android/tools/r8/lightir/LirRoundtripTest.java
@@ -3,7 +3,6 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.lightir;
 
-import static org.junit.Assume.assumeTrue;
 
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.TestParametersCollection;
@@ -42,8 +41,8 @@
 
   @Test
   public void testReference() throws Exception {
-    assumeTrue(parameters.isCfRuntime());
-    testForJvm()
+    parameters.assumeJvmTestParameters();
+    testForJvm(parameters)
         .addProgramClasses(TestClass.class)
         .run(parameters.getRuntime(), TestClass.class)
         .assertSuccessWithOutputLines("Hello, world!");
diff --git a/src/test/java/com/android/tools/r8/maindexlist/MainDexWithSynthesizedClassesTest.java b/src/test/java/com/android/tools/r8/maindexlist/MainDexWithSynthesizedClassesTest.java
index 74404fe..1f980f3 100644
--- a/src/test/java/com/android/tools/r8/maindexlist/MainDexWithSynthesizedClassesTest.java
+++ b/src/test/java/com/android/tools/r8/maindexlist/MainDexWithSynthesizedClassesTest.java
@@ -57,7 +57,7 @@
   @Test
   public void testFinal() throws Exception {
     if (parameters.isCfRuntime()) {
-      testForJvm()
+      testForJvm(parameters)
           .addTestClasspath()
           .run(parameters.getRuntime(), TestClass.class)
           .assertSuccessWithOutput(EXPECTED);
diff --git a/src/test/java/com/android/tools/r8/memberrebinding/IllegalFieldRebindingTest.java b/src/test/java/com/android/tools/r8/memberrebinding/IllegalFieldRebindingTest.java
index 4095713..1dbbec9 100644
--- a/src/test/java/com/android/tools/r8/memberrebinding/IllegalFieldRebindingTest.java
+++ b/src/test/java/com/android/tools/r8/memberrebinding/IllegalFieldRebindingTest.java
@@ -9,7 +9,8 @@
 import static org.junit.Assert.assertEquals;
 
 import com.android.tools.r8.TestBase;
-import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
 import com.android.tools.r8.memberrebinding.testclasses.IllegalFieldRebindingTestClasses;
 import com.android.tools.r8.memberrebinding.testclasses.IllegalFieldRebindingTestClasses.B;
 import com.android.tools.r8.utils.StringUtils;
@@ -20,38 +21,43 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
 import org.junit.runners.Parameterized.Parameters;
 
 @RunWith(Parameterized.class)
 public class IllegalFieldRebindingTest extends TestBase {
 
-  private final Backend backend;
+  private static final String EXPECTED_OUTPUT = StringUtils.lines("42");
+  private static final String OTHER_EXPECTED_OUTPUT = StringUtils.lines("0");
 
-  @Parameters(name = "Backend: {0}")
-  public static Backend[] data() {
-    return ToolHelper.getBackends();
+  @Parameter(0)
+  public TestParameters parameters;
+
+  @Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withAllRuntimesAndApiLevels().build();
   }
 
-  public IllegalFieldRebindingTest(Backend backend) {
-    this.backend = backend;
+  @Test
+  public void testJvm() throws Exception {
+    parameters.assumeJvmTestParameters();
+    testForJvm(parameters)
+        .addTestClasspath()
+        .run(parameters.getRuntime(), TestClass.class)
+        .assertSuccessWithOutput(EXPECTED_OUTPUT);
   }
 
   @Test
   public void test() throws Exception {
-    String expectedOutput = StringUtils.lines("42");
-
-    if (backend == Backend.CF) {
-      testForJvm().addTestClasspath().run(TestClass.class).assertSuccessWithOutput(expectedOutput);
-    }
-
     CodeInspector inspector =
-        testForR8(Backend.DEX)
+        testForR8(parameters.getBackend())
             .addInnerClasses(IllegalFieldRebindingTest.class)
             .addInnerClasses(IllegalFieldRebindingTestClasses.class)
             .addKeepMainRule(TestClass.class)
             .enableNoVerticalClassMergingAnnotations()
-            .run(TestClass.class)
-            .assertSuccessWithOutput(expectedOutput)
+            .setMinApi(parameters)
+            .run(parameters.getRuntime(), TestClass.class)
+            .assertSuccessWithOutput(EXPECTED_OUTPUT)
             .inspector();
 
     ClassSubject classSubject = inspector.clazz(TestClass.class);
@@ -66,24 +72,25 @@
   }
 
   @Test
+  public void testJvmOther() throws Exception {
+    parameters.assumeJvmTestParameters();
+    testForJvm(parameters)
+        .addTestClasspath()
+        .run(parameters.getRuntime(), OtherTestClass.class)
+        .assertSuccessWithOutput(OTHER_EXPECTED_OUTPUT);
+  }
+
+  @Test
   public void otherTest() throws Exception {
-    String expectedOutput = StringUtils.lines("0");
-
-    if (backend == Backend.CF) {
-      testForJvm()
-          .addTestClasspath()
-          .run(OtherTestClass.class)
-          .assertSuccessWithOutput(expectedOutput);
-    }
-
     CodeInspector inspector =
-        testForR8(Backend.DEX)
+        testForR8(parameters.getBackend())
             .addInnerClasses(IllegalFieldRebindingTest.class)
             .addInnerClasses(IllegalFieldRebindingTestClasses.class)
             .addKeepMainRule(OtherTestClass.class)
             .enableNoVerticalClassMergingAnnotations()
-            .run(OtherTestClass.class)
-            .assertSuccessWithOutput(expectedOutput)
+            .setMinApi(parameters)
+            .run(parameters.getRuntime(), OtherTestClass.class)
+            .assertSuccessWithOutput(OTHER_EXPECTED_OUTPUT)
             .inspector();
 
     // The static-get instruction in OtherTestClass.main() should have been replaced by the
diff --git a/src/test/java/com/android/tools/r8/memberrebinding/IndirectSuperInterfaceTest.java b/src/test/java/com/android/tools/r8/memberrebinding/IndirectSuperInterfaceTest.java
index 9993999..0d4f532 100644
--- a/src/test/java/com/android/tools/r8/memberrebinding/IndirectSuperInterfaceTest.java
+++ b/src/test/java/com/android/tools/r8/memberrebinding/IndirectSuperInterfaceTest.java
@@ -5,13 +5,15 @@
 
 import com.android.tools.r8.NeverInline;
 import com.android.tools.r8.TestBase;
-import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
 import com.android.tools.r8.utils.StringUtils;
 import com.google.common.collect.ImmutableList;
 import java.util.List;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
 import org.junit.runners.Parameterized.Parameters;
 
 @RunWith(Parameterized.class)
@@ -129,36 +131,39 @@
     }
   }
 
-  private final Backend backend;
+  private static final String EXPECTED =
+      StringUtils.joinLines(
+          "A::method -> InterfaceA::method",
+          "B::method -> InterfaceB::method",
+          "C::method -> InterfaceC::method",
+          "D::method -> InterfaceD::method");
+
+  @Parameter(0)
+  public TestParameters parameters;
 
   @Parameters(name = "{0}")
-  public static Backend[] setup() {
-    return ToolHelper.getBackends();
-  }
-
-  public IndirectSuperInterfaceTest(Backend backend) {
-    this.backend = backend;
+  public static TestParametersCollection data() {
+    return getTestParameters().withAllRuntimesAndApiLevels().build();
   }
 
   @Test
-  public void test() throws Exception {
-    String expected = StringUtils.joinLines(
-        "A::method -> InterfaceA::method",
-        "B::method -> InterfaceB::method",
-        "C::method -> InterfaceC::method",
-        "D::method -> InterfaceD::method");
-
-    testForJvm()
+  public void testJvm() throws Exception {
+    parameters.assumeJvmTestParameters();
+    testForJvm(parameters)
         .addTestClasspath()
-        .run(TestClass.class)
-        .assertSuccessWithOutput(expected);
+        .run(parameters.getRuntime(), TestClass.class)
+        .assertSuccessWithOutput(EXPECTED);
+  }
 
-    testForR8(backend)
+  @Test
+  public void testR8() throws Exception {
+    testForR8(parameters.getBackend())
         .addProgramClasses(CLASSES)
         .addKeepPackageRules(TestClass.class.getPackage())
         .addKeepMainRule(TestClass.class)
         .enableInliningAnnotations()
-        .run(TestClass.class)
-        .assertSuccessWithOutput(expected);
+        .setMinApi(parameters)
+        .run(parameters.getRuntime(), TestClass.class)
+        .assertSuccessWithOutput(EXPECTED);
   }
 }
diff --git a/src/test/java/com/android/tools/r8/memberrebinding/MemberRebindingAmbiguousDispatchToLibraryTest.java b/src/test/java/com/android/tools/r8/memberrebinding/MemberRebindingAmbiguousDispatchToLibraryTest.java
index 19956c7..65d63b4 100644
--- a/src/test/java/com/android/tools/r8/memberrebinding/MemberRebindingAmbiguousDispatchToLibraryTest.java
+++ b/src/test/java/com/android/tools/r8/memberrebinding/MemberRebindingAmbiguousDispatchToLibraryTest.java
@@ -4,7 +4,6 @@
 
 package com.android.tools.r8.memberrebinding;
 
-import static org.junit.Assume.assumeTrue;
 
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestBuilder;
@@ -49,8 +48,8 @@
 
   @Test
   public void testReference() throws Exception {
-    assumeTrue(parameters.isCfRuntime());
-    testForJvm()
+    parameters.assumeJvmTestParameters();
+    testForJvm(parameters)
         .apply(this::setupInput)
         .run(parameters.getRuntime(), Main.class)
         .apply(this::checkOutput);
diff --git a/src/test/java/com/android/tools/r8/memberrebinding/MemberRebindingFrontierTest.java b/src/test/java/com/android/tools/r8/memberrebinding/MemberRebindingFrontierTest.java
index d52a38e..6277dbd 100644
--- a/src/test/java/com/android/tools/r8/memberrebinding/MemberRebindingFrontierTest.java
+++ b/src/test/java/com/android/tools/r8/memberrebinding/MemberRebindingFrontierTest.java
@@ -6,7 +6,6 @@
 
 import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
 import static org.hamcrest.MatcherAssert.assertThat;
-import static org.junit.Assume.assumeTrue;
 
 import com.android.tools.r8.SingleTestRunResult;
 import com.android.tools.r8.TestBase;
@@ -34,8 +33,8 @@
 
   @Test
   public void testD8() throws Exception {
-    assumeTrue(parameters.isDexRuntime());
-    testForD8(parameters.getBackend())
+    parameters.assumeDexRuntime();
+    testForD8()
         .addProgramClasses(Main.class, ProgramClass.class)
         .addDefaultRuntimeLibrary(parameters)
         .addLibraryClasses(Base.class, I.class)
diff --git a/src/test/java/com/android/tools/r8/memberrebinding/MemberRebindingLibraryBridgeVerticallyMergeTest.java b/src/test/java/com/android/tools/r8/memberrebinding/MemberRebindingLibraryBridgeVerticallyMergeTest.java
index c34cfb2..60f0a75 100644
--- a/src/test/java/com/android/tools/r8/memberrebinding/MemberRebindingLibraryBridgeVerticallyMergeTest.java
+++ b/src/test/java/com/android/tools/r8/memberrebinding/MemberRebindingLibraryBridgeVerticallyMergeTest.java
@@ -4,7 +4,6 @@
 
 package com.android.tools.r8.memberrebinding;
 
-import static org.junit.Assume.assumeTrue;
 
 import com.android.tools.r8.NeverInline;
 import com.android.tools.r8.TestBase;
@@ -30,8 +29,8 @@
 
   @Test
   public void testJvm() throws Exception {
-    assumeTrue(parameters.isCfRuntime());
-    testForJvm()
+    parameters.assumeJvmTestParameters();
+    testForJvm(parameters)
         .addProgramClasses(A.class, B.class, C.class, D.class, Main.class)
         .addLibraryClasses(Lib.class)
         .run(parameters.getRuntime(), Main.class)
@@ -40,8 +39,8 @@
 
   @Test
   public void testD8() throws Exception {
-    assumeTrue(parameters.isDexRuntime());
-    testForD8(parameters.getBackend())
+    parameters.assumeDexRuntime();
+    testForD8()
         .addProgramClasses(A.class, B.class, C.class, D.class, Main.class)
         .addLibraryClasses(Lib.class)
         .addDefaultRuntimeLibrary(parameters)
diff --git a/src/test/java/com/android/tools/r8/movestringconstants/MoveStringConstantsTest.java b/src/test/java/com/android/tools/r8/movestringconstants/MoveStringConstantsTest.java
index 35e8c37..857a222 100644
--- a/src/test/java/com/android/tools/r8/movestringconstants/MoveStringConstantsTest.java
+++ b/src/test/java/com/android/tools/r8/movestringconstants/MoveStringConstantsTest.java
@@ -8,16 +8,12 @@
 import static junit.framework.TestCase.assertEquals;
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.junit.Assert.assertTrue;
-import static org.junit.Assume.assumeTrue;
 
 import com.android.tools.r8.AlwaysInline;
-import com.android.tools.r8.CompilationMode;
 import com.android.tools.r8.NeverInline;
-import com.android.tools.r8.R8Command;
 import com.android.tools.r8.TestBase;
-import com.android.tools.r8.ToolHelper;
-import com.android.tools.r8.origin.Origin;
-import com.android.tools.r8.utils.AndroidApp;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
 import com.android.tools.r8.utils.codeinspector.ClassSubject;
 import com.android.tools.r8.utils.codeinspector.CodeInspector;
 import com.android.tools.r8.utils.codeinspector.InstructionSubject;
@@ -25,58 +21,41 @@
 import com.android.tools.r8.utils.codeinspector.MethodSubject;
 import com.google.common.collect.ImmutableList;
 import java.util.Iterator;
-import java.util.function.Consumer;
 import java.util.function.Predicate;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
 import org.junit.runners.Parameterized.Parameters;
 
 @RunWith(Parameterized.class)
 public class MoveStringConstantsTest extends TestBase {
 
-  private Backend backend;
+  @Parameter(0)
+  public TestParameters parameters;
 
-  @Parameters(name = "Backend: {0}")
-  public static Backend[] data() {
-    return ToolHelper.getBackends();
+  @Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withAllRuntimesAndApiLevels().build();
   }
 
-  private void runTest(Consumer<CodeInspector> inspection) throws Exception {
-    R8Command.Builder builder = R8Command.builder();
-    builder.addProgramFiles(ToolHelper.getClassFileForTestClass(NeverInline.class));
-    builder.addProgramFiles(ToolHelper.getClassFileForTestClass(TestClass.class));
-    builder.addProgramFiles(ToolHelper.getClassFileForTestClass(Utils.class));
-    builder.addProgramFiles(ToolHelper.getClassFileForTestClass(AlwaysInline.class));
-    builder.addLibraryFiles(runtimeJar(backend));
-    builder.setProgramConsumer(emptyConsumer(backend));
-    builder.setMode(CompilationMode.RELEASE);
-    builder.addProguardConfiguration(
-        ImmutableList.of(
-            "-alwaysinline class * { @com.android.tools.r8.AlwaysInline *; }",
-            "-neverinline class * { @com.android.tools.r8.NeverInline *; }",
-            "-keep class " + TestClass.class.getCanonicalName() + "{ *; }",
-            "-dontobfuscate",
-            "-allowaccessmodification"),
-        Origin.unknown());
-    ToolHelper.allowTestProguardOptions(builder);
-    AndroidApp app = ToolHelper.runR8(builder.build());
-    inspection.accept(new CodeInspector(app));
-
-    if (backend == Backend.DEX) {
-      // Run on Art to check generated code against verifier.
-      runOnArt(app, TestClass.class);
-    } else {
-      assert backend == Backend.CF;
-      runOnJava(app, TestClass.class);
-    }
+  @Test
+  public void test() throws Exception {
+    testForR8(parameters.getBackend())
+        .addInnerClasses(getClass())
+        .addKeepClassAndMembersRules(TestClass.class)
+        .addDontObfuscate()
+        .allowAccessModification()
+        .enableAlwaysInliningAnnotations()
+        .enableInliningAnnotations()
+        .setMinApi(parameters)
+        .compile()
+        .inspect(this::inspect)
+        .run(parameters.getRuntime(), TestClass.class)
+        .assertSuccessWithEmptyOutput();
   }
 
-  public MoveStringConstantsTest(Backend backend) {
-    this.backend = backend;
-  }
-
-  private void validate(CodeInspector inspector) {
+  private void inspect(CodeInspector inspector) {
     ClassSubject clazz = inspector.clazz(TestClass.class);
     assertTrue(clazz.isPresent());
 
@@ -85,53 +64,55 @@
         clazz.method("void", "foo", ImmutableList.of(
             "java.lang.String", "java.lang.String", "java.lang.String", "java.lang.String"));
     assertTrue(methodThrowToBeInlined.isPresent());
-    assert (backend == Backend.DEX || backend == Backend.CF);
 
     // CF should not canonicalize strings or lower them. This test ensures that strings are moved
     // down and make assertions based on throwing branches, which we do not care about in CF.
     // See (r8g/30163) and (r8g/30320).
-    assumeTrue(backend == Backend.DEX);
-    validateSequence(
-        methodThrowToBeInlined.iterateInstructions(),
+    if (parameters.isDexRuntime()) {
+      validateSequence(
+          methodThrowToBeInlined.iterateInstructions(),
 
-        // 'if' with "foo#1" is flipped.
-        InstructionSubject::isIfEqz,
+          // 'if' with "foo#1" is flipped.
+          InstructionSubject::isIfEqz,
 
-        // 'if' with "foo#2" is removed along with the constant.
+          // 'if' with "foo#2" is removed along with the constant.
 
-        // 'if' with "foo#3" is removed so now we have an unconditional call inside the branch.
-        InstructionSubject::isIfEq,
+          // 'if' with "foo#3" is removed so now we have an unconditional call inside the branch.
+          InstructionSubject::isIfEq,
 
-        // 'if' with "foo#4" is flipped, but the throwing branch is not moved to the end of the code
-        // (area for improvement?).
-        insn -> insn.isConstString("StringConstants::foo#4", JumboStringMode.DISALLOW),
-        InstructionSubject::isIfEqz, // Flipped if
-        InstructionSubject::isGoto, // Jump around throwing branch.
-        InstructionSubject::isInvokeStatic, // Throwing branch.
-        InstructionSubject::isThrow,
+          // 'if' with "foo#4" is flipped, but the throwing branch is not moved to the end of the
+          // code
+          // (area for improvement?).
+          insn -> insn.isConstString("StringConstants::foo#4", JumboStringMode.DISALLOW),
+          InstructionSubject::isIfEqz, // Flipped if
+          InstructionSubject::isGoto, // Jump around throwing branch.
+          InstructionSubject::isInvokeStatic, // Throwing branch.
+          InstructionSubject::isThrow,
 
-        // 'if's with "foo#5" are flipped.
-        insn -> insn.isConstString("StringConstants::foo#5", JumboStringMode.DISALLOW),
-        InstructionSubject::isIfEqz, // Flipped if
-        InstructionSubject::isReturnVoid, // Final return statement.
-        InstructionSubject::isInvokeStatic, // Throwing branch.
-        InstructionSubject::isThrow,
+          // 'if's with "foo#5" are flipped.
+          insn -> insn.isConstString("StringConstants::foo#5", JumboStringMode.DISALLOW),
+          InstructionSubject::isIfEqz, // Flipped if
+          InstructionSubject::isReturnVoid, // Final return statement.
+          InstructionSubject::isInvokeStatic, // Throwing branch.
+          InstructionSubject::isThrow,
 
-        // 'if' with "foo#3" is removed so now we have an unconditional call.
-        insn -> insn.isConstString("StringConstants::foo#3", JumboStringMode.DISALLOW),
-        InstructionSubject::isInvokeStatic,
-        InstructionSubject::isThrow,
+          // 'if' with "foo#3" is removed so now we have an unconditional call.
+          insn -> insn.isConstString("StringConstants::foo#3", JumboStringMode.DISALLOW),
+          InstructionSubject::isInvokeStatic,
+          InstructionSubject::isThrow,
 
-        // After 'if' with "foo#1" flipped, the always throwing branch is moved here along with the
-        // constant.
-        insn -> insn.isConstString("StringConstants::foo#1", JumboStringMode.DISALLOW),
-        InstructionSubject::isInvokeStatic,
-        InstructionSubject::isThrow);
+          // After 'if' with "foo#1" flipped, the always throwing branch is moved here along with
+          // the
+          // constant.
+          insn -> insn.isConstString("StringConstants::foo#1", JumboStringMode.DISALLOW),
+          InstructionSubject::isInvokeStatic,
+          InstructionSubject::isThrow);
 
-    ClassSubject utilsClassSubject = inspector.clazz(Utils.class);
-    assertThat(utilsClassSubject, isPresent());
-    assertThat(utilsClassSubject.uniqueMethodWithOriginalName("throwException"), isPresent());
-    assertEquals(1, utilsClassSubject.allMethods().size());
+      ClassSubject utilsClassSubject = inspector.clazz(Utils.class);
+      assertThat(utilsClassSubject, isPresent());
+      assertThat(utilsClassSubject.uniqueMethodWithOriginalName("throwException"), isPresent());
+      assertEquals(1, utilsClassSubject.allMethods().size());
+    }
   }
 
   @SafeVarargs
@@ -151,8 +132,39 @@
     assertTrue("Not all checks processed", index >= checks.length);
   }
 
-  @Test
-  public void test() throws Exception {
-    runTest(this::validate);
+  public static class TestClass {
+    public static void main(String[] args) {}
+
+    static void foo(String arg1, String arg2, String arg3, String arg4) {
+      Utils.check(arg1, "StringConstants::foo#1");
+      Utils.check("", "StringConstants::foo#2");
+      if (arg2.length() == 12345) {
+        Utils.check(null, "StringConstants::foo#3");
+      }
+      try {
+        Utils.check(arg3, "StringConstants::foo#4");
+      } catch (Exception e) {
+        System.out.println(e.getMessage());
+      }
+      try {
+        Utils.check(arg4, "StringConstants::foo#5");
+      } finally {
+        System.out.println("finally");
+      }
+    }
+  }
+
+  static class Utils {
+    @AlwaysInline
+    static void check(Object value, String message) {
+      if (value == null) {
+        throwException(message);
+      }
+    }
+
+    @NeverInline
+    private static void throwException(String message) {
+      throw new RuntimeException(message);
+    }
   }
 }
diff --git a/src/test/java/com/android/tools/r8/movestringconstants/TestClass.java b/src/test/java/com/android/tools/r8/movestringconstants/TestClass.java
deleted file mode 100644
index 7df59d9..0000000
--- a/src/test/java/com/android/tools/r8/movestringconstants/TestClass.java
+++ /dev/null
@@ -1,44 +0,0 @@
-// Copyright (c) 2018, the R8 project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-package com.android.tools.r8.movestringconstants;
-
-import com.android.tools.r8.AlwaysInline;
-import com.android.tools.r8.NeverInline;
-
-public class TestClass {
-  public static void main(String[] args) {}
-
-  static void foo(String arg1, String arg2, String arg3, String arg4) {
-    Utils.check(arg1, "StringConstants::foo#1");
-    Utils.check("", "StringConstants::foo#2");
-    if (arg2.length() == 12345) {
-      Utils.check(null, "StringConstants::foo#3");
-    }
-    try {
-      Utils.check(arg3, "StringConstants::foo#4");
-    } catch (Exception e) {
-      System.out.println(e.getMessage());
-    }
-    try {
-      Utils.check(arg4, "StringConstants::foo#5");
-    } finally {
-      System.out.println("finally");
-    }
-  }
-}
-
-class Utils {
-  @AlwaysInline
-  static void check(Object value, String message) {
-    if (value == null) {
-      throwException(message);
-    }
-  }
-
-  @NeverInline
-  private static void throwException(String message) {
-    throw new RuntimeException(message);
-  }
-}
diff --git a/src/test/java/com/android/tools/r8/naming/AdaptResourceFileContentsTest.java b/src/test/java/com/android/tools/r8/naming/AdaptResourceFileContentsTest.java
index 3727423..dc61ce0 100644
--- a/src/test/java/com/android/tools/r8/naming/AdaptResourceFileContentsTest.java
+++ b/src/test/java/com/android/tools/r8/naming/AdaptResourceFileContentsTest.java
@@ -15,10 +15,12 @@
 import com.android.tools.r8.DataEntryResource;
 import com.android.tools.r8.DataResourceConsumer;
 import com.android.tools.r8.DataResourceProvider.Visitor;
-import com.android.tools.r8.TestCompileResult;
-import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.R8TestCompileResult;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
 import com.android.tools.r8.origin.Origin;
 import com.android.tools.r8.shaking.forceproguardcompatibility.ProguardCompatibilityTestBase;
+import com.android.tools.r8.utils.AndroidApiLevel;
 import com.android.tools.r8.utils.ArchiveResourceProvider;
 import com.android.tools.r8.utils.DataResourceConsumerForTesting;
 import com.android.tools.r8.utils.FileUtils;
@@ -36,6 +38,8 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
 
 @RunWith(Parameterized.class)
 public class AdaptResourceFileContentsTest extends ProguardCompatibilityTestBase {
@@ -46,15 +50,12 @@
           AdaptResourceFileContentsTestClass.A.class,
           AdaptResourceFileContentsTestClass.B.class);
 
-  private Backend backend;
+  @Parameter(0)
+  public TestParameters parameters;
 
-  @Parameterized.Parameters(name = "Backend: {0}")
-  public static Backend[] data() {
-    return ToolHelper.getBackends();
-  }
-
-  public AdaptResourceFileContentsTest(Backend backend) {
-    this.backend = backend;
+  @Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withDefaultRuntimes().withApiLevel(AndroidApiLevel.B).build();
   }
 
   private static final ImmutableList<String> originalAllChangedResource =
@@ -281,15 +282,16 @@
     }
   }
 
-  private TestCompileResult compileWithR8(
+  private R8TestCompileResult compileWithR8(
       String proguardConfig, DataResourceConsumer dataResourceConsumer)
       throws CompilationFailedException {
-    return testForR8(backend)
+    return testForR8(parameters.getBackend())
         .addProgramClasses(CLASSES)
         .addDataResources(getDataResources())
         .enableProguardTestOptions()
         .addKeepRules(proguardConfig)
         .addOptionsModification(o -> o.dataResourceConsumer = dataResourceConsumer)
+        .setMinApi(parameters)
         .compile();
   }
 
diff --git a/src/test/java/com/android/tools/r8/naming/NonMemberClassTest.java b/src/test/java/com/android/tools/r8/naming/NonMemberClassTest.java
index 55497de..db69516 100644
--- a/src/test/java/com/android/tools/r8/naming/NonMemberClassTest.java
+++ b/src/test/java/com/android/tools/r8/naming/NonMemberClassTest.java
@@ -143,7 +143,7 @@
     assumeTrue(
         "Only run JVM reference on CF runtimes",
         parameters.isCfRuntime() && config == TestConfig.NO_KEEP_NO_MINIFICATION);
-    testForJvm()
+    testForJvm(parameters)
         .addTestClasspath()
         .run(parameters.getRuntime(), MAIN)
         .assertSuccessWithOutput(JVM_OUTPUT);
diff --git a/src/test/java/com/android/tools/r8/naming/RenameSourceFileDebugTest.java b/src/test/java/com/android/tools/r8/naming/RenameSourceFileDebugTest.java
index 9501ae9..6d8982a 100644
--- a/src/test/java/com/android/tools/r8/naming/RenameSourceFileDebugTest.java
+++ b/src/test/java/com/android/tools/r8/naming/RenameSourceFileDebugTest.java
@@ -25,6 +25,8 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
 
 /** Tests -renamesourcefileattribute. */
 @RunWith(Parameterized.class)
@@ -74,15 +76,12 @@
     }
   }
 
-  private Backend backend;
+  @Parameter(0)
+  public Backend backend;
 
-  @Parameterized.Parameters(name = "Backend: {0}")
+  @Parameters(name = "{0}")
   public static Backend[] data() {
-    return ToolHelper.getBackends();
-  }
-
-  public RenameSourceFileDebugTest(Backend backend) {
-    this.backend = backend;
+    return Backend.values();
   }
 
   /** replica of {@link ClassInitializationTest#testBreakpointInEmptyClassInitializer} */
diff --git a/src/test/java/com/android/tools/r8/naming/WarnReflectiveAccessTestRunner.java b/src/test/java/com/android/tools/r8/naming/WarnReflectiveAccessTestRunner.java
index 0e06680..ee2bb91 100644
--- a/src/test/java/com/android/tools/r8/naming/WarnReflectiveAccessTestRunner.java
+++ b/src/test/java/com/android/tools/r8/naming/WarnReflectiveAccessTestRunner.java
@@ -4,32 +4,23 @@
 
 package com.android.tools.r8.naming;
 
-import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
 import static org.hamcrest.CoreMatchers.containsString;
-import static org.hamcrest.MatcherAssert.assertThat;
-import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotEquals;
-import static org.junit.Assert.assertTrue;
 
 import com.android.tools.r8.DiagnosticsChecker;
-import com.android.tools.r8.R8Command;
 import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestCompilerBuilder.DiagnosticsConsumer;
+import com.android.tools.r8.TestDiagnosticMessages;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
 import com.android.tools.r8.ToolHelper;
-import com.android.tools.r8.ToolHelper.ProcessResult;
-import com.android.tools.r8.origin.Origin;
-import com.android.tools.r8.utils.AndroidApp;
-import com.android.tools.r8.utils.KeepingDiagnosticHandler;
-import com.android.tools.r8.utils.Reporter;
-import com.android.tools.r8.utils.codeinspector.ClassSubject;
-import com.android.tools.r8.utils.codeinspector.CodeInspector;
-import com.google.common.collect.ImmutableList;
-import java.nio.file.Path;
-import java.util.Collections;
-import org.junit.Before;
+import com.android.tools.r8.utils.AndroidApiLevel;
+import com.android.tools.r8.utils.InternalOptions.InlinerOptions;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
 
 @RunWith(Parameterized.class)
 public class WarnReflectiveAccessTestRunner extends TestBase {
@@ -37,195 +28,165 @@
   // See "Method foo" in WarnReflectiveAccessTestMain.main().
   private static int LINE_NUMBER_OF_MARKED_LINE = 28;
 
-  private KeepingDiagnosticHandler handler;
-  private Reporter reporter;
+  @Parameter(0)
+  public TestParameters parameters;
 
-  private Backend backend;
-
-  @Parameterized.Parameters(name = "Backend: {0}")
-  public static Backend[] data() {
-    return ToolHelper.getBackends();
-  }
-
-  public WarnReflectiveAccessTestRunner(Backend backend) {
-    this.backend = backend;
-  }
-
-  @Before
-  public void reset() {
-    handler = new KeepingDiagnosticHandler();
-    reporter = new Reporter(handler);
-  }
-
-  private AndroidApp runR8(
-      byte[][] classes,
-      Class main,
-      Path out,
-      boolean explicitRule,
-      boolean enableMinification,
-      boolean forceProguardCompatibility)
-      throws Exception {
-    String minificationModifier = enableMinification ? ",allowobfuscation " : " ";
-    String reflectionRules =
-        explicitRule
-            ? "-identifiernamestring class java.lang.Class {\n"
-                  + "static java.lang.Class forName(java.lang.String);\n"
-                  + "java.lang.reflect.Method getDeclaredMethod(java.lang.String,"
-                  + " java.lang.Class[]);\n"
-                  + "}\n"
-            : "";
-    R8Command.Builder commandBuilder =
-        R8Command.builder(reporter)
-            .addProguardConfiguration(
-                ImmutableList.of(
-                    "-keep"
-                        + minificationModifier
-                        + "class "
-                        + main.getCanonicalName()
-                        + " {"
-                        + " <methods>;"
-                        + "}",
-                    "-printmapping",
-                    "-keepattributes LineNumberTable",
-                    reflectionRules),
-                Origin.unknown())
-            .setOutput(out, outputMode(backend));
-    for (byte[] clazz : classes) {
-      commandBuilder.addClassProgramData(clazz, Origin.unknown());
-    }
-    commandBuilder.addLibraryFiles(TestBase.runtimeJar(backend));
-    return ToolHelper.runR8(
-        commandBuilder.build(),
-        o -> {
-          o.inlinerOptions().enableInlining = false;
-          o.forceProguardCompatibility = forceProguardCompatibility;
-        });
+  @Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withDefaultRuntimes().withApiLevel(AndroidApiLevel.B).build();
   }
 
   private void reflectionWithBuilder(
-      boolean explicitRule, boolean enableMinification, boolean forceProguardCompatibility)
+      boolean allowDiagnosticWarningMessages,
+      boolean explicitRule,
+      boolean enableMinification,
+      boolean forceProguardCompatibility,
+      DiagnosticsConsumer diagnosticsConsumer)
       throws Exception {
-    byte[][] classes = {ToolHelper.getClassAsBytes(WarnReflectiveAccessTest.class)};
-    Path out = temp.getRoot().toPath();
-    AndroidApp processedApp =
-        runR8(
-            classes,
-            WarnReflectiveAccessTest.class,
-            out,
-            explicitRule,
+    testForR8Compat(parameters.getBackend(), forceProguardCompatibility)
+        .addProgramClasses(WarnReflectiveAccessTest.class)
+        .addKeepRules(
+            "-keepclassmembers class " + WarnReflectiveAccessTest.class.getTypeName() + " {",
+            "  public static void main(java.lang.String[]);",
+            "}")
+        .applyIf(
             enableMinification,
-            forceProguardCompatibility);
+            testBuilder ->
+                testBuilder.addKeepClassAndMembersRulesWithAllowObfuscation(
+                    WarnReflectiveAccessTest.class),
+            testBuilder -> testBuilder.addKeepClassAndMembersRules(WarnReflectiveAccessTest.class))
+        .addKeepAttributeLineNumberTable()
+        .addOptionsModification(InlinerOptions::disableInlining)
+        .allowDiagnosticWarningMessages(allowDiagnosticWarningMessages)
+        .applyIf(
+            explicitRule,
+            testBuilder ->
+                testBuilder.addKeepRules(
+                    "-identifiernamestring class java.lang.Class {",
+                    "  static java.lang.Class forName(java.lang.String);",
+                    "  java.lang.reflect.Method getDeclaredMethod(java.lang.String,"
+                        + " java.lang.Class[]);",
+                    "}"))
+        .setMinApi(parameters)
+        .compileWithExpectedDiagnostics(diagnosticsConsumer)
+        .run(parameters.getRuntime(), WarnReflectiveAccessTest.class)
+        .applyIf(
+            enableMinification,
+            runResult -> runResult.assertFailureWithErrorThatThrows(NoSuchMethodException.class),
+            runResult ->
+                runResult.assertSuccessWithOutputThatMatches(containsString("TestMain::foo")));
+  }
 
-    String main = WarnReflectiveAccessTest.class.getCanonicalName();
-    CodeInspector codeInspector = new CodeInspector(processedApp);
-    ClassSubject mainSubject = codeInspector.clazz(main);
-    assertThat(mainSubject, isPresent());
-
-    ProcessResult javaOutput = runOnJavaRaw(main, classes);
-    assertEquals(0, javaOutput.exitCode);
-    assertThat(javaOutput.stdout, containsString("TestMain::foo"));
-
-    String mainClassName = enableMinification ? mainSubject.getFinalName() : main;
-    ProcessResult output;
-    String errorString;
-    if (backend == Backend.DEX) {
-      output = runOnArtRaw(processedApp, mainClassName);
-      errorString = "NoSuchMethodError";
-    } else {
-      assert backend == Backend.CF;
-      output = runOnJavaRaw(processedApp, mainClassName, Collections.emptyList());
-      errorString = "method not found";
-    }
-    if (enableMinification) {
-      assertNotEquals(0, output.exitCode);
-      assertThat(output.stderr, containsString(errorString));
-    } else {
-      assertEquals(0, output.exitCode);
-      assertThat(output.stdout, containsString("TestMain::foo"));
-    }
+  @Test
+  public void testJvm() throws Exception {
+    parameters.assumeJvmTestParameters();
+    testForJvm(parameters)
+        .addProgramClasses(WarnReflectiveAccessTest.class)
+        .run(parameters.getRuntime(), WarnReflectiveAccessTest.class)
+        .assertSuccessWithOutputThatMatches(containsString("TestMain::foo"));
   }
 
   @Test
   public void test_explicit_minification_forceProguardCompatibility() throws Exception {
-    reflectionWithBuilder(true, true, true);
-    assertFalse(handler.warnings.isEmpty());
-    DiagnosticsChecker.checkDiagnostic(
-        handler.warnings.get(0),
-        (Path) null,
-        LINE_NUMBER_OF_MARKED_LINE,
-        1,
-        "Cannot determine",
-        "getDeclaredMethod",
-        "-identifiernamestring",
-        "resolution failure");
+    reflectionWithBuilder(
+        true,
+        true,
+        true,
+        true,
+        diagnostics -> {
+          assertFalse(diagnostics.getWarnings().isEmpty());
+          DiagnosticsChecker.checkDiagnostic(
+              diagnostics.getWarnings().get(0),
+              ToolHelper.getClassFileForTestClass(WarnReflectiveAccessTest.class),
+              LINE_NUMBER_OF_MARKED_LINE,
+              1,
+              "Cannot determine",
+              "getDeclaredMethod",
+              "-identifiernamestring",
+              "resolution failure");
+        });
   }
 
   @Test
   public void test_explicit_noMinification_forceProguardCompatibility() throws Exception {
-    reflectionWithBuilder(true, false, true);
-    assertFalse(handler.warnings.isEmpty());
-    DiagnosticsChecker.checkDiagnostic(
-        handler.warnings.get(0),
-        (Path) null,
-        LINE_NUMBER_OF_MARKED_LINE,
-        1,
-        "Cannot determine",
-        "getDeclaredMethod",
-        "-identifiernamestring",
-        "resolution failure");
+    reflectionWithBuilder(
+        true,
+        true,
+        false,
+        true,
+        diagnostics -> {
+          assertFalse(diagnostics.getWarnings().isEmpty());
+          DiagnosticsChecker.checkDiagnostic(
+              diagnostics.getWarnings().get(0),
+              ToolHelper.getClassFileForTestClass(WarnReflectiveAccessTest.class),
+              LINE_NUMBER_OF_MARKED_LINE,
+              1,
+              "Cannot determine",
+              "getDeclaredMethod",
+              "-identifiernamestring",
+              "resolution failure");
+        });
   }
 
   @Test
   public void test_explicit_minification_R8() throws Exception {
-    reflectionWithBuilder(true, true, false);
-    assertFalse(handler.warnings.isEmpty());
-    DiagnosticsChecker.checkDiagnostic(
-        handler.warnings.get(0),
-        (Path) null,
-        LINE_NUMBER_OF_MARKED_LINE,
-        1,
-        "Cannot determine",
-        "getDeclaredMethod",
-        "-identifiernamestring",
-        "resolution failure");
+    reflectionWithBuilder(
+        true,
+        true,
+        true,
+        false,
+        diagnostics -> {
+          assertFalse(diagnostics.getWarnings().isEmpty());
+          DiagnosticsChecker.checkDiagnostic(
+              diagnostics.getWarnings().get(0),
+              ToolHelper.getClassFileForTestClass(WarnReflectiveAccessTest.class),
+              LINE_NUMBER_OF_MARKED_LINE,
+              1,
+              "Cannot determine",
+              "getDeclaredMethod",
+              "-identifiernamestring",
+              "resolution failure");
+        });
   }
 
   @Test
   public void test_explicit_noMinification_R8() throws Exception {
-    reflectionWithBuilder(true, false, false);
-    assertFalse(handler.warnings.isEmpty());
-    DiagnosticsChecker.checkDiagnostic(
-        handler.warnings.get(0),
-        (Path) null,
-        LINE_NUMBER_OF_MARKED_LINE,
-        1,
-        "Cannot determine",
-        "getDeclaredMethod",
-        "-identifiernamestring",
-        "resolution failure");
+    reflectionWithBuilder(
+        true,
+        true,
+        false,
+        false,
+        diagnostics -> {
+          assertFalse(diagnostics.getWarnings().isEmpty());
+          DiagnosticsChecker.checkDiagnostic(
+              diagnostics.getWarnings().get(0),
+              ToolHelper.getClassFileForTestClass(WarnReflectiveAccessTest.class),
+              LINE_NUMBER_OF_MARKED_LINE,
+              1,
+              "Cannot determine",
+              "getDeclaredMethod",
+              "-identifiernamestring",
+              "resolution failure");
+        });
   }
 
   @Test
   public void test_implicit_minification_forceProguardCompatibility() throws Exception {
-    reflectionWithBuilder(false, true, true);
-    assertTrue(handler.warnings.isEmpty());
+    reflectionWithBuilder(false, false, true, true, TestDiagnosticMessages::assertNoWarnings);
   }
 
   @Test
   public void test_implicit_noMinification_forceProguardCompatibility() throws Exception {
-    reflectionWithBuilder(false, false, true);
-    assertTrue(handler.warnings.isEmpty());
+    reflectionWithBuilder(false, false, false, true, TestDiagnosticMessages::assertNoWarnings);
   }
 
   @Test
   public void test_implicit_minification_R8() throws Exception {
-    reflectionWithBuilder(false, true, false);
-    assertTrue(handler.warnings.isEmpty());
+    reflectionWithBuilder(false, false, true, false, TestDiagnosticMessages::assertNoWarnings);
   }
 
   @Test
   public void test_implicit_noMinification_R8() throws Exception {
-    reflectionWithBuilder(false, false, false);
-    assertTrue(handler.warnings.isEmpty());
+    reflectionWithBuilder(false, false, false, false, TestDiagnosticMessages::assertNoWarnings);
   }
 }
diff --git a/src/test/java/com/android/tools/r8/naming/applymapping/ApplyMappingAfterDevirtualizationTest.java b/src/test/java/com/android/tools/r8/naming/applymapping/ApplyMappingAfterDevirtualizationTest.java
index 19b499a..1219836 100644
--- a/src/test/java/com/android/tools/r8/naming/applymapping/ApplyMappingAfterDevirtualizationTest.java
+++ b/src/test/java/com/android/tools/r8/naming/applymapping/ApplyMappingAfterDevirtualizationTest.java
@@ -16,7 +16,6 @@
 import com.android.tools.r8.TestParametersCollection;
 import com.android.tools.r8.utils.StringUtils;
 import com.android.tools.r8.utils.codeinspector.CodeInspector;
-import org.junit.Assume;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
@@ -96,8 +95,8 @@
 
   @Test
   public void runOnJvm() throws Throwable {
-    Assume.assumeTrue(parameters.isCfRuntime());
-    testForJvm()
+    parameters.assumeJvmTestParameters();
+    testForJvm(parameters)
         .addClasspathClasses(CLASSPATH_CLASSES)
         .addProgramClasses(PROGRAM_CLASSES)
         .run(parameters.getRuntime(), ProgramClass.class)
diff --git a/src/test/java/com/android/tools/r8/naming/applymapping/ApplyMappingAfterHorizontalMergingFieldTest.java b/src/test/java/com/android/tools/r8/naming/applymapping/ApplyMappingAfterHorizontalMergingFieldTest.java
index fea21aa..22a0643 100644
--- a/src/test/java/com/android/tools/r8/naming/applymapping/ApplyMappingAfterHorizontalMergingFieldTest.java
+++ b/src/test/java/com/android/tools/r8/naming/applymapping/ApplyMappingAfterHorizontalMergingFieldTest.java
@@ -13,7 +13,6 @@
 import com.android.tools.r8.TestParametersCollection;
 import com.android.tools.r8.utils.StringUtils;
 import com.android.tools.r8.utils.codeinspector.CodeInspector;
-import org.junit.Assume;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
@@ -78,8 +77,8 @@
 
   @Test
   public void runOnJvm() throws Throwable {
-    Assume.assumeTrue(parameters.isCfRuntime());
-    testForJvm()
+    parameters.assumeJvmTestParameters();
+    testForJvm(parameters)
         .addProgramClasses(LIBRARY_CLASSES)
         .addProgramClasses(PROGRAM_CLASSES)
         .run(parameters.getRuntime(), ProgramClass.class)
diff --git a/src/test/java/com/android/tools/r8/naming/applymapping/ApplyMappingAfterHorizontalMergingMethodTest.java b/src/test/java/com/android/tools/r8/naming/applymapping/ApplyMappingAfterHorizontalMergingMethodTest.java
index ac2e989..1c19a2e 100644
--- a/src/test/java/com/android/tools/r8/naming/applymapping/ApplyMappingAfterHorizontalMergingMethodTest.java
+++ b/src/test/java/com/android/tools/r8/naming/applymapping/ApplyMappingAfterHorizontalMergingMethodTest.java
@@ -11,13 +11,15 @@
 import com.android.tools.r8.NeverPropagateValue;
 import com.android.tools.r8.R8TestCompileResult;
 import com.android.tools.r8.TestBase;
-import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
 import com.android.tools.r8.utils.StringUtils;
 import com.android.tools.r8.utils.codeinspector.CodeInspector;
-import org.junit.Assume;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
 
 @RunWith(Parameterized.class)
 public class ApplyMappingAfterHorizontalMergingMethodTest extends TestBase {
@@ -72,35 +74,34 @@
       ProgramClass.class
   };
 
-  private Backend backend;
+  @Parameter(0)
+  public TestParameters parameters;
 
-  @Parameterized.Parameters(name = "{0}")
-  public static Backend[] data() {
-    return ToolHelper.getBackends();
-  }
-
-  public ApplyMappingAfterHorizontalMergingMethodTest(Backend backend) {
-    this.backend = backend;
+  @Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withAllRuntimesAndApiLevels().build();
   }
 
   @Test
   public void runOnJvm() throws Throwable {
-    Assume.assumeTrue(backend == Backend.CF);
-    testForJvm()
+    parameters.assumeJvmTestParameters();
+    testForJvm(parameters)
         .addProgramClasses(LIBRARY_CLASSES)
         .addProgramClasses(PROGRAM_CLASSES)
-        .run(ProgramClass.class)
+        .run(parameters.getRuntime(), ProgramClass.class)
         .assertSuccessWithOutput(EXPECTED_SUCCESS);
   }
 
   @Test
   public void b121042934() throws Exception {
-    R8TestCompileResult libraryResult = testForR8(backend)
-        .enableInliningAnnotations()
-        .enableMemberValuePropagationAnnotations()
-        .addProgramClasses(LIBRARY_CLASSES)
-        .addKeepMainRule(LibraryMain.class)
-        .compile();
+    R8TestCompileResult libraryResult =
+        testForR8(parameters.getBackend())
+            .enableInliningAnnotations()
+            .enableMemberValuePropagationAnnotations()
+            .addProgramClasses(LIBRARY_CLASSES)
+            .addKeepMainRule(LibraryMain.class)
+            .setMinApi(parameters)
+            .compile();
 
     CodeInspector inspector = libraryResult.inspector();
     assertThat(inspector.clazz(LibraryMain.class), isPresent());
@@ -108,16 +109,17 @@
     assertTrue(inspector.clazz(LibraryA.class).isPresent()
         != inspector.clazz(LibraryB.class).isPresent());
 
-    testForR8(backend)
+    testForR8(parameters.getBackend())
         .noTreeShaking()
         .addDontObfuscate()
         .addProgramClasses(PROGRAM_CLASSES)
         .addApplyMapping(libraryResult.getProguardMap())
         .addLibraryClasses(LIBRARY_CLASSES)
-        .addLibraryFiles(runtimeJar(backend))
+        .addLibraryFiles(parameters.getDefaultRuntimeLibrary())
+        .setMinApi(parameters)
         .compile()
         .addRunClasspathFiles(libraryResult.writeToZip())
-        .run(ProgramClass.class)
+        .run(parameters.getRuntime(), ProgramClass.class)
         .assertSuccessWithOutput(EXPECTED_SUCCESS);
   }
 }
diff --git a/src/test/java/com/android/tools/r8/naming/applymapping/ApplyMappingAfterVerticalMergingFieldTest.java b/src/test/java/com/android/tools/r8/naming/applymapping/ApplyMappingAfterVerticalMergingFieldTest.java
index 0fe35cb..3b08988 100644
--- a/src/test/java/com/android/tools/r8/naming/applymapping/ApplyMappingAfterVerticalMergingFieldTest.java
+++ b/src/test/java/com/android/tools/r8/naming/applymapping/ApplyMappingAfterVerticalMergingFieldTest.java
@@ -9,13 +9,15 @@
 
 import com.android.tools.r8.R8TestCompileResult;
 import com.android.tools.r8.TestBase;
-import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
 import com.android.tools.r8.utils.StringUtils;
 import com.android.tools.r8.utils.codeinspector.CodeInspector;
-import org.junit.Assume;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
 
 @RunWith(Parameterized.class)
 public class ApplyMappingAfterVerticalMergingFieldTest extends TestBase {
@@ -55,49 +57,49 @@
       ProgramClass.class
   };
 
-  private Backend backend;
+  @Parameter(0)
+  public TestParameters parameters;
 
-  @Parameterized.Parameters(name = "{0}")
-  public static Backend[] data() {
-    return ToolHelper.getBackends();
-  }
-
-  public ApplyMappingAfterVerticalMergingFieldTest(Backend backend) {
-    this.backend = backend;
+  @Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withAllRuntimesAndApiLevels().build();
   }
 
   @Test
   public void runOnJvm() throws Throwable {
-    Assume.assumeTrue(backend == Backend.CF);
-    testForJvm()
+    parameters.assumeJvmTestParameters();
+    testForJvm(parameters)
         .addProgramClasses(LIBRARY_CLASSES)
         .addProgramClasses(PROGRAM_CLASSES)
-        .run(ProgramClass.class)
+        .run(parameters.getRuntime(), ProgramClass.class)
         .assertSuccessWithOutput(EXPECTED_SUCCESS);
   }
 
   @Test
   public void b121042934() throws Exception {
-    R8TestCompileResult libraryResult = testForR8(backend)
-        .addProgramClasses(LIBRARY_CLASSES)
-        .addKeepMainRule(LibrarySubclass.class)
-        .addKeepClassAndDefaultConstructor(LibrarySubclass.class)
-        .compile();
+    R8TestCompileResult libraryResult =
+        testForR8(parameters.getBackend())
+            .addProgramClasses(LIBRARY_CLASSES)
+            .addKeepMainRule(LibrarySubclass.class)
+            .addKeepClassAndDefaultConstructor(LibrarySubclass.class)
+            .setMinApi(parameters)
+            .compile();
 
     CodeInspector inspector = libraryResult.inspector();
     assertThat(inspector.clazz(LibraryBase.class), not(isPresent()));
     assertThat(inspector.clazz(LibrarySubclass.class), isPresent());
 
-    testForR8(backend)
+    testForR8(parameters.getBackend())
         .noTreeShaking()
         .addDontObfuscate()
         .addProgramClasses(PROGRAM_CLASSES)
         .addApplyMapping(libraryResult.getProguardMap())
         .addLibraryClasses(LIBRARY_CLASSES)
-        .addLibraryFiles(runtimeJar(backend))
+        .addLibraryFiles(parameters.getDefaultRuntimeLibrary())
+        .setMinApi(parameters)
         .compile()
         .addRunClasspathFiles(libraryResult.writeToZip())
-        .run(ProgramClass.class)
+        .run(parameters.getRuntime(), ProgramClass.class)
         .assertSuccessWithOutput(EXPECTED_SUCCESS);
   }
 }
diff --git a/src/test/java/com/android/tools/r8/naming/applymapping/ApplyMappingAfterVerticalMergingMethodTest.java b/src/test/java/com/android/tools/r8/naming/applymapping/ApplyMappingAfterVerticalMergingMethodTest.java
index 609465f..8c0274e 100644
--- a/src/test/java/com/android/tools/r8/naming/applymapping/ApplyMappingAfterVerticalMergingMethodTest.java
+++ b/src/test/java/com/android/tools/r8/naming/applymapping/ApplyMappingAfterVerticalMergingMethodTest.java
@@ -24,7 +24,6 @@
 import java.util.List;
 import java.util.concurrent.ExecutionException;
 import java.util.function.Function;
-import org.junit.Assume;
 import org.junit.ClassRule;
 import org.junit.Test;
 import org.junit.rules.TemporaryFolder;
@@ -152,8 +151,8 @@
 
   @Test
   public void runOnJvm() throws Throwable {
-    Assume.assumeTrue(parameters.isCfRuntime());
-    testForJvm()
+    parameters.assumeJvmTestParameters();
+    testForJvm(parameters)
         .addProgramClasses(LIBRARY_CLASSES)
         .addProgramClasses(PROGRAM_CLASSES)
         .run(parameters.getRuntime(), ProgramClass.class)
diff --git a/src/test/java/com/android/tools/r8/naming/applymapping/desugar/DefaultInterfaceMethodTest.java b/src/test/java/com/android/tools/r8/naming/applymapping/desugar/DefaultInterfaceMethodTest.java
index a18cf8a..37f2b71 100644
--- a/src/test/java/com/android/tools/r8/naming/applymapping/desugar/DefaultInterfaceMethodTest.java
+++ b/src/test/java/com/android/tools/r8/naming/applymapping/desugar/DefaultInterfaceMethodTest.java
@@ -15,7 +15,6 @@
 import com.android.tools.r8.utils.StringUtils;
 import com.android.tools.r8.utils.codeinspector.ClassSubject;
 import com.android.tools.r8.utils.codeinspector.CodeInspector;
-import org.junit.Assume;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
@@ -53,8 +52,8 @@
 
   @Test
   public void testJvm() throws Throwable {
-    Assume.assumeTrue(parameters.isCfRuntime());
-    testForJvm()
+    parameters.assumeJvmTestParameters();
+    testForJvm(parameters)
         .addProgramClasses(LibraryInterface.class, ProgramClass.class)
         .run(parameters.getRuntime(), ProgramClass.class)
         .assertSuccessWithOutput(EXPECTED);
diff --git a/src/test/java/com/android/tools/r8/naming/applymapping/desugar/StaticInterfaceMethodTest.java b/src/test/java/com/android/tools/r8/naming/applymapping/desugar/StaticInterfaceMethodTest.java
index 49fffdc..d42b085 100644
--- a/src/test/java/com/android/tools/r8/naming/applymapping/desugar/StaticInterfaceMethodTest.java
+++ b/src/test/java/com/android/tools/r8/naming/applymapping/desugar/StaticInterfaceMethodTest.java
@@ -16,7 +16,6 @@
 import com.android.tools.r8.utils.StringUtils;
 import com.android.tools.r8.utils.codeinspector.ClassSubject;
 import com.android.tools.r8.utils.codeinspector.CodeInspector;
-import org.junit.Assume;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
@@ -55,8 +54,8 @@
 
   @Test
   public void testJvm() throws Throwable {
-    Assume.assumeTrue(parameters.isCfRuntime());
-    testForJvm()
+    parameters.assumeJvmTestParameters();
+    testForJvm(parameters)
         .addProgramClasses(LibraryInterface.class, ProgramClass.class)
         .run(parameters.getRuntime(), ProgramClass.class)
         .assertSuccessWithOutput(EXPECTED);
diff --git a/src/test/java/com/android/tools/r8/naming/applymapping/sourcelibrary/ApplyMappingTest.java b/src/test/java/com/android/tools/r8/naming/applymapping/sourcelibrary/ApplyMappingTest.java
index 01de767..e0d32a3 100644
--- a/src/test/java/com/android/tools/r8/naming/applymapping/sourcelibrary/ApplyMappingTest.java
+++ b/src/test/java/com/android/tools/r8/naming/applymapping/sourcelibrary/ApplyMappingTest.java
@@ -9,13 +9,13 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
 
-import com.android.tools.r8.CompilationFailedException;
-import com.android.tools.r8.R8Command;
 import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
 import com.android.tools.r8.ToolHelper;
 import com.android.tools.r8.graph.DexMethod;
 import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.utils.AndroidApp;
+import com.android.tools.r8.utils.AndroidApiLevel;
 import com.android.tools.r8.utils.FileUtils;
 import com.android.tools.r8.utils.codeinspector.ClassSubject;
 import com.android.tools.r8.utils.codeinspector.CodeInspector;
@@ -23,25 +23,18 @@
 import com.android.tools.r8.utils.codeinspector.InvokeInstructionSubject;
 import com.android.tools.r8.utils.codeinspector.MethodSubject;
 import com.android.tools.r8.utils.codeinspector.NewInstanceInstructionSubject;
-import java.io.IOException;
 import java.nio.file.Path;
 import java.nio.file.Paths;
 import java.util.Iterator;
-import java.util.concurrent.ExecutionException;
-import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
 import org.junit.runners.Parameterized.Parameters;
 
 @RunWith(Parameterized.class)
 public class ApplyMappingTest extends TestBase {
 
-  private static final String MAPPING = "test-mapping.txt";
-
-  private static final Path MINIFICATION_JAR =
-      Paths.get(ToolHelper.EXAMPLES_BUILD_DIR, "minification" + FileUtils.JAR_EXTENSION);
-
   private static final Path NAMING001_JAR =
       Paths.get(ToolHelper.EXAMPLES_BUILD_DIR, "naming001" + FileUtils.JAR_EXTENSION);
 
@@ -51,37 +44,28 @@
   private static final Path APPLYMAPPING044_JAR =
       Paths.get(ToolHelper.EXAMPLES_BUILD_DIR, "applymapping044" + FileUtils.JAR_EXTENSION);
 
-  private Path out;
+  @Parameter(0)
+  public TestParameters parameters;
 
-  private Backend backend;
-
-  @Parameters(name = "Backend: {0}")
-  public static Backend[] data() {
-    return ToolHelper.getBackends();
-  }
-
-  public ApplyMappingTest(Backend backend) {
-    this.backend = backend;
-  }
-
-  @Before
-  public void setup() throws IOException {
-    out = temp.newFolder("out").toPath();
+  @Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withDefaultRuntimes().withApiLevel(AndroidApiLevel.B).build();
   }
 
   @Test
   public void test044_apply() throws Exception {
-    Path flag =
-        Paths.get(ToolHelper.EXAMPLES_DIR, "applymapping044", "keep-rules-apply-mapping.txt");
-    AndroidApp outputApp =
-        runR8(
-            getCommandForInstrumentation(out, flag, NAMING044_JAR, APPLYMAPPING044_JAR)
-                .setDisableMinification(true)
-                .setOutput(out, outputMode(Backend.CF))
-                .build());
-
     // Make sure the given proguard map is indeed applied.
-    CodeInspector inspector = createDexInspector(outputApp);
+    CodeInspector inspector =
+        testForR8(parameters.getBackend())
+            .addProgramFiles(APPLYMAPPING044_JAR)
+            .addClasspathFiles(NAMING044_JAR)
+            .addKeepRuleFiles(
+                Paths.get(
+                    ToolHelper.EXAMPLES_DIR, "applymapping044", "keep-rules-apply-mapping.txt"))
+            .addDontObfuscate()
+            .setMinApi(parameters)
+            .compile()
+            .inspector();
     MethodSubject main = inspector.clazz("applymapping044.Main").method(CodeInspector.MAIN);
     Iterator<InvokeInstructionSubject> iterator =
         main.iterateInstructions(InstructionSubject::isInvoke);
@@ -123,28 +107,19 @@
     assertEquals("p", original_f.invokedMethod().name.toString());
   }
 
-  private static CodeInspector createDexInspector(AndroidApp outputApp)
-      throws IOException, ExecutionException {
-    return new CodeInspector(outputApp);
-  }
-
   @Test
   public void test_naming001_rule105() throws Exception {
     // keep rules to reserve D and E, along with a proguard map.
-    Path flag = Paths.get(ToolHelper.EXAMPLES_DIR, "naming001", "keep-rules-105.txt");
-    Path proguardMap = out.resolve(MAPPING);
-    AndroidApp outputApp =
-        runR8(
-            ToolHelper.addProguardConfigurationConsumer(
-                    getCommandForApps(out, flag, NAMING001_JAR).setDisableMinification(true),
-                    pgConfig -> {
-                      pgConfig.setPrintMapping(true);
-                      pgConfig.setPrintMappingFile(proguardMap);
-                    })
-                .build());
+    CodeInspector inspector =
+        testForR8(parameters.getBackend())
+            .addProgramFiles(NAMING001_JAR)
+            .addKeepRuleFiles(Paths.get(ToolHelper.EXAMPLES_DIR, "naming001", "keep-rules-105.txt"))
+            .addDontObfuscate()
+            .setMinApi(parameters)
+            .compile()
+            .inspector();
 
     // Make sure the given proguard map is indeed applied.
-    CodeInspector inspector = createDexInspector(outputApp);
     ClassSubject classD = inspector.clazz("naming001.D");
     assertThat(classD, isPresent());
     // D must not be renamed
@@ -165,22 +140,18 @@
   @Test
   public void test_naming001_rule106() throws Exception {
     // keep rules just to rename E
-    Path flag = Paths.get(ToolHelper.EXAMPLES_DIR, "naming001", "keep-rules-106.txt");
-    Path proguardMap = out.resolve(MAPPING);
-    AndroidApp outputApp =
-        runR8(
-            ToolHelper.addProguardConfigurationConsumer(
-                    getCommandForApps(out, flag, NAMING001_JAR),
-                    pgConfig -> {
-                      pgConfig.disableShrinking();
-                      pgConfig.setPrintMapping(true);
-                      pgConfig.setPrintMappingFile(proguardMap);
-                    })
-                .build());
+    CodeInspector inspector =
+        testForR8(parameters.getBackend())
+            .addProgramFiles(NAMING001_JAR)
+            .addKeepRuleFiles(Paths.get(ToolHelper.EXAMPLES_DIR, "naming001", "keep-rules-106.txt"))
+            .noTreeShaking()
+            .setMinApi(parameters)
+            .compile()
+            .inspector();
 
     // Make sure the given proguard map is indeed applied.
-    CodeInspector inspector = createDexInspector(outputApp);
-    MethodSubject main = inspector.clazz("naming001.D").method(CodeInspector.MAIN);
+    MethodSubject main = inspector.clazz("naming001.D").mainMethod();
+    assertThat(main, isPresent());
 
     Iterator<InstructionSubject> iterator = main.iterateInstructions();
     // naming001.E is renamed to a.a, so first instruction must be: new-instance La/a;
@@ -195,32 +166,4 @@
     assertNotNull(newInstance);
     assertEquals( "La/a;", newInstance.getType().toSmaliString());
   }
-
-  private R8Command.Builder getCommandForInstrumentation(
-      Path out, Path flag, Path mainApp, Path instrApp) throws IOException {
-    return R8Command.builder()
-        .addLibraryFiles(runtimeJar(backend))
-        .addClasspathFiles(mainApp)
-        .addProgramFiles(instrApp)
-        .setOutput(out, outputMode(backend))
-        .addProguardConfigurationFiles(flag);
-  }
-
-  private R8Command.Builder getCommandForApps(Path out, Path flag, Path... jars)
-      throws IOException {
-    return R8Command.builder()
-        .addLibraryFiles(runtimeJar(backend))
-        .addProgramFiles(jars)
-        .setOutput(out, outputMode(backend))
-        .addProguardConfigurationFiles(flag);
-  }
-
-  private static AndroidApp runR8(R8Command command) throws CompilationFailedException {
-    return ToolHelper.runR8(
-        command,
-        options -> {
-          // Disable inlining to make this test not depend on inlining decisions.
-          options.inlinerOptions().enableInlining = false;
-        });
-  }
 }
diff --git a/src/test/java/com/android/tools/r8/naming/applymapping/sourcelibrary/MemberResolutionTest.java b/src/test/java/com/android/tools/r8/naming/applymapping/sourcelibrary/MemberResolutionTest.java
index 7fd2094..e71747b 100644
--- a/src/test/java/com/android/tools/r8/naming/applymapping/sourcelibrary/MemberResolutionTest.java
+++ b/src/test/java/com/android/tools/r8/naming/applymapping/sourcelibrary/MemberResolutionTest.java
@@ -111,7 +111,7 @@
             "ConcreteChecker#check:NewTag");
 
     if (parameters.isCfRuntime()) {
-      testForJvm()
+      testForJvm(parameters)
           .addTestClasspath()
           .run(parameters.getRuntime(), MemberResolutionTestMain.class)
           .assertSuccessWithOutput(expectedOutput);
diff --git a/src/test/java/com/android/tools/r8/naming/b114554345/B114554345.java b/src/test/java/com/android/tools/r8/naming/b114554345/B114554345.java
index 4af7be5..c624ea7 100644
--- a/src/test/java/com/android/tools/r8/naming/b114554345/B114554345.java
+++ b/src/test/java/com/android/tools/r8/naming/b114554345/B114554345.java
@@ -4,124 +4,134 @@
 
 package com.android.tools.r8.naming.b114554345;
 
-import static junit.framework.TestCase.assertEquals;
 
 import com.android.tools.r8.TestBase;
-import com.android.tools.r8.ToolHelper;
-import com.android.tools.r8.utils.AndroidApp;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.utils.InternalOptions.InlinerOptions;
+import com.android.tools.r8.utils.StringUtils;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
 import org.junit.runners.Parameterized.Parameters;
 
 @RunWith(Parameterized.class)
 public class B114554345 extends TestBase {
 
-  private final Backend backend;
+  private static final String EXPECTED_OUTPUT =
+      StringUtils.lines(
+          "In InterfaceImpl.method()",
+          "In OtherInterfaceImpl.method()",
+          "In SubInterfaceImpl.method()",
+          "In YetAnotherSubInterfaceImpl.method()",
+          "In SubInterfaceImpl.method()",
+          "In OtherSubInterfaceImpl.method()",
+          "In YetAnotherSubInterfaceImpl.method()");
 
-  @Parameters(name = "backend: {0}")
-  public static Backend[] data() {
-    return ToolHelper.getBackends();
-  }
+  @Parameter(0)
+  public TestParameters parameters;
 
-  public B114554345(Backend backend) {
-    this.backend = backend;
+  @Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withAllRuntimesAndApiLevels().build();
   }
 
   @Test
-  public void test() throws Exception {
-    AndroidApp input =
-        AndroidApp.builder()
-            .addProgramFiles(
-                ToolHelper.getClassFilesForTestDirectory(
-                    ToolHelper.getPackageDirectoryForTestPackage(this.getClass().getPackage()),
-                    path -> !path.toString().contains("B114554345")))
-            .build();
-    AndroidApp output =
-        compileWithR8(
-            input,
-            keepMainProguardConfiguration(TestDriver.class),
-            options -> options.inlinerOptions().enableInlining = false,
-            backend);
-    String mainClass = TestDriver.class.getName();
-    assertEquals(runOnJava(TestDriver.class), runOnVM(output, mainClass, backend));
-  }
-}
-
-// Interface and two implementations.
-
-interface Interface {
-  Interface method();
-}
-
-class InterfaceImpl implements Interface {
-
-  @Override
-  public InterfaceImpl method() {
-    System.out.println("In InterfaceImpl.method()");
-    return this;
-  }
-}
-
-class OtherInterfaceImpl extends InterfaceImpl {
-
-  @Override
-  public OtherInterfaceImpl method() {
-    System.out.println("In OtherInterfaceImpl.method()");
-    return this;
-  }
-}
-
-// Sub-interface and three implementations.
-
-interface SubInterface extends Interface {
-  SubInterface method();
-}
-
-class SubInterfaceImpl implements SubInterface {
-
-  @Override
-  public SubInterfaceImpl method() {
-    System.out.println("In SubInterfaceImpl.method()");
-    return this;
-  }
-}
-
-class OtherSubInterfaceImpl implements SubInterface {
-
-  @Override
-  public OtherSubInterfaceImpl method() {
-    System.out.println("In OtherSubInterfaceImpl.method()");
-    return this;
-  }
-}
-
-class YetAnotherSubInterfaceImpl extends InterfaceImpl implements SubInterface {
-
-  @Override
-  public YetAnotherSubInterfaceImpl method() {
-    System.out.println("In YetAnotherSubInterfaceImpl.method()");
-    return this;
-  }
-}
-
-class TestDriver {
-
-  public static void main(String[] args) {
-    foo(new InterfaceImpl());
-    foo(new OtherInterfaceImpl());
-    foo(new SubInterfaceImpl());
-    foo(new YetAnotherSubInterfaceImpl());
-    bar(new SubInterfaceImpl());
-    bar(new OtherSubInterfaceImpl());
-    bar(new YetAnotherSubInterfaceImpl());
+  public void testJvm() throws Exception {
+    parameters.assumeJvmTestParameters();
+    testForJvm(parameters)
+        .addInnerClasses(getClass())
+        .run(parameters.getRuntime(), TestDriver.class)
+        .assertSuccessWithOutput(EXPECTED_OUTPUT);
   }
 
-  private static void foo(Interface obj) {
-    obj.method();
+  @Test
+  public void testR8() throws Exception {
+    testForR8(parameters.getBackend())
+        .addInnerClasses(getClass())
+        .addKeepMainRule(TestDriver.class)
+        .addOptionsModification(InlinerOptions::disableInlining)
+        .setMinApi(parameters)
+        .run(parameters.getRuntime(), TestDriver.class)
+        .assertSuccessWithOutput(EXPECTED_OUTPUT);
   }
 
-  private static void bar(SubInterface obj) {
-    obj.method();
+  // Interface and two implementations.
+
+  interface Interface {
+    Interface method();
+  }
+
+  static class InterfaceImpl implements Interface {
+
+    @Override
+    public InterfaceImpl method() {
+      System.out.println("In InterfaceImpl.method()");
+      return this;
+    }
+  }
+
+  static class OtherInterfaceImpl extends InterfaceImpl {
+
+    @Override
+    public OtherInterfaceImpl method() {
+      System.out.println("In OtherInterfaceImpl.method()");
+      return this;
+    }
+  }
+
+  // Sub-interface and three implementations.
+
+  interface SubInterface extends Interface {
+    SubInterface method();
+  }
+
+  static class SubInterfaceImpl implements SubInterface {
+
+    @Override
+    public SubInterfaceImpl method() {
+      System.out.println("In SubInterfaceImpl.method()");
+      return this;
+    }
+  }
+
+  static class OtherSubInterfaceImpl implements SubInterface {
+
+    @Override
+    public OtherSubInterfaceImpl method() {
+      System.out.println("In OtherSubInterfaceImpl.method()");
+      return this;
+    }
+  }
+
+  static class YetAnotherSubInterfaceImpl extends InterfaceImpl implements SubInterface {
+
+    @Override
+    public YetAnotherSubInterfaceImpl method() {
+      System.out.println("In YetAnotherSubInterfaceImpl.method()");
+      return this;
+    }
+  }
+
+  static class TestDriver {
+
+    public static void main(String[] args) {
+      foo(new InterfaceImpl());
+      foo(new OtherInterfaceImpl());
+      foo(new SubInterfaceImpl());
+      foo(new YetAnotherSubInterfaceImpl());
+      bar(new SubInterfaceImpl());
+      bar(new OtherSubInterfaceImpl());
+      bar(new YetAnotherSubInterfaceImpl());
+    }
+
+    private static void foo(Interface obj) {
+      obj.method();
+    }
+
+    private static void bar(SubInterface obj) {
+      obj.method();
+    }
   }
 }
diff --git a/src/test/java/com/android/tools/r8/naming/b116840216/ReserveOuterClassNameTest.java b/src/test/java/com/android/tools/r8/naming/b116840216/ReserveOuterClassNameTest.java
index a55e7da..8b50be9 100644
--- a/src/test/java/com/android/tools/r8/naming/b116840216/ReserveOuterClassNameTest.java
+++ b/src/test/java/com/android/tools/r8/naming/b116840216/ReserveOuterClassNameTest.java
@@ -7,14 +7,11 @@
 import static com.android.tools.r8.utils.codeinspector.Matchers.isPresentAndRenamed;
 import static org.hamcrest.MatcherAssert.assertThat;
 
-import com.android.tools.r8.CompatProguardCommandBuilder;
 import com.android.tools.r8.NeverInline;
 import com.android.tools.r8.NoHorizontalClassMerging;
-import com.android.tools.r8.R8Command;
 import com.android.tools.r8.TestBase;
-import com.android.tools.r8.ToolHelper;
-import com.android.tools.r8.origin.Origin;
-import com.android.tools.r8.utils.AndroidApp;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
 import com.android.tools.r8.utils.codeinspector.ClassSubject;
 import com.android.tools.r8.utils.codeinspector.CodeInspector;
 import com.android.tools.r8.utils.codeinspector.MethodSubject;
@@ -22,6 +19,7 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
 import org.junit.runners.Parameterized.Parameters;
 
 @NoHorizontalClassMerging
@@ -51,45 +49,34 @@
 @RunWith(Parameterized.class)
 public class ReserveOuterClassNameTest extends TestBase {
 
-  private Backend backend;
+  @Parameter(0)
+  public TestParameters parameters;
 
-  @Parameters(name = "Backend: {0}")
-  public static Backend[] data() {
-    return ToolHelper.getBackends();
-  }
-
-  public ReserveOuterClassNameTest(Backend backend){
-    this.backend = backend;
+  @Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withAllRuntimesAndApiLevels().build();
   }
 
   private void runTest(boolean keepOuterName) throws Exception {
-    Class mainClass = TestMain.class;
-    R8Command.Builder builder = new CompatProguardCommandBuilder(true);
-    builder.addProgramFiles(
-        ToolHelper.getClassFileForTestClass(mainClass),
-        ToolHelper.getClassFileForTestClass(Outer.class),
-        ToolHelper.getClassFileForTestClass(Outer.Inner.class),
-        ToolHelper.getClassFileForTestClass(NeverInline.class),
-        ToolHelper.getClassFileForTestClass(NoHorizontalClassMerging.class));
-    builder.setProgramConsumer(emptyConsumer(backend));
-    builder.addLibraryFiles(runtimeJar(backend));
-    builder.addProguardConfiguration(
-        ImmutableList.of(
-            "-printmapping",
-            "-keepattributes EnclosingMethod,InnerClasses,Signature",
-            keepMainProguardConfigurationWithInliningAnnotation(mainClass),
-            // Note that reproducing b/116840216 relies on the order of following rules that cause
-            // the visiting of classes during class minification to be Outer$Inner before Outer.
-            "-keepnames class " + Outer.class.getCanonicalName() + "$Inner",
-            keepOuterName ? "-keepnames class " + Outer.class.getCanonicalName() : "",
-            noHorizontalClassMerging()),
-        Origin.unknown());
+    CodeInspector inspector =
+        testForR8Compat(parameters.getBackend())
+            .addProgramClasses(TestMain.class, Outer.class, Outer.Inner.class)
+            .addKeepAttributeInnerClassesAndEnclosingMethod()
+            .addKeepAttributeSignature()
+            .addKeepMainRule(TestMain.class)
+            .addKeepRules(
+                // Note that reproducing b/116840216 relies on the order of following rules that
+                // cause
+                // the visiting of classes during class minification to be Outer$Inner before Outer.
+                "-keepnames class " + Outer.class.getCanonicalName() + "$Inner",
+                keepOuterName ? "-keepnames class " + Outer.class.getCanonicalName() : "")
+            .enableInliningAnnotations()
+            .enableNoHorizontalClassMergingAnnotations()
+            .setMinApi(parameters)
+            .compile()
+            .inspector();
 
-    ToolHelper.allowTestProguardOptions(builder);
-    AndroidApp processedApp = ToolHelper.runR8(builder.build());
-
-    CodeInspector inspector = new CodeInspector(processedApp);
-    ClassSubject mainSubject = inspector.clazz(mainClass);
+    ClassSubject mainSubject = inspector.clazz(TestMain.class);
     assertThat(mainSubject, isPresentAndNotRenamed());
     MethodSubject mainMethod = mainSubject.mainMethod();
     assertThat(mainMethod, isPresentAndNotRenamed());
diff --git a/src/test/java/com/android/tools/r8/naming/b123068484/FieldRenamingTest.java b/src/test/java/com/android/tools/r8/naming/b123068484/FieldRenamingTest.java
index 48ae678..dae9881 100644
--- a/src/test/java/com/android/tools/r8/naming/b123068484/FieldRenamingTest.java
+++ b/src/test/java/com/android/tools/r8/naming/b123068484/FieldRenamingTest.java
@@ -8,7 +8,10 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotEquals;
 
+import com.android.tools.r8.ProguardVersion;
 import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
 import com.android.tools.r8.ToolHelper;
 import com.android.tools.r8.naming.b123068484.data.Concrete1;
 import com.android.tools.r8.naming.b123068484.runner.Runner;
@@ -25,6 +28,8 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
 
 @RunWith(Parameterized.class)
 public class FieldRenamingTest extends TestBase {
@@ -33,15 +38,12 @@
   private static List<Path> CLASSES;
   private static final String EXPECTED_OUTPUT = StringUtils.lines("Runner");
 
-  private final Backend backend;
+  @Parameter(0)
+  public TestParameters parameters;
 
-  @Parameterized.Parameters(name = "Backend: {0}")
-  public static Object[] data() {
-    return ToolHelper.getBackends();
-  }
-
-  public FieldRenamingTest(Backend backend) {
-    this.backend = backend;
+  @Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withAllRuntimesAndApiLevels().build();
   }
 
   @BeforeClass
@@ -54,22 +56,24 @@
 
   @Test
   public void testProguard() throws Exception {
+    parameters.assumeCfRuntime();
     Path inJar = temp.newFile("input.jar").toPath().toAbsolutePath();
     writeClassFilesToJar(inJar, CLASSES);
-    testForProguard()
+    testForProguard(ProguardVersion.V6_0_1)
         .addProgramFiles(inJar)
         .addKeepMainRule(MAIN)
-        .run(MAIN)
+        .run(parameters.getRuntime(), MAIN)
         .assertSuccessWithOutput(EXPECTED_OUTPUT)
         .inspect(this::inspect);
   }
 
   @Test
   public void testR8() throws Exception {
-    testForR8(backend)
+    testForR8(parameters.getBackend())
         .addProgramFiles(CLASSES)
         .addKeepMainRule(MAIN)
-        .run(MAIN)
+        .setMinApi(parameters)
+        .run(parameters.getRuntime(), MAIN)
         .assertSuccessWithOutput(EXPECTED_OUTPUT)
         .inspect(this::inspect);
   }
diff --git a/src/test/java/com/android/tools/r8/naming/b126592786/B126592786.java b/src/test/java/com/android/tools/r8/naming/b126592786/B126592786.java
index 3e4d30f..ce1faf5 100644
--- a/src/test/java/com/android/tools/r8/naming/b126592786/B126592786.java
+++ b/src/test/java/com/android/tools/r8/naming/b126592786/B126592786.java
@@ -10,7 +10,7 @@
 import static org.junit.Assert.assertEquals;
 
 import com.android.tools.r8.TestBase;
-import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.utils.BooleanUtils;
 import com.android.tools.r8.utils.codeinspector.ClassSubject;
 import com.android.tools.r8.utils.codeinspector.FieldSubject;
@@ -18,31 +18,30 @@
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.lang.annotation.Target;
-import java.util.Collection;
 import java.util.List;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
 
 @RunWith(Parameterized.class)
 public class B126592786 extends TestBase {
 
-  private final Backend backend;
-  private final boolean minify;
+  @Parameter(0)
+  public TestParameters parameters;
 
-  @Parameterized.Parameters(name = "Backend: {0} minify: {1}")
-  public static Collection<Object[]> data() {
-    return buildParameters(ToolHelper.getBackends(), BooleanUtils.values());
-  }
+  @Parameter(1)
+  public boolean minify;
 
-  public B126592786(Backend backend, boolean minify) {
-    this.backend = backend;
-    this.minify = minify;
+  @Parameterized.Parameters(name = "{0}, minify: {1}")
+  public static List<Object[]> data() {
+    return buildParameters(
+        getTestParameters().withAllRuntimesAndApiLevels().build(), BooleanUtils.values());
   }
 
   public void runTest(boolean genericTypeLive) throws Exception {
     Class<?> mainClass = genericTypeLive ? MainGenericTypeLive.class : MainGenericTypeNotLive.class;
-    testForR8(backend)
+    testForR8(parameters.getBackend())
         .minification(minify)
         .addProgramClasses(GetClassUtil.class, A.class, GenericType.class, mainClass, Marker.class)
         .addKeepMainRule(mainClass)
@@ -54,6 +53,7 @@
             "  <fields>;",
             "}",
             "-keepattributes InnerClasses,EnclosingMethod,Signature ")
+        .setMinApi(parameters)
         .compile()
         .inspect(
             inspector -> {
@@ -68,7 +68,7 @@
               assertThat(list, isPresent());
               assertEquals(expectedSignature, list.getFinalSignatureAttribute());
             })
-        .run(mainClass)
+        .run(parameters.getRuntime(), mainClass)
         .assertSuccess();
   }
 
diff --git a/src/test/java/com/android/tools/r8/naming/overloadaggressively/OverloadAggressivelyTest.java b/src/test/java/com/android/tools/r8/naming/overloadaggressively/OverloadAggressivelyTest.java
index 46e691f..56eae04 100644
--- a/src/test/java/com/android/tools/r8/naming/overloadaggressively/OverloadAggressivelyTest.java
+++ b/src/test/java/com/android/tools/r8/naming/overloadaggressively/OverloadAggressivelyTest.java
@@ -7,7 +7,6 @@
 import static org.junit.Assert.assertNotEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
-import static org.junit.Assume.assumeTrue;
 
 import com.android.tools.r8.R8Command;
 import com.android.tools.r8.TestBase;
@@ -170,7 +169,10 @@
     String expectedOverloadAggressively = StringUtils.lines("diff: 0", "d8 v.s. 8", "r8 v.s. 8");
 
     if (parameters.isCfRuntime()) {
-      testForJvm().addTestClasspath().run(MethodResolution.class).assertSuccessWithOutput(expected);
+      testForJvm(parameters)
+          .addTestClasspath()
+          .run(MethodResolution.class)
+          .assertSuccessWithOutput(expected);
     }
 
     testForR8Compat(parameters.getBackend())
diff --git a/src/test/java/com/android/tools/r8/naming/overloadaggressively/ValidNameConflictTest.java b/src/test/java/com/android/tools/r8/naming/overloadaggressively/ValidNameConflictTest.java
index bec7505..6a18bd6 100644
--- a/src/test/java/com/android/tools/r8/naming/overloadaggressively/ValidNameConflictTest.java
+++ b/src/test/java/com/android/tools/r8/naming/overloadaggressively/ValidNameConflictTest.java
@@ -8,40 +8,40 @@
 import static org.junit.Assert.assertNotEquals;
 import static org.junit.Assert.assertTrue;
 
-import com.android.tools.r8.ToolHelper;
-import com.android.tools.r8.ToolHelper.ProcessResult;
+import com.android.tools.r8.R8TestRunResult;
+import com.android.tools.r8.TestCompileResult;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
 import com.android.tools.r8.jasmin.JasminBuilder;
 import com.android.tools.r8.jasmin.JasminBuilder.ClassBuilder;
 import com.android.tools.r8.jasmin.JasminTestBase;
-import com.android.tools.r8.utils.AndroidApp;
-import com.android.tools.r8.utils.StringUtils;
+import com.android.tools.r8.utils.ListUtils;
 import com.android.tools.r8.utils.codeinspector.ClassSubject;
 import com.android.tools.r8.utils.codeinspector.CodeInspector;
 import com.android.tools.r8.utils.codeinspector.FieldSubject;
 import com.android.tools.r8.utils.codeinspector.MethodSubject;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Iterables;
-import java.io.IOException;
-import java.util.Collections;
-import java.util.HashSet;
 import java.util.List;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
 
 @RunWith(Parameterized.class)
 public class ValidNameConflictTest extends JasminTestBase {
+
+  private static final List<String> EXPECTED_OUTPUT =
+      ImmutableList.of("null", "Expected to be seen at the end.");
   private static final String REPEATED_NAME = "hopeTheresNoSuchNameInRuntimeLibraries";
 
-  private final Backend backend;
+  @Parameter(0)
+  public TestParameters parameters;
 
-  @Parameterized.Parameters(name = "Backend: {0}")
-  public static Backend[] data() {
-    return ToolHelper.getBackends();
-  }
-
-  public ValidNameConflictTest(Backend backend) {
-    this.backend = backend;
+  @Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withAllRuntimesAndApiLevels().build();
   }
 
   private final String CLASS_NAME = "Example";
@@ -79,7 +79,7 @@
         "  return"));
   }
 
-  private JasminBuilder buildFieldNameConflictClassFile() {
+  private List<byte[]> buildFieldNameConflictClassFile() throws Exception {
     JasminBuilder builder = new JasminBuilder();
     ClassBuilder classBuilder = builder.addClass(CLASS_NAME);
     classBuilder.addStaticField(REPEATED_NAME, "Ljava/lang/Object;", null);
@@ -95,34 +95,34 @@
                 "  aconst_null",
                 "  invokevirtual"
                     + " java/lang/reflect/Field/get(Ljava/lang/Object;)Ljava/lang/Object;")));
-    return builder;
-  }
-
-  private ProcessResult runRaw(AndroidApp app, String main) throws IOException {
-    if (backend == Backend.DEX) {
-      return runOnArtRaw(app, main);
-    } else {
-      assert backend == Backend.CF;
-      return runOnJavaRawNoVerify(app, main, Collections.emptyList());
-    }
+    return builder.buildClasses();
   }
 
   @Test
   public void remainFieldNameConflict_keepRules() throws Exception {
-    JasminBuilder builder = buildFieldNameConflictClassFile();
-    ProcessResult javaOutput = runOnJavaNoVerifyRaw(builder, CLASS_NAME);
-    assertEquals(0, javaOutput.exitCode);
+    List<byte[]> programClassFileData = buildFieldNameConflictClassFile();
 
-    List<String> pgConfigs = ImmutableList.of(
-        "-keep public class " + CLASS_NAME + " {\n"
-            + "  public static void main(java.lang.String[]);\n"
-            + "  static <fields>;"
-            + "}\n"
-            + "-printmapping\n",
-        "-dontshrink");
-    AndroidApp app = compileWithR8(builder, pgConfigs, null, backend);
+    if (parameters.isCfRuntime()) {
+      testForJvm(parameters)
+          .addProgramClassFileData(programClassFileData)
+          .noVerify()
+          .run(parameters.getRuntime(), CLASS_NAME)
+          .assertSuccessWithOutputLines(EXPECTED_OUTPUT);
+    }
 
-    CodeInspector codeInspector = new CodeInspector(app);
+    R8TestRunResult runResult =
+        testForR8(parameters.getBackend())
+            .addProgramClassFileData(programClassFileData)
+            .addKeepMainRule(CLASS_NAME)
+            .addKeepRules("-keep class " + CLASS_NAME + " { static <fields>; }")
+            .addDontShrink()
+            .setMinApi(parameters)
+            .compile()
+            .applyIf(parameters.isCfRuntime(), TestCompileResult::noVerify)
+            .run(parameters.getRuntime(), CLASS_NAME)
+            .assertSuccessWithOutputLines(EXPECTED_OUTPUT);
+
+    CodeInspector codeInspector = runResult.inspector();
     ClassSubject clazz = codeInspector.clazz(CLASS_NAME);
     assertTrue(clazz.isPresent());
     FieldSubject f1 = clazz.field("java.lang.String", REPEATED_NAME);
@@ -132,24 +132,32 @@
     assertTrue(f2.isPresent());
     assertFalse(f2.isRenamed());
     assertEquals(f1.getFinalName(), f2.getFinalName());
-
-    ProcessResult output = runRaw(app, CLASS_NAME);
-    assertEquals(0, output.exitCode);
-    assertEquals(javaOutput.stdout, output.stdout);
   }
 
   @Test
   public void resolveFieldNameConflict_no_options() throws Exception {
-    JasminBuilder builder = buildFieldNameConflictClassFile();
-    ProcessResult javaOutput = runOnJavaNoVerifyRaw(builder, CLASS_NAME);
-    assertEquals(0, javaOutput.exitCode);
+    List<byte[]> programClassFileData = buildFieldNameConflictClassFile();
 
-    List<String> pgConfigs = ImmutableList.of(
-        keepMainProguardConfiguration(CLASS_NAME),
-        "-dontshrink");
-    AndroidApp app = compileWithR8(builder, pgConfigs, null, backend);
+    if (parameters.isCfRuntime()) {
+      testForJvm(parameters)
+          .addProgramClassFileData(programClassFileData)
+          .noVerify()
+          .run(parameters.getRuntime(), CLASS_NAME)
+          .assertSuccessWithOutputLines(EXPECTED_OUTPUT);
+    }
 
-    CodeInspector codeInspector = new CodeInspector(app);
+    R8TestRunResult runResult =
+        testForR8(parameters.getBackend())
+            .addProgramClassFileData(programClassFileData)
+            .addKeepMainRule(CLASS_NAME)
+            .addDontShrink()
+            .setMinApi(parameters)
+            .compile()
+            .applyIf(parameters.isCfRuntime(), TestCompileResult::noVerify)
+            .run(parameters.getRuntime(), CLASS_NAME)
+            .assertSuccessWithOutputLines(EXPECTED_OUTPUT);
+
+    CodeInspector codeInspector = runResult.inspector();
     ClassSubject clazz = codeInspector.clazz(CLASS_NAME);
     assertTrue(clazz.isPresent());
     FieldSubject f1 = clazz.field("java.lang.String", REPEATED_NAME);
@@ -159,13 +167,9 @@
     assertTrue(f2.isPresent());
     assertTrue(f2.isRenamed());
     assertNotEquals(f1.getFinalName(), f2.getFinalName());
-
-    ProcessResult output = runRaw(app, CLASS_NAME);
-    assertEquals(0, output.exitCode);
-    assertEquals(javaOutput.stdout, output.stdout);
   }
 
-  private JasminBuilder buildMethodNameConflictClassFile() {
+  private List<byte[]> buildMethodNameConflictClassFile() throws Exception {
     JasminBuilder builder = new JasminBuilder();
     ClassBuilder classBuilder = builder.addClass(ANOTHER_CLASS);
     classBuilder.addStaticMethod(
@@ -176,7 +180,7 @@
     classBuilder.addMainMethod(
         buildCodeForVisitingDeclaredMembers(
             ImmutableList.of(
-                ".limit stack 3",
+                ".limit stack 4",
                 ".limit locals 4",
                 "  ldc " + ANOTHER_CLASS,
                 "  invokevirtual java/lang/Class/getDeclaredMethods()[Ljava/lang/reflect/Method;"),
@@ -186,24 +190,34 @@
                 "  checkcast [Ljava/lang/Object;",
                 "  invokevirtual java/lang/reflect/Method/invoke"
                     + "(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;")));
-    return builder;
+    return builder.buildClasses();
   }
 
   @Test
   public void remainMethodNameConflict_keepRules() throws Exception {
-    JasminBuilder builder = buildMethodNameConflictClassFile();
-    ProcessResult javaOutput = runOnJavaNoVerifyRaw(builder, CLASS_NAME);
-    assertEquals(0, javaOutput.exitCode);
+    List<byte[]> programClassFileData = buildMethodNameConflictClassFile();
 
-    List<String> pgConfigs = ImmutableList.of(
-        "-keep class " + ANOTHER_CLASS + " {\n"
-            + "  static <methods>;"
-            + "}\n",
-        keepMainProguardConfiguration(CLASS_NAME),
-        "-dontshrink");
-    AndroidApp app = compileWithR8(builder, pgConfigs, null, backend);
+    if (parameters.isCfRuntime()) {
+      testForJvm(parameters)
+          .addProgramClassFileData(programClassFileData)
+          .noVerify()
+          .run(parameters.getRuntime(), CLASS_NAME)
+          .assertSuccessWithOutputLines(EXPECTED_OUTPUT);
+    }
 
-    CodeInspector codeInspector = new CodeInspector(app);
+    R8TestRunResult runResult =
+        testForR8(parameters.getBackend())
+            .addProgramClassFileData(programClassFileData)
+            .addKeepMainRule(CLASS_NAME)
+            .addKeepRules("-keep class " + ANOTHER_CLASS + " { static <methods>; }")
+            .addDontShrink()
+            .setMinApi(parameters)
+            .compile()
+            .applyIf(parameters.isCfRuntime(), TestCompileResult::noVerify)
+            .run(parameters.getRuntime(), CLASS_NAME)
+            .assertSuccessWithOutputLines(EXPECTED_OUTPUT);
+
+    CodeInspector codeInspector = runResult.inspector();
     ClassSubject clazz = codeInspector.clazz(ANOTHER_CLASS);
     assertTrue(clazz.isPresent());
     MethodSubject m1 = clazz.method("java.lang.String", REPEATED_NAME, ImmutableList.of());
@@ -213,24 +227,35 @@
     assertTrue(m2.isPresent());
     assertFalse(m2.isRenamed());
     assertEquals(m1.getFinalName(), m2.getFinalName());
-
-    ProcessResult output = runRaw(app, CLASS_NAME);
-    assertEquals(0, output.exitCode);
-    assertEquals(javaOutput.stdout, output.stdout);
   }
 
   @Test
   public void resolveMethodNameConflict_no_options() throws Exception {
-    JasminBuilder builder = buildMethodNameConflictClassFile();
-    ProcessResult javaOutput = runOnJavaNoVerifyRaw(builder, CLASS_NAME);
-    assertEquals(0, javaOutput.exitCode);
+    List<byte[]> programClassFileData = buildMethodNameConflictClassFile();
 
-    List<String> pgConfigs = ImmutableList.of(
-        keepMainProguardConfiguration(CLASS_NAME),
-        "-dontshrink");
-    AndroidApp app = compileWithR8(builder, pgConfigs, null, backend);
+    if (parameters.isCfRuntime()) {
+      testForJvm(parameters)
+          .addProgramClassFileData(programClassFileData)
+          .noVerify()
+          .run(parameters.getRuntime(), CLASS_NAME)
+          .assertSuccessWithOutputLines(EXPECTED_OUTPUT);
+    }
 
-    CodeInspector codeInspector = new CodeInspector(app);
+    R8TestRunResult runResult =
+        testForR8(parameters.getBackend())
+            .addProgramClassFileData(programClassFileData)
+            .addKeepMainRule(CLASS_NAME)
+            .addDontShrink()
+            .setMinApi(parameters)
+            .compile()
+            .applyIf(parameters.isCfRuntime(), TestCompileResult::noVerify)
+            .run(parameters.getRuntime(), CLASS_NAME)
+            .applyIf(
+                parameters.isCfRuntime(),
+                r -> r.assertSuccessWithOutputLines(ListUtils.reverse(EXPECTED_OUTPUT)),
+                r -> r.assertSuccessWithOutputLines(EXPECTED_OUTPUT));
+
+    CodeInspector codeInspector = runResult.inspector();
     ClassSubject clazz = codeInspector.clazz(ANOTHER_CLASS);
     assertTrue(clazz.isPresent());
     MethodSubject m1 = clazz.method("java.lang.String", REPEATED_NAME, ImmutableList.of());
@@ -240,16 +265,9 @@
     assertTrue(m2.isPresent());
     assertTrue(m2.isRenamed());
     assertNotEquals(m1.getFinalName(), m2.getFinalName());
-
-    ProcessResult output = runRaw(app, CLASS_NAME);
-    assertEquals(0, output.exitCode);
-    assertEquals(
-        new HashSet<>(StringUtils.splitLines(javaOutput.stdout)),
-        new HashSet<>(StringUtils.splitLines(output.stdout)));
   }
 
-
-  private JasminBuilder buildMethodNameConflictInHierarchy() {
+  private List<byte[]> buildMethodNameConflictInHierarchy() throws Exception {
     JasminBuilder builder = new JasminBuilder();
     ClassBuilder classBuilder = builder.addClass(SUPER_CLASS);
     classBuilder.addVirtualMethod(
@@ -275,7 +293,7 @@
     classBuilder.addMainMethod(
         buildCodeForVisitingDeclaredMembers(
             ImmutableList.of(
-                ".limit stack 3",
+                ".limit stack 4",
                 ".limit locals 5",
                 "  new " + ANOTHER_CLASS,
                 "  dup",
@@ -284,29 +302,39 @@
                 "  ldc " + ANOTHER_CLASS,
                 "  invokevirtual java/lang/Class/getDeclaredMethods()[Ljava/lang/reflect/Method;"),
             ImmutableList.of(
-                "  aload 4",  // instance
+                "  aload 4", // instance
                 "  aconst_null",
                 "  checkcast [Ljava/lang/Object;",
                 "  invokevirtual java/lang/reflect/Method/invoke"
                     + "(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;")));
-    return builder;
+    return builder.buildClasses();
   }
 
   @Test
   public void remainMethodNameConflictInHierarchy_keepRules() throws Exception {
-    JasminBuilder builder = buildMethodNameConflictInHierarchy();
-    ProcessResult javaOutput = runOnJavaNoVerifyRaw(builder, CLASS_NAME);
-    assertEquals(0, javaOutput.exitCode);
+    List<byte[]> programClassFileData = buildMethodNameConflictInHierarchy();
 
-    List<String> pgConfigs = ImmutableList.of(
-        "-keep class " + ANOTHER_CLASS + " {\n"
-            + "  <methods>;"
-            + "}\n",
-        keepMainProguardConfiguration(CLASS_NAME),
-        "-dontshrink");
-    AndroidApp app = compileWithR8(builder, pgConfigs, null, backend);
+    if (parameters.isCfRuntime()) {
+      testForJvm(parameters)
+          .addProgramClassFileData(programClassFileData)
+          .noVerify()
+          .run(parameters.getRuntime(), CLASS_NAME)
+          .assertSuccessWithOutputLines(EXPECTED_OUTPUT);
+    }
 
-    CodeInspector codeInspector = new CodeInspector(app);
+    R8TestRunResult runResult =
+        testForR8(parameters.getBackend())
+            .addProgramClassFileData(programClassFileData)
+            .addKeepMainRule(CLASS_NAME)
+            .addKeepClassAndMembersRules(ANOTHER_CLASS)
+            .addDontShrink()
+            .setMinApi(parameters)
+            .compile()
+            .applyIf(parameters.isCfRuntime(), TestCompileResult::noVerify)
+            .run(parameters.getRuntime(), CLASS_NAME)
+            .assertSuccessWithOutputLines(EXPECTED_OUTPUT);
+
+    CodeInspector codeInspector = runResult.inspector();
     ClassSubject sup = codeInspector.clazz(SUPER_CLASS);
     assertTrue(sup.isPresent());
     MethodSubject m1 = sup.method("java.lang.String", REPEATED_NAME, ImmutableList.of());
@@ -330,24 +358,35 @@
     // No matter what, overloading methods should be renamed to the same name.
     assertEquals(m1.getFinalName(), subM1.getFinalName());
     assertEquals(m2.getFinalName(), subM2.getFinalName());
-
-    ProcessResult output = runRaw(app, CLASS_NAME);
-    assertEquals(0, output.exitCode);
-    assertEquals(javaOutput.stdout, output.stdout);
   }
 
   @Test
   public void resolveMethodNameConflictInHierarchy_no_options() throws Exception {
-    JasminBuilder builder = buildMethodNameConflictInHierarchy();
-    ProcessResult javaOutput = runOnJavaNoVerifyRaw(builder, CLASS_NAME);
-    assertEquals(0, javaOutput.exitCode);
+    List<byte[]> programClassFileData = buildMethodNameConflictInHierarchy();
 
-    List<String> pgConfigs = ImmutableList.of(
-        keepMainProguardConfiguration(CLASS_NAME),
-        "-dontshrink");
-    AndroidApp app = compileWithR8(builder, pgConfigs, null, backend);
+    if (parameters.isCfRuntime()) {
+      testForJvm(parameters)
+          .addProgramClassFileData(programClassFileData)
+          .noVerify()
+          .run(parameters.getRuntime(), CLASS_NAME)
+          .assertSuccessWithOutputLines(EXPECTED_OUTPUT);
+    }
 
-    CodeInspector codeInspector = new CodeInspector(app);
+    R8TestRunResult runResult =
+        testForR8(parameters.getBackend())
+            .addProgramClassFileData(programClassFileData)
+            .addKeepMainRule(CLASS_NAME)
+            .addDontShrink()
+            .setMinApi(parameters)
+            .compile()
+            .applyIf(parameters.isCfRuntime(), TestCompileResult::noVerify)
+            .run(parameters.getRuntime(), CLASS_NAME)
+            .applyIf(
+                parameters.isCfRuntime(),
+                r -> r.assertSuccessWithOutputLines(ListUtils.reverse(EXPECTED_OUTPUT)),
+                r -> r.assertSuccessWithOutputLines(EXPECTED_OUTPUT));
+
+    CodeInspector codeInspector = runResult.inspector();
     ClassSubject sup = codeInspector.clazz(SUPER_CLASS);
     assertTrue(sup.isPresent());
     MethodSubject m1 = sup.method("java.lang.String", REPEATED_NAME, ImmutableList.of());
@@ -371,11 +410,5 @@
     // No matter what, overloading methods should be renamed to the same name.
     assertEquals(m1.getFinalName(), subM1.getFinalName());
     assertEquals(m2.getFinalName(), subM2.getFinalName());
-
-    ProcessResult output = runRaw(app, CLASS_NAME);
-    assertEquals(0, output.exitCode);
-    assertEquals(
-        new HashSet<>(StringUtils.splitLines(javaOutput.stdout)),
-        new HashSet<>(StringUtils.splitLines(output.stdout)));
   }
 }
diff --git a/src/test/java/com/android/tools/r8/naming/retrace/DesugarLambdaRetraceTest.java b/src/test/java/com/android/tools/r8/naming/retrace/DesugarLambdaRetraceTest.java
index 59bc15d..5787486 100644
--- a/src/test/java/com/android/tools/r8/naming/retrace/DesugarLambdaRetraceTest.java
+++ b/src/test/java/com/android/tools/r8/naming/retrace/DesugarLambdaRetraceTest.java
@@ -57,21 +57,21 @@
 
   private void checkIsSame(StackTrace actualStackTrace, StackTrace retracedStackTrace) {
     // Even when SourceFile is present retrace replaces the file name in the stack trace.
-    assertThat(retracedStackTrace, isSame(expectedStackTrace));
+    assertThat(retracedStackTrace, isSame(getExpectedStackTrace()));
     assertEquals(expectedActualStackTraceHeight(), actualStackTrace.getStackTraceLines().size());
   }
 
   private void checkIsSameExceptForFileName(
       StackTrace actualStackTrace, StackTrace retracedStackTrace) {
     // Even when SourceFile is present retrace replaces the file name in the stack trace.
-    assertThat(retracedStackTrace, isSameExceptForFileName(expectedStackTrace));
+    assertThat(retracedStackTrace, isSameExceptForFileName(getExpectedStackTrace()));
     assertEquals(expectedActualStackTraceHeight(), actualStackTrace.getStackTraceLines().size());
   }
 
   private void checkIsSameExceptForFileNameAndLineNumber(
       StackTrace actualStackTrace, StackTrace retracedStackTrace) {
     // Even when SourceFile is present retrace replaces the file name in the stack trace.
-    assertThat(retracedStackTrace, isSameExceptForFileNameAndLineNumber(expectedStackTrace));
+    assertThat(retracedStackTrace, isSameExceptForFileNameAndLineNumber(getExpectedStackTrace()));
     assertEquals(expectedActualStackTraceHeight(), actualStackTrace.getStackTraceLines().size());
   }
 
diff --git a/src/test/java/com/android/tools/r8/naming/retrace/DesugarPrivateLambdaRetraceTest.java b/src/test/java/com/android/tools/r8/naming/retrace/DesugarPrivateLambdaRetraceTest.java
index e21927b..4cccd71 100644
--- a/src/test/java/com/android/tools/r8/naming/retrace/DesugarPrivateLambdaRetraceTest.java
+++ b/src/test/java/com/android/tools/r8/naming/retrace/DesugarPrivateLambdaRetraceTest.java
@@ -6,7 +6,6 @@
 
 import static com.android.tools.r8.naming.retrace.StackTrace.isSame;
 import static org.hamcrest.MatcherAssert.assertThat;
-import static org.junit.Assume.assumeTrue;
 
 import com.android.tools.r8.CompilationMode;
 import com.android.tools.r8.TestBase;
@@ -68,8 +67,8 @@
 
   @Test
   public void testJvm() throws Exception {
-    assumeTrue(parameters.isCfRuntime());
-    testForJvm()
+    parameters.assumeJvmTestParameters();
+    testForJvm(parameters)
         .addInnerClasses(DesugarInterfaceInstanceLambdaRetrace.class)
         .run(TestRuntime.getDefaultCfRuntime(), DesugarInterfaceInstanceLambdaRetrace.Main.class)
         .inspectStackTrace(stackTrace -> assertThat(stackTrace, isSame(expectedStackTrace)));
diff --git a/src/test/java/com/android/tools/r8/naming/retrace/DesugarStaticInterfaceMethodDirectRetraceTest.java b/src/test/java/com/android/tools/r8/naming/retrace/DesugarStaticInterfaceMethodDirectRetraceTest.java
index 2cbb911..2439b3b 100644
--- a/src/test/java/com/android/tools/r8/naming/retrace/DesugarStaticInterfaceMethodDirectRetraceTest.java
+++ b/src/test/java/com/android/tools/r8/naming/retrace/DesugarStaticInterfaceMethodDirectRetraceTest.java
@@ -55,7 +55,7 @@
     runTest(
         ImmutableList.of("-keepattributes SourceFile,LineNumberTable"),
         (StackTrace actualStackTrace, StackTrace retracedStackTrace) ->
-            assertThat(retracedStackTrace, isSameExceptForFileName(expectedStackTrace)));
+            assertThat(retracedStackTrace, isSameExceptForFileName(getExpectedStackTrace())));
   }
 }
 
diff --git a/src/test/java/com/android/tools/r8/naming/retrace/InliningRetraceTest.java b/src/test/java/com/android/tools/r8/naming/retrace/InliningRetraceTest.java
index c3a07cd..ef6f5a7 100644
--- a/src/test/java/com/android/tools/r8/naming/retrace/InliningRetraceTest.java
+++ b/src/test/java/com/android/tools/r8/naming/retrace/InliningRetraceTest.java
@@ -51,7 +51,7 @@
     runTest(
         ImmutableList.of("-keepattributes SourceFile,LineNumberTable"),
         (StackTrace actualStackTrace, StackTrace retracedStackTrace) -> {
-          assertThat(retracedStackTrace, isSame(expectedStackTrace));
+          assertThat(retracedStackTrace, isSame(getExpectedStackTrace()));
           assertEquals(
               expectedActualStackTraceHeight(), actualStackTrace.getStackTraceLines().size());
         });
@@ -64,7 +64,7 @@
     runTest(
         ImmutableList.of("-keepattributes LineNumberTable"),
         (StackTrace actualStackTrace, StackTrace retracedStackTrace) -> {
-          assertThat(retracedStackTrace, isSameExceptForFileName(expectedStackTrace));
+          assertThat(retracedStackTrace, isSameExceptForFileName(getExpectedStackTrace()));
           assertEquals(
               expectedActualStackTraceHeight(), actualStackTrace.getStackTraceLines().size());
         });
@@ -77,7 +77,8 @@
     runTest(
         ImmutableList.of(),
         (StackTrace actualStackTrace, StackTrace retracedStackTrace) -> {
-          assertThat(retracedStackTrace, isSameExceptForFileNameAndLineNumber(expectedStackTrace));
+          assertThat(
+              retracedStackTrace, isSameExceptForFileNameAndLineNumber(getExpectedStackTrace()));
           assertEquals(
               expectedActualStackTraceHeight(), actualStackTrace.getStackTraceLines().size());
         });
diff --git a/src/test/java/com/android/tools/r8/naming/retrace/RetraceTestBase.java b/src/test/java/com/android/tools/r8/naming/retrace/RetraceTestBase.java
index 94117c5..21ea804 100644
--- a/src/test/java/com/android/tools/r8/naming/retrace/RetraceTestBase.java
+++ b/src/test/java/com/android/tools/r8/naming/retrace/RetraceTestBase.java
@@ -15,7 +15,7 @@
 import java.util.Collection;
 import java.util.List;
 import java.util.function.BiConsumer;
-import org.junit.Before;
+import java.util.function.Function;
 
 public abstract class RetraceTestBase extends TestBase {
   protected TestParameters parameters;
@@ -28,7 +28,14 @@
     this.compat = compat;
   }
 
-  public StackTrace expectedStackTrace;
+  private static Function<Class<?>, StackTrace> expectedStackTrace =
+      memoizeFunction(
+          mainClass ->
+              testForJvm(getStaticTemp())
+                  .addTestClasspath()
+                  .run(CfRuntime.getSystemRuntime(), mainClass)
+                  .assertFailure()
+                  .map(StackTrace::extractFromJvm));
 
   public void configure(R8TestBuilder<?> builder) {}
 
@@ -38,24 +45,17 @@
     return ImmutableList.of(getMainClass());
   }
 
-  public abstract Class<?> getMainClass();
-
-  @Before
-  public void setup() throws Exception {
-    // Get the expected stack trace by running on the JVM.
-    expectedStackTrace =
-        testForJvm()
-            .addTestClasspath()
-            .run(CfRuntime.getSystemRuntime(), getMainClass())
-            .assertFailure()
-            .map(StackTrace::extractFromJvm);
+  public StackTrace getExpectedStackTrace() {
+    return expectedStackTrace.apply(getMainClass());
   }
 
+  public abstract Class<?> getMainClass();
+
   public void runTest(List<String> keepRules, BiConsumer<StackTrace, StackTrace> checker)
       throws Exception {
 
     R8TestRunResult result =
-        (compat ? testForR8Compat(parameters.getBackend()) : testForR8(parameters.getBackend()))
+        testForR8Compat(parameters.getBackend(), compat)
             .setMode(mode)
             .addProgramClasses(getClasses())
             .addKeepMainRule(getMainClass())
diff --git a/src/test/java/com/android/tools/r8/naming/retrace/VerticalClassMergingRetraceTest.java b/src/test/java/com/android/tools/r8/naming/retrace/VerticalClassMergingRetraceTest.java
index 5b4dcb2..9d261da 100644
--- a/src/test/java/com/android/tools/r8/naming/retrace/VerticalClassMergingRetraceTest.java
+++ b/src/test/java/com/android/tools/r8/naming/retrace/VerticalClassMergingRetraceTest.java
@@ -76,7 +76,7 @@
               mode == CompilationMode.DEBUG
                   ? retracedStackTrace
                   : retracedStackTrace.filter(this::filterSynthesizedMethodWhenLineNumberAvailable);
-          assertThat(reprocessedStackTrace, isSameExceptForFileName(expectedStackTrace));
+          assertThat(reprocessedStackTrace, isSameExceptForFileName(getExpectedStackTrace()));
           assertEquals(
               expectedActualStackTraceHeight(), actualStackTrace.getStackTraceLines().size());
         });
@@ -93,7 +93,7 @@
               mode == CompilationMode.DEBUG
                   ? retracedStackTrace
                   : retracedStackTrace.filter(this::filterSynthesizedMethodWhenLineNumberAvailable);
-          assertThat(reprocessedStackTrace, isSameExceptForFileName(expectedStackTrace));
+          assertThat(reprocessedStackTrace, isSameExceptForFileName(getExpectedStackTrace()));
           assertEquals(
               expectedActualStackTraceHeight(), actualStackTrace.getStackTraceLines().size());
         });
@@ -130,7 +130,8 @@
     runTest(
         ImmutableList.of(),
         (StackTrace actualStackTrace, StackTrace retracedStackTrace) -> {
-          assertThat(retracedStackTrace, isSameExceptForFileNameAndLineNumber(expectedStackTrace));
+          assertThat(
+              retracedStackTrace, isSameExceptForFileNameAndLineNumber(getExpectedStackTrace()));
           assertEquals(
               expectedActualStackTraceHeight(), actualStackTrace.getStackTraceLines().size());
         });
diff --git a/src/test/java/com/android/tools/r8/naming/signature/GenericSignatureRenamingTest.java b/src/test/java/com/android/tools/r8/naming/signature/GenericSignatureRenamingTest.java
index 12d315f..f08c178 100644
--- a/src/test/java/com/android/tools/r8/naming/signature/GenericSignatureRenamingTest.java
+++ b/src/test/java/com/android/tools/r8/naming/signature/GenericSignatureRenamingTest.java
@@ -4,7 +4,6 @@
 
 package com.android.tools.r8.naming.signature;
 
-import static org.junit.Assume.assumeTrue;
 
 import com.android.tools.r8.CompilationMode;
 import com.android.tools.r8.R8TestBuilder;
@@ -36,13 +35,16 @@
 
   @Test
   public void testJVM() throws Exception {
-    assumeTrue(parameters.isCfRuntime());
-    testForJvm().addTestClasspath().run(parameters.getRuntime(), Main.class).assertSuccess();
+    parameters.assumeJvmTestParameters();
+    testForJvm(parameters)
+        .addTestClasspath()
+        .run(parameters.getRuntime(), Main.class)
+        .assertSuccess();
   }
 
   @Test
   public void testD8() throws Exception {
-    assumeTrue(parameters.isDexRuntime());
+    parameters.assumeDexRuntime();
     testForD8()
         .addProgramClasses(Main.class)
         .addProgramClassesAndInnerClasses(A.class, B.class, CY.class, CYY.class)
diff --git a/src/test/java/com/android/tools/r8/naming/sourcefile/MapIdTemplateTest.java b/src/test/java/com/android/tools/r8/naming/sourcefile/MapIdTemplateTest.java
index 7da7b54..dc4970a 100644
--- a/src/test/java/com/android/tools/r8/naming/sourcefile/MapIdTemplateTest.java
+++ b/src/test/java/com/android/tools/r8/naming/sourcefile/MapIdTemplateTest.java
@@ -11,37 +11,31 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
 
-import com.android.tools.r8.ClassFileConsumer.ArchiveConsumer;
-import com.android.tools.r8.DexIndexedConsumer;
 import com.android.tools.r8.DiagnosticsHandler;
-import com.android.tools.r8.R8;
-import com.android.tools.r8.R8Command.Builder;
 import com.android.tools.r8.R8CommandParser;
+import com.android.tools.r8.R8TestCompileResult;
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestDiagnosticMessagesImpl;
 import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.TestParametersCollection;
 import com.android.tools.r8.origin.Origin;
-import java.nio.file.Path;
+import com.android.tools.r8.utils.AndroidApiLevel;
 import java.util.Arrays;
-import java.util.List;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
 
 @RunWith(Parameterized.class)
 public class MapIdTemplateTest extends TestBase {
 
-  @Parameterized.Parameters(name = "{0}, {1}")
-  public static List<Object[]> data() {
-    return buildParameters(getTestParameters().withNoneRuntime().build(), Backend.values());
-  }
+  @Parameter(0)
+  public TestParameters parameters;
 
-  private final Backend backend;
-
-  public MapIdTemplateTest(TestParameters parameters, Backend backend) {
-    parameters.assertNoneRuntime();
-    this.backend = backend;
+  @Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withDefaultRuntimes().withApiLevel(AndroidApiLevel.B).build();
   }
 
   @Test
@@ -52,6 +46,7 @@
 
   @Test
   public void testInvalidVariable() {
+    parameters.assumeIsOrSimulateNoneRuntime();
     TestDiagnosticMessagesImpl messages = new TestDiagnosticMessagesImpl();
     parseMapIdTemplate("my-%build-id", messages);
     messages
@@ -62,6 +57,7 @@
 
   @Test
   public void testInvalidVariablesMix() {
+    parameters.assumeIsOrSimulateNoneRuntime();
     TestDiagnosticMessagesImpl messages = new TestDiagnosticMessagesImpl();
     parseMapIdTemplate("my%%MAP_HASHJUNK", messages);
     messages
@@ -72,6 +68,7 @@
 
   @Test
   public void testNoEscape() {
+    parameters.assumeIsOrSimulateNoneRuntime();
     TestDiagnosticMessagesImpl messages = new TestDiagnosticMessagesImpl();
     parseMapIdTemplate("my%%buildid", messages);
     messages
@@ -99,32 +96,21 @@
   }
 
   private String compileWithMapIdTemplate(String template) throws Exception {
-    Path out = temp.newFolder().toPath().resolve("out.jar");
-    TestDiagnosticMessagesImpl messages = new TestDiagnosticMessagesImpl();
-    StringBuilder mapping = new StringBuilder();
-    R8.run(
-        parseMapIdTemplate(template, messages)
-            .addProguardConfiguration(
-                Arrays.asList("-keep class * { *; }", "-dontwarn " + typeName(TestClass.class)),
-                Origin.unknown())
-            .setProgramConsumer(
-                backend.isCf()
-                    ? new ArchiveConsumer(out)
-                    : new DexIndexedConsumer.ArchiveConsumer(out))
-            .addProgramFiles(ToolHelper.getClassFileForTestClass(TestClass.class))
-            // TODO(b/201269335): What should be the expected result when no map is created?
-            .setProguardMapConsumer((content, handler) -> mapping.append(content))
-            .build());
-    messages.assertNoMessages();
-    return getMapId(mapping.toString());
+    return getMapId(
+        testForR8(parameters.getBackend())
+            .addProgramClasses(TestClass.class)
+            .addKeepMainRule(TestClass.class)
+            .setMapIdTemplate(template)
+            .setMinApi(parameters)
+            .compile());
   }
 
-  private Builder parseMapIdTemplate(String template, DiagnosticsHandler handler) {
-    return R8CommandParser.parse(
-        new String[] {"--map-id-template", template}, Origin.unknown(), handler);
+  private void parseMapIdTemplate(String template, DiagnosticsHandler handler) {
+    R8CommandParser.parse(new String[] {"--map-id-template", template}, Origin.unknown(), handler);
   }
 
-  private String getMapId(String mapping) {
+  private String getMapId(R8TestCompileResult compileResult) {
+    String mapping = compileResult.getProguardMap();
     String lineHeader = "# pg_map_id: ";
     int i = mapping.indexOf(lineHeader);
     assertTrue(i >= 0);
diff --git a/src/test/java/com/android/tools/r8/naming/sourcefile/SourceFileTemplateTest.java b/src/test/java/com/android/tools/r8/naming/sourcefile/SourceFileTemplateTest.java
index cdff91c..ebf329d 100644
--- a/src/test/java/com/android/tools/r8/naming/sourcefile/SourceFileTemplateTest.java
+++ b/src/test/java/com/android/tools/r8/naming/sourcefile/SourceFileTemplateTest.java
@@ -10,53 +10,45 @@
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.junit.Assert.assertEquals;
 
-import com.android.tools.r8.ClassFileConsumer.ArchiveConsumer;
-import com.android.tools.r8.CompilationFailedException;
-import com.android.tools.r8.DexIndexedConsumer;
 import com.android.tools.r8.DiagnosticsHandler;
-import com.android.tools.r8.R8;
 import com.android.tools.r8.R8Command.Builder;
 import com.android.tools.r8.R8CommandParser;
-import com.android.tools.r8.StringConsumer;
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestDiagnosticMessagesImpl;
 import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.TestParametersCollection;
 import com.android.tools.r8.origin.Origin;
+import com.android.tools.r8.utils.AndroidApiLevel;
+import com.android.tools.r8.utils.ThrowingConsumer;
 import com.android.tools.r8.utils.codeinspector.CodeInspector;
-import java.io.IOException;
-import java.nio.file.Path;
 import java.util.Arrays;
-import java.util.List;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
 
 @RunWith(Parameterized.class)
 public class SourceFileTemplateTest extends TestBase {
 
-  @Parameterized.Parameters(name = "{0}, {1}")
-  public static List<Object[]> data() {
-    return buildParameters(getTestParameters().withNoneRuntime().build(), Backend.values());
-  }
+  @Parameter(0)
+  public TestParameters parameters;
 
-  private final Backend backend;
-
-  public SourceFileTemplateTest(TestParameters parameters, Backend backend) {
-    parameters.assertNoneRuntime();
-    this.backend = backend;
+  @Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withAllRuntimes().withApiLevel(AndroidApiLevel.B).build();
   }
 
   @Test
   public void testNoVariables() throws Exception {
     String template = "MySourceFile";
-    assertEquals(
+    compileWithSourceFileTemplate(
         template,
-        new CodeInspector(compileWithSourceFileTemplate(template))
-            .clazz(TestClass.class)
-            .getDexProgramClass()
-            .getSourceFile()
-            .toString());
+        inspector -> {
+          assertEquals(
+              template,
+              inspector.clazz(TestClass.class).getDexProgramClass().getSourceFile().toString());
+        });
   }
 
   @Test
@@ -96,62 +88,52 @@
   @Test
   public void testMapId() throws Exception {
     String template = "MySourceFile %MAP_ID";
-    String actual =
-        new CodeInspector(compileWithSourceFileTemplate(template))
-            .clazz(TestClass.class)
-            .getDexProgramClass()
-            .getSourceFile()
-            .toString();
-    assertThat(actual, startsWith("MySourceFile "));
-    assertThat(actual, not(containsString("%")));
-    assertEquals("MySourceFile ".length() + 7, actual.length());
+    compileWithSourceFileTemplate(
+        template,
+        inspector -> {
+          String actual =
+              inspector.clazz(TestClass.class).getDexProgramClass().getSourceFile().toString();
+          assertThat(actual, startsWith("MySourceFile "));
+          assertThat(actual, not(containsString("%")));
+          assertEquals("MySourceFile ".length() + 7, actual.length());
+        });
   }
 
   @Test
   public void testMapHash() throws Exception {
     String template = "MySourceFile %MAP_HASH";
-    String actual =
-        new CodeInspector(compileWithSourceFileTemplate(template))
-            .clazz(TestClass.class)
-            .getDexProgramClass()
-            .getSourceFile()
-            .toString();
-    assertThat(actual, startsWith("MySourceFile "));
-    assertThat(actual, not(containsString("%")));
-    assertEquals("MySourceFile ".length() + 64, actual.length());
+    compileWithSourceFileTemplate(
+        template,
+        inspector -> {
+          String actual =
+              inspector.clazz(TestClass.class).getDexProgramClass().getSourceFile().toString();
+          assertThat(actual, startsWith("MySourceFile "));
+          assertThat(actual, not(containsString("%")));
+          assertEquals("MySourceFile ".length() + 64, actual.length());
+        });
   }
 
   @Test
   public void testMultiple() throws Exception {
     String template = "id %MAP_ID hash %MAP_HASH id %MAP_ID hash %MAP_HASH";
-    String actual =
-        new CodeInspector(compileWithSourceFileTemplate(template))
-            .clazz(TestClass.class)
-            .getDexProgramClass()
-            .getSourceFile()
-            .toString();
-    assertEquals("id  hash  id  hash ".length() + 2 * 7 + 2 * 64, actual.length());
+    compileWithSourceFileTemplate(
+        template,
+        inspector -> {
+          String actual =
+              inspector.clazz(TestClass.class).getDexProgramClass().getSourceFile().toString();
+          assertEquals("id  hash  id  hash ".length() + 2 * 7 + 2 * 64, actual.length());
+        });
   }
 
-  private Path compileWithSourceFileTemplate(String template)
-      throws IOException, CompilationFailedException {
-    Path out = temp.newFolder().toPath().resolve("out.jar");
-    TestDiagnosticMessagesImpl messages = new TestDiagnosticMessagesImpl();
-    R8.run(
-        parseSourceFileTemplate(template, messages)
-            .addProguardConfiguration(
-                Arrays.asList("-keep class * { *; }", "-dontwarn " + typeName(TestClass.class)),
-                Origin.unknown())
-            .setProgramConsumer(
-                backend.isCf()
-                    ? new ArchiveConsumer(out)
-                    : new DexIndexedConsumer.ArchiveConsumer(out))
-            .addProgramFiles(ToolHelper.getClassFileForTestClass(TestClass.class))
-            // TODO(b/201269335): What should be the expected result when no map is created?
-            .setProguardMapConsumer(StringConsumer.emptyConsumer())
-            .build());
-    messages.assertNoMessages();
-    return out;
+  private <E extends Exception> void compileWithSourceFileTemplate(
+      String template, ThrowingConsumer<CodeInspector, E> inspection) throws Exception {
+    testForR8(parameters.getBackend())
+        .addProgramClasses(TestClass.class)
+        .addKeepMainRule(TestClass.class)
+        .setMinApi(parameters)
+        .setSourceFileTemplate(template)
+        .compile()
+        .inspect(inspection);
   }
 
   private Builder parseSourceFileTemplate(String template, DiagnosticsHandler handler) {
diff --git a/src/test/java/com/android/tools/r8/profile/art/completeness/ApiOutlineProfileRewritingTest.java b/src/test/java/com/android/tools/r8/profile/art/completeness/ApiOutlineProfileRewritingTest.java
index 3cbba15..584814b 100644
--- a/src/test/java/com/android/tools/r8/profile/art/completeness/ApiOutlineProfileRewritingTest.java
+++ b/src/test/java/com/android/tools/r8/profile/art/completeness/ApiOutlineProfileRewritingTest.java
@@ -62,7 +62,7 @@
     assumeTrue(parameters.isCfRuntime());
     assumeTrue(parameters.getApiLevel() == AndroidApiLevel.B);
     assertFalse(isLibraryClassPresentInCurrentRuntime());
-    testForJvm()
+    testForJvm(parameters)
         .addProgramClasses(Main.class)
         .run(parameters.getRuntime(), Main.class)
         .apply(this::inspectRunResult);
diff --git a/src/test/java/com/android/tools/r8/profile/art/completeness/InvokeSpecialToVirtualMethodProfileRewritingTest.java b/src/test/java/com/android/tools/r8/profile/art/completeness/InvokeSpecialToVirtualMethodProfileRewritingTest.java
index 8bf0b7a..1f7da5f 100644
--- a/src/test/java/com/android/tools/r8/profile/art/completeness/InvokeSpecialToVirtualMethodProfileRewritingTest.java
+++ b/src/test/java/com/android/tools/r8/profile/art/completeness/InvokeSpecialToVirtualMethodProfileRewritingTest.java
@@ -8,7 +8,6 @@
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotEquals;
-import static org.junit.Assume.assumeTrue;
 
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
@@ -43,8 +42,8 @@
 
   @Test
   public void testJvm() throws Exception {
-    assumeTrue(parameters.isCfRuntime());
-    testForJvm()
+    parameters.assumeJvmTestParameters();
+    testForJvm(parameters)
         .addProgramClassFileData(getTransformedMain())
         .run(parameters.getRuntime(), Main.class)
         .assertSuccessWithOutputLines("Hello, world!", "Hello, world!");
diff --git a/src/test/java/com/android/tools/r8/profile/art/completeness/MovedPrivateInterfaceMethodProfileRewritingTest.java b/src/test/java/com/android/tools/r8/profile/art/completeness/MovedPrivateInterfaceMethodProfileRewritingTest.java
index 97d29a4..9d36b97 100644
--- a/src/test/java/com/android/tools/r8/profile/art/completeness/MovedPrivateInterfaceMethodProfileRewritingTest.java
+++ b/src/test/java/com/android/tools/r8/profile/art/completeness/MovedPrivateInterfaceMethodProfileRewritingTest.java
@@ -40,8 +40,8 @@
 
   @Test
   public void testJvm() throws Exception {
-    parameters.assumeCfRuntime();
-    testForJvm()
+    parameters.assumeJvmTestParameters();
+    testForJvm(parameters)
         .addProgramClasses(Main.class, A.class)
         .addProgramClassFileData(getTransformedInterface())
         .run(parameters.getRuntime(), Main.class)
diff --git a/src/test/java/com/android/tools/r8/profile/art/completeness/NestBasedAccessBridgesProfileRewritingTest.java b/src/test/java/com/android/tools/r8/profile/art/completeness/NestBasedAccessBridgesProfileRewritingTest.java
index 5551a32..7d9e9ab 100644
--- a/src/test/java/com/android/tools/r8/profile/art/completeness/NestBasedAccessBridgesProfileRewritingTest.java
+++ b/src/test/java/com/android/tools/r8/profile/art/completeness/NestBasedAccessBridgesProfileRewritingTest.java
@@ -46,9 +46,9 @@
 
   @Test
   public void testJvm() throws Exception {
-    assumeTrue(parameters.isCfRuntime());
+    parameters.assumeJvmTestParameters();
     assumeTrue(parameters.asCfRuntime().isNewerThanOrEqual(CfVm.JDK11));
-    testForJvm()
+    testForJvm(parameters)
         .addProgramClassFileData(getProgramClassFileData())
         .run(parameters.getRuntime(), Main.class)
         .assertSuccessWithOutputLines("1", "2", "3", "4");
diff --git a/src/test/java/com/android/tools/r8/reachabilitysensitive/ReachabilitySensitiveAndDebugLocalReads.java b/src/test/java/com/android/tools/r8/reachabilitysensitive/ReachabilitySensitiveAndDebugLocalReads.java
index ff125be..4d0d3e6 100644
--- a/src/test/java/com/android/tools/r8/reachabilitysensitive/ReachabilitySensitiveAndDebugLocalReads.java
+++ b/src/test/java/com/android/tools/r8/reachabilitysensitive/ReachabilitySensitiveAndDebugLocalReads.java
@@ -4,31 +4,60 @@
 package com.android.tools.r8.reachabilitysensitive;
 
 import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
 import com.android.tools.r8.utils.StringUtils;
+import org.junit.BeforeClass;
 import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
 import org.objectweb.asm.AnnotationVisitor;
 import org.objectweb.asm.ClassWriter;
 import org.objectweb.asm.Label;
 import org.objectweb.asm.MethodVisitor;
 import org.objectweb.asm.Opcodes;
 
+@RunWith(Parameterized.class)
 public class ReachabilitySensitiveAndDebugLocalReads extends TestBase {
 
-  @Test
-  public void test() throws Exception {
-    byte[] classdata = Dump.dump();
-    String mainClass = "test.Test";
-    String expected = StringUtils.lines("5");
-    testForJvm()
-        .addProgramClassFileData(classdata)
-        .run(mainClass)
-        .assertSuccessWithOutput(expected);
+  private static final String MAIN_CLASS = "test.Test";
+  private static final String EXPECTED = StringUtils.lines("5");
 
+  private static byte[] classData;
+
+  @Parameter(0)
+  public TestParameters parameters;
+
+  @Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withAllRuntimesAndApiLevels().build();
+  }
+
+  @BeforeClass
+  public static void setup() {
+    classData = Dump.dump();
+  }
+
+  @Test
+  public void testJvm() throws Exception {
+    parameters.assumeJvmTestParameters();
+    testForJvm(parameters)
+        .addProgramClassFileData(classData)
+        .run(parameters.getRuntime(), MAIN_CLASS)
+        .assertSuccessWithOutput(EXPECTED);
+  }
+
+  @Test
+  public void testD8() throws Exception {
+    parameters.assumeDexRuntime();
     testForD8()
         .release()
-        .addProgramClassFileData(classdata)
-        .run(mainClass)
-        .assertSuccessWithOutput(expected);
+        .addProgramClassFileData(classData)
+        .setMinApi(parameters)
+        .run(parameters.getRuntime(), MAIN_CLASS)
+        .assertSuccessWithOutput(EXPECTED);
   }
 }
 
diff --git a/src/test/java/com/android/tools/r8/regress/b118075510/Regress118075510Runner.java b/src/test/java/com/android/tools/r8/regress/b118075510/Regress118075510Runner.java
index e562b4f..2345ec3 100644
--- a/src/test/java/com/android/tools/r8/regress/b118075510/Regress118075510Runner.java
+++ b/src/test/java/com/android/tools/r8/regress/b118075510/Regress118075510Runner.java
@@ -4,45 +4,46 @@
 package com.android.tools.r8.regress.b118075510;
 
 import com.android.tools.r8.AsmTestBase;
-import com.android.tools.r8.CompilationFailedException;
-import com.android.tools.r8.CompilationMode;
 import com.android.tools.r8.D8TestCompileResult;
 import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
 import com.android.tools.r8.utils.AndroidApiLevel;
 import com.android.tools.r8.utils.StringUtils;
 import com.android.tools.r8.utils.codeinspector.CodeInspector;
 import com.android.tools.r8.utils.codeinspector.MethodSubject;
-import java.io.IOException;
-import java.util.List;
-import java.util.concurrent.ExecutionException;
 import org.junit.Assert;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
 
 @RunWith(Parameterized.class)
 public class Regress118075510Runner extends AsmTestBase {
 
-  public static final Class<?> CLASS = Regress118075510Test.class;
-  public static final String EXPECTED = StringUtils.lines("0", "0");
+  private static final Class<?> CLASS = Regress118075510Test.class;
+  private static final String EXPECTED = StringUtils.lines("0", "0");
 
-  private final TestParameters parameters;
+  @Parameter(0)
+  public TestParameters parameters;
 
-  @Parameterized.Parameters(name = "{0}, {1}")
-  public static List<Object[]> data() {
-    return buildParameters(
-        getTestParameters().withDexRuntimes().withAllApiLevels().build(), CompilationMode.values());
-  }
-
-  public Regress118075510Runner(TestParameters parameters, CompilationMode mode) {
-    this.parameters = parameters;
+  @Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withAllRuntimesAndApiLevels().build();
   }
 
   @Test
-  public void test()
-      throws CompilationFailedException, IOException, ExecutionException, NoSuchMethodException {
-    testForJvm().addTestClasspath().run(CLASS).assertSuccessWithOutput(EXPECTED);
+  public void testJvm() throws Exception {
+    parameters.assumeJvmTestParameters();
+    testForJvm(parameters)
+        .addTestClasspath()
+        .run(parameters.getRuntime(), CLASS)
+        .assertSuccessWithOutput(EXPECTED);
+  }
 
+  @Test
+  public void testD8() throws Exception {
+    parameters.assumeDexRuntime();
     D8TestCompileResult d8Result =
         testForD8().addProgramClasses(CLASS).setMinApi(AndroidApiLevel.M).release().compile();
 
diff --git a/src/test/java/com/android/tools/r8/regress/b150274427/JsrRetRegressionTest.java b/src/test/java/com/android/tools/r8/regress/b150274427/JsrRetRegressionTest.java
index 9a6c40e..cf63d5f 100644
--- a/src/test/java/com/android/tools/r8/regress/b150274427/JsrRetRegressionTest.java
+++ b/src/test/java/com/android/tools/r8/regress/b150274427/JsrRetRegressionTest.java
@@ -42,7 +42,7 @@
   @Test
   public void testReachableJsrRet() throws Exception {
     if (parameters.isCfRuntime()) {
-      testForJvm()
+      testForJvm(parameters)
           .addProgramClassFileData(getTransformClass(true))
           .run(parameters.getRuntime(), TestClass.class)
           .assertFailureWithErrorThatThrows(VerifyError.class);
diff --git a/src/test/java/com/android/tools/r8/regress/b71604169/Regress71604169.java b/src/test/java/com/android/tools/r8/regress/b71604169/Regress71604169.java
deleted file mode 100644
index 90935bd..0000000
--- a/src/test/java/com/android/tools/r8/regress/b71604169/Regress71604169.java
+++ /dev/null
@@ -1,28 +0,0 @@
-// Copyright (c) 2018, the R8 project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-package com.android.tools.r8.regress.b71604169;
-
-public class Regress71604169 {
-  public interface Creator<C> {
-    C create(Object o);
-  }
-
-  public static class X {
-    Object o;
-
-    X(Object o) {
-      this.o = o;
-      System.out.print(o);
-    }
-  }
-
-  public static <C> C create(Creator<C> creator)  {
-    return creator.create("Hello, world!");
-  }
-
-  public static void main(String[] args) {
-    create(X::new);
-  }
-}
diff --git a/src/test/java/com/android/tools/r8/regress/b71604169/Regress71604169Test.java b/src/test/java/com/android/tools/r8/regress/b71604169/Regress71604169Test.java
index dba1c0b..b618eca 100644
--- a/src/test/java/com/android/tools/r8/regress/b71604169/Regress71604169Test.java
+++ b/src/test/java/com/android/tools/r8/regress/b71604169/Regress71604169Test.java
@@ -4,59 +4,58 @@
 
 package com.android.tools.r8.regress.b71604169;
 
-import static junit.framework.TestCase.assertEquals;
 
-import com.android.tools.r8.ClassFileConsumer;
-import com.android.tools.r8.DexIndexedConsumer;
-import com.android.tools.r8.R8Command;
 import com.android.tools.r8.TestBase;
-import com.android.tools.r8.ToolHelper;
-import com.android.tools.r8.origin.Origin;
-import com.google.common.collect.ImmutableList;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
 
 @RunWith(Parameterized.class)
 public class Regress71604169Test extends TestBase {
-  private Backend backend;
 
-  @Parameterized.Parameters(name = "Backend: {0}")
-  public static Backend[] data() {
-    return ToolHelper.getBackends();
-  }
+  @Parameter(0)
+  public TestParameters parameters;
 
-  public Regress71604169Test(Backend backend) {
-    this.backend = backend;
+  @Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withAllRuntimesAndApiLevels().build();
   }
 
   @Test
   public void test() throws Exception {
-    R8Command.Builder builder = R8Command.builder();
-    // Add application classes.
-    Class mainClass = Regress71604169.class;
-    builder.addProgramFiles(ToolHelper.getClassFileForTestClass(mainClass));
-    builder.addProgramFiles(ToolHelper.getClassFileForTestClass(Regress71604169.X.class));
-    builder.addProgramFiles(ToolHelper.getClassFileForTestClass(Regress71604169.Creator.class));
+    testForR8(parameters.getBackend())
+        .addInnerClasses(getClass())
+        .addKeepMainRule(Main.class)
+        .setMinApi(parameters)
+        .compile()
+        .run(parameters.getRuntime(), Main.class)
+        .assertSuccessWithOutput("Hello, world!");
+  }
 
-    // Keep main class.
-    builder.addProguardConfiguration(
-        ImmutableList.of(keepMainProguardConfiguration(mainClass, true, false)), Origin.unknown());
-
-    if (backend == Backend.DEX) {
-      builder
-          .setProgramConsumer(DexIndexedConsumer.emptyConsumer())
-          .addLibraryFiles(ToolHelper.getDefaultAndroidJar());
-    } else {
-      assert backend == Backend.CF;
-      builder
-          .setProgramConsumer(ClassFileConsumer.emptyConsumer())
-          .addLibraryFiles(ToolHelper.getJava8RuntimeJar());
+  public static class Main {
+    public interface Creator<C> {
+      C create(Object o);
     }
-    assertEquals(
-        "Hello, world!",
-        backend == Backend.DEX
-            ? runOnArt(ToolHelper.runR8(builder.build()), mainClass)
-            : runOnJava(ToolHelper.runR8(builder.build()), mainClass));
+
+    public static class X {
+      Object o;
+
+      X(Object o) {
+        this.o = o;
+        System.out.print(o);
+      }
+    }
+
+    public static <C> C create(Creator<C> creator) {
+      return creator.create("Hello, world!");
+    }
+
+    public static void main(String[] args) {
+      create(X::new);
+    }
   }
 }
diff --git a/src/test/java/com/android/tools/r8/regress/b76025099/B76025099.java b/src/test/java/com/android/tools/r8/regress/b76025099/B76025099.java
index b80b9ce..5ef06ad 100644
--- a/src/test/java/com/android/tools/r8/regress/b76025099/B76025099.java
+++ b/src/test/java/com/android/tools/r8/regress/b76025099/B76025099.java
@@ -47,8 +47,8 @@
 
   @Test
   public void testJvm() throws Exception {
-    assumeTrue(parameters.isCfRuntime());
-    testForJvm()
+    parameters.assumeJvmTestParameters();
+    testForJvm(parameters)
         .addTestClasspath()
         .run(parameters.getRuntime(), Main.class)
         .assertSuccessWithOutput(EXPECTED_OUTPUT);
diff --git a/src/test/java/com/android/tools/r8/regress/b78493232/Regress78493232_WithPhi.java b/src/test/java/com/android/tools/r8/regress/b78493232/Regress78493232_WithPhi.java
index 7d5e8c8..b0686db 100644
--- a/src/test/java/com/android/tools/r8/regress/b78493232/Regress78493232_WithPhi.java
+++ b/src/test/java/com/android/tools/r8/regress/b78493232/Regress78493232_WithPhi.java
@@ -50,8 +50,8 @@
 
   @Test
   public void testReference() throws Exception {
-    assumeTrue(parameters.isCfRuntime());
-    testForJvm()
+    parameters.assumeJvmTestParameters();
+    testForJvm(parameters)
         .noVerify()
         .addProgramClassFileData(CLASS_BYTES)
         .addProgramClasses(CLASSES)
@@ -61,7 +61,7 @@
 
   @Test
   public void testD8() throws Exception {
-    assumeTrue(parameters.isDexRuntime());
+    parameters.assumeDexRuntime();
     D8TestRunResult result =
         testForD8()
             .addProgramClasses(CLASSES)
diff --git a/src/test/java/com/android/tools/r8/release/ShareCommonCodeOnDistinctPositionsTestRunner.java b/src/test/java/com/android/tools/r8/release/ShareCommonCodeOnDistinctPositionsTestRunner.java
index 5bc4e02..da0b9ff 100644
--- a/src/test/java/com/android/tools/r8/release/ShareCommonCodeOnDistinctPositionsTestRunner.java
+++ b/src/test/java/com/android/tools/r8/release/ShareCommonCodeOnDistinctPositionsTestRunner.java
@@ -6,70 +6,63 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 
-import com.android.tools.r8.CompilationFailedException;
-import com.android.tools.r8.R8Command;
 import com.android.tools.r8.TestBase;
-import com.android.tools.r8.ToolHelper;
-import com.android.tools.r8.origin.Origin;
-import com.android.tools.r8.utils.AndroidAppConsumers;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.utils.AndroidApiLevel;
 import com.android.tools.r8.utils.InternalOptions.LineNumberOptimization;
-import com.android.tools.r8.utils.codeinspector.CodeInspector;
 import com.android.tools.r8.utils.codeinspector.InstructionSubject;
 import com.android.tools.r8.utils.codeinspector.LineNumberTable;
 import com.android.tools.r8.utils.codeinspector.MethodSubject;
-import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Streams;
 import it.unimi.dsi.fastutil.ints.IntCollection;
-import java.io.IOException;
-import java.util.concurrent.ExecutionException;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
 import org.junit.runners.Parameterized.Parameters;
 
 @RunWith(Parameterized.class)
 public class ShareCommonCodeOnDistinctPositionsTestRunner extends TestBase {
 
-  private static final Class CLASS = ShareCommonCodeOnDistinctPositionsTest.class;
+  private static final Class<?> CLASS = ShareCommonCodeOnDistinctPositionsTest.class;
 
-  @Parameters(name = "Backend: {0}")
-  public static Backend[] parameters() {
-    return ToolHelper.getBackends();
-  }
+  @Parameter(0)
+  public TestParameters parameters;
 
-  private final Backend backend;
-
-  public ShareCommonCodeOnDistinctPositionsTestRunner(Backend backend) {
-    this.backend = backend;
+  @Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withDefaultRuntimes().withApiLevel(AndroidApiLevel.B).build();
   }
 
   @Test
-  public void test() throws CompilationFailedException, IOException, ExecutionException {
-    AndroidAppConsumers sink = new AndroidAppConsumers();
-    ToolHelper.runR8(
-        R8Command.builder()
-            .addLibraryFiles(runtimeJar(backend))
-            .addProgramFiles(ToolHelper.getClassFileForTestClass(CLASS))
-            .setProgramConsumer(sink.wrapProgramConsumer(emptyConsumer(backend)))
-            .setDisableMinification(true)
-            .setDisableTreeShaking(true)
-            .addProguardConfiguration(
-                ImmutableList.of("-keepattributes LineNumberTable"), Origin.unknown())
-            .build(),
-        options -> options.lineNumberOptimization = LineNumberOptimization.OFF);
-    CodeInspector inspector = new CodeInspector(sink.build());
-    MethodSubject method = inspector.clazz(CLASS).mainMethod();
-    // Check that the two shared lines are not in the output (they have no throwing instructions).
-    LineNumberTable lineNumberTable = method.getLineNumberTable();
-    IntCollection lines = lineNumberTable.getLines();
-    assertFalse(lines.contains(12));
-    assertFalse(lines.contains(14));
-    // Check that the two lines have been shared, e.g., there may be only one multiplication left.
-    assertEquals(
-        "Expected only one multiplcation due to instruction sharing.",
-        1,
-        Streams.stream(method.iterateInstructions())
-            .filter(InstructionSubject::isMultiplication)
-            .count());
+  public void test() throws Exception {
+    testForR8(parameters.getBackend())
+        .addProgramClasses(CLASS)
+        .addKeepAttributeLineNumberTable()
+        .addDontObfuscate()
+        .addDontShrink()
+        .addOptionsModification(
+            options -> options.lineNumberOptimization = LineNumberOptimization.OFF)
+        .setMinApi(parameters)
+        .compile()
+        .inspect(
+            inspector -> {
+              MethodSubject method = inspector.clazz(CLASS).mainMethod();
+              // Check that the two shared lines are not in the output (they have no throwing
+              // instructions).
+              LineNumberTable lineNumberTable = method.getLineNumberTable();
+              IntCollection lines = lineNumberTable.getLines();
+              assertFalse(lines.contains(12));
+              assertFalse(lines.contains(14));
+              // Check that the two lines have been shared, e.g., there may be only one
+              // multiplication left.
+              assertEquals(
+                  "Expected only one multiplcation due to instruction sharing.",
+                  1,
+                  Streams.stream(method.iterateInstructions())
+                      .filter(InstructionSubject::isMultiplication)
+                      .count());
+            });
   }
 }
diff --git a/src/test/java/com/android/tools/r8/repackage/CrossPackageInvokeSuperToPackagePrivateMethodTest.java b/src/test/java/com/android/tools/r8/repackage/CrossPackageInvokeSuperToPackagePrivateMethodTest.java
index 66ba3ad..599ad3d 100644
--- a/src/test/java/com/android/tools/r8/repackage/CrossPackageInvokeSuperToPackagePrivateMethodTest.java
+++ b/src/test/java/com/android/tools/r8/repackage/CrossPackageInvokeSuperToPackagePrivateMethodTest.java
@@ -6,7 +6,6 @@
 
 import static org.hamcrest.CoreMatchers.allOf;
 import static org.hamcrest.CoreMatchers.containsString;
-import static org.junit.Assume.assumeTrue;
 
 import com.android.tools.r8.NeverClassInline;
 import com.android.tools.r8.NeverInline;
@@ -40,8 +39,8 @@
 
   @Test
   public void testJvm() throws Exception {
-    assumeTrue(parameters.isCfRuntime());
-    testForJvm()
+    parameters.assumeJvmTestParameters();
+    testForJvm(parameters)
         .apply(this::addProgramClasses)
         .run(parameters.getRuntime(), TestClass.class)
         .assertSuccessWithOutputLines("A", "B", "A", "C", "D", "C");
diff --git a/src/test/java/com/android/tools/r8/repackage/RepackageMissingTypeCollisionTest.java b/src/test/java/com/android/tools/r8/repackage/RepackageMissingTypeCollisionTest.java
index e967b74..e1f0cb0 100644
--- a/src/test/java/com/android/tools/r8/repackage/RepackageMissingTypeCollisionTest.java
+++ b/src/test/java/com/android/tools/r8/repackage/RepackageMissingTypeCollisionTest.java
@@ -7,7 +7,6 @@
 import static com.android.tools.r8.utils.codeinspector.Matchers.isPresentAndRenamed;
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.junit.Assert.assertEquals;
-import static org.junit.Assume.assumeTrue;
 
 import com.android.tools.r8.R8CompatTestBuilder;
 import com.android.tools.r8.TestParameters;
@@ -33,13 +32,13 @@
 
   @Test
   public void testJvm() throws Exception {
-    assumeTrue(parameters.isCfRuntime());
+    parameters.assumeJvmTestParameters();
     String newMissingTypeName =
         getRepackagePackage() + (isFlattenPackageHierarchy() ? ".a.a" : ".a");
     String newMissingDescriptor = DescriptorUtils.javaTypeToDescriptor(newMissingTypeName);
     String newATypeName = A.class.getPackage().getName() + ".a";
     String newADescriptor = DescriptorUtils.javaTypeToDescriptor(newATypeName);
-    testForJvm()
+    testForJvm(parameters)
         .addProgramClassFileData(
             transformer(A.class).setClassDescriptor(newADescriptor).transform(),
             transformer(Anno.class)
diff --git a/src/test/java/com/android/tools/r8/repackage/RepackageTest.java b/src/test/java/com/android/tools/r8/repackage/RepackageTest.java
index 370d413..5651252 100644
--- a/src/test/java/com/android/tools/r8/repackage/RepackageTest.java
+++ b/src/test/java/com/android/tools/r8/repackage/RepackageTest.java
@@ -86,8 +86,8 @@
   public void testJvm() throws Exception {
     assumeFalse(allowAccessModification);
     assumeTrue(isFlattenPackageHierarchy());
-    assumeTrue(parameters.isCfRuntime());
-    testForJvm()
+    parameters.assumeJvmTestParameters();
+    testForJvm(parameters)
         .addTestClasspath()
         .run(parameters.getRuntime(), TestClass.class)
         .assertSuccessWithOutputLines(EXPECTED);
diff --git a/src/test/java/com/android/tools/r8/resolution/B77944861.java b/src/test/java/com/android/tools/r8/resolution/B77944861.java
index 09a3054..5e007b7 100644
--- a/src/test/java/com/android/tools/r8/resolution/B77944861.java
+++ b/src/test/java/com/android/tools/r8/resolution/B77944861.java
@@ -8,103 +8,85 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
 
-import com.android.tools.r8.R8Command;
 import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
 import com.android.tools.r8.ToolHelper;
-import com.android.tools.r8.ToolHelper.ProcessResult;
-import com.android.tools.r8.origin.Origin;
-import com.android.tools.r8.utils.AndroidApp;
 import com.android.tools.r8.utils.FileUtils;
+import com.android.tools.r8.utils.StringUtils;
 import com.android.tools.r8.utils.codeinspector.ClassSubject;
-import com.android.tools.r8.utils.codeinspector.CodeInspector;
 import com.android.tools.r8.utils.codeinspector.FieldAccessInstructionSubject;
 import com.android.tools.r8.utils.codeinspector.InstructionSubject;
 import com.android.tools.r8.utils.codeinspector.MethodSubject;
 import com.google.common.collect.ImmutableList;
 import java.nio.file.Path;
 import java.nio.file.Paths;
-import java.util.Collections;
 import java.util.Iterator;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
 
 @RunWith(Parameterized.class)
 public class B77944861 extends TestBase {
 
-  private static final String PRG =
-      ToolHelper.EXAMPLES_BUILD_DIR + "regress_77944861" + FileUtils.JAR_EXTENSION;
+  private static final String MAIN = "regress_77944861.SomeView";
+  private static final String EXPECTED_OUTPUT = StringUtils.lines("foo");
 
-  private Backend backend;
+  private static final Path PRG =
+      Paths.get(ToolHelper.EXAMPLES_BUILD_DIR + "regress_77944861" + FileUtils.JAR_EXTENSION);
 
-  @Parameterized.Parameters(name = "Backend: {0}")
-  public static Backend[] data() {
-    return ToolHelper.getBackends();
-  }
+  @Parameter(0)
+  public TestParameters parameters;
 
-  public B77944861(Backend backend) {
-    this.backend = backend;
-  }
-
-  private AndroidApp runR8(AndroidApp app, String main, Path out) throws Exception {
-    R8Command command =
-        ToolHelper.addProguardConfigurationConsumer(
-                ToolHelper.prepareR8CommandBuilder(app),
-                pgConfig -> {
-                  pgConfig.setPrintMapping(true);
-                  pgConfig.setPrintMappingFile(out.resolve(ToolHelper.DEFAULT_PROGUARD_MAP_FILE));
-                })
-            .addProguardConfiguration(
-                ImmutableList.of(keepMainProguardConfiguration(main)), Origin.unknown())
-            .setOutput(out, outputMode(backend))
-            .addLibraryFiles(TestBase.runtimeJar(backend))
-            .setDisableTreeShaking(true)
-            .setDisableMinification(true)
-            .build();
-    return ToolHelper.runR8(
-        command,
-        o -> {
-          o.inlinerOptions().enableInlining = false;
-        });
+  @Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withAllRuntimesAndApiLevels().build();
   }
 
   @Test
-  public void test() throws Exception {
-    Path out = temp.getRoot().toPath();
-    Path jarPath = Paths.get(PRG);
-    String mainName = "regress_77944861.SomeView";
-    ProcessResult jvmOutput = ToolHelper.runJava(ImmutableList.of(jarPath), mainName);
-    assertEquals(0, jvmOutput.exitCode);
-    AndroidApp processedApp = runR8(readJar(jarPath), mainName, out);
-    CodeInspector codeInspector = new CodeInspector(processedApp);
-    ClassSubject view = codeInspector.clazz("regress_77944861.SomeView");
-    assertThat(view, isPresent());
-    String className = "regress_77944861.inner.TopLevelPolicy$MobileIconState";
-    MethodSubject initView = view.method("java.lang.String", "get", ImmutableList.of(className));
-    assertThat(initView, isPresent());
-    Iterator<InstructionSubject> iterator = initView.iterateInstructions();
-    InstructionSubject instruction;
-    do {
-      assertTrue(iterator.hasNext());
-      instruction = iterator.next();
-    } while (!instruction.isInstanceGet());
-
-    assertEquals(className, ((FieldAccessInstructionSubject) instruction).holder().toString());
-
-    do {
-      assertTrue(iterator.hasNext());
-      instruction = iterator.next();
-    } while (!instruction.isReturnObject());
-
-    ProcessResult output;
-    if (backend == Backend.DEX) {
-      output = runOnArtRaw(processedApp, mainName);
-    } else {
-      assert backend == Backend.CF;
-      output = runOnJavaRaw(processedApp, mainName, Collections.emptyList());
-    }
-    assertEquals(0, output.exitCode);
-    assertEquals(jvmOutput.stdout, output.stdout);
+  public void testJvm() throws Exception {
+    parameters.assumeJvmTestParameters();
+    testForJvm(parameters)
+        .addProgramFiles(PRG)
+        .run(parameters.getRuntime(), MAIN)
+        .assertSuccessWithOutput(EXPECTED_OUTPUT);
   }
 
+  @Test
+  public void testR8() throws Exception {
+    testForR8(parameters.getBackend())
+        .addProgramFiles(PRG)
+        .addKeepMainRule(MAIN)
+        .addDontObfuscate()
+        .addDontShrink()
+        .setMinApi(parameters)
+        .compile()
+        .inspect(
+            inspector -> {
+              ClassSubject view = inspector.clazz("regress_77944861.SomeView");
+              assertThat(view, isPresent());
+              String className = "regress_77944861.inner.TopLevelPolicy$MobileIconState";
+              MethodSubject initView =
+                  view.method("java.lang.String", "get", ImmutableList.of(className));
+              assertThat(initView, isPresent());
+              Iterator<InstructionSubject> iterator = initView.iterateInstructions();
+              InstructionSubject instruction;
+              do {
+                assertTrue(iterator.hasNext());
+                instruction = iterator.next();
+              } while (!instruction.isInstanceGet());
+
+              assertEquals(
+                  className, ((FieldAccessInstructionSubject) instruction).holder().toString());
+
+              do {
+                assertTrue(iterator.hasNext());
+                instruction = iterator.next();
+              } while (!instruction.isReturnObject());
+            })
+        .run(parameters.getRuntime(), MAIN)
+        .assertSuccessWithOutput(EXPECTED_OUTPUT);
+  }
 }
diff --git a/src/test/java/com/android/tools/r8/resolution/VirtualOverrideOfPrivateStaticMethodTest.java b/src/test/java/com/android/tools/r8/resolution/VirtualOverrideOfPrivateStaticMethodTest.java
index f2c6cac..86a0415 100644
--- a/src/test/java/com/android/tools/r8/resolution/VirtualOverrideOfPrivateStaticMethodTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/VirtualOverrideOfPrivateStaticMethodTest.java
@@ -5,7 +5,6 @@
 
 import static com.android.tools.r8.ToolHelper.getMostRecentAndroidJar;
 import static org.junit.Assert.assertTrue;
-import static org.junit.Assume.assumeTrue;
 
 import com.android.tools.r8.CompilationFailedException;
 import com.android.tools.r8.TestBase;
@@ -98,8 +97,8 @@
 
   @Test
   public void testJvm() throws Exception {
-    assumeTrue(parameters.isCfRuntime());
-    testForJvm()
+    parameters.assumeJvmTestParameters();
+    testForJvm(parameters)
         .addProgramClasses(CLASSES)
         .run(parameters.getRuntime(), Main.class)
         .assertFailureWithErrorThatThrows(IllegalAccessError.class);
diff --git a/src/test/java/com/android/tools/r8/resolution/VirtualOverrideOfPrivateStaticMethodWithVirtualParentTest.java b/src/test/java/com/android/tools/r8/resolution/VirtualOverrideOfPrivateStaticMethodWithVirtualParentTest.java
index eae67e7..3fbfafb 100644
--- a/src/test/java/com/android/tools/r8/resolution/VirtualOverrideOfPrivateStaticMethodWithVirtualParentTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/VirtualOverrideOfPrivateStaticMethodWithVirtualParentTest.java
@@ -117,7 +117,7 @@
     TestRunResult<?> runResult;
     if (parameters.isCfRuntime()) {
       runResult =
-          testForJvm()
+          testForJvm(parameters)
               .addProgramClasses(CLASSES)
               .addProgramClassFileData(getDumps())
               .run(parameters.getRuntime(), Main.class);
diff --git a/src/test/java/com/android/tools/r8/resolution/VirtualOverrideOfStaticMethodWithVirtualParentTest.java b/src/test/java/com/android/tools/r8/resolution/VirtualOverrideOfStaticMethodWithVirtualParentTest.java
index ce3ab7f..b456774 100644
--- a/src/test/java/com/android/tools/r8/resolution/VirtualOverrideOfStaticMethodWithVirtualParentTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/VirtualOverrideOfStaticMethodWithVirtualParentTest.java
@@ -199,7 +199,7 @@
     TestRunResult<?> runResult;
     if (parameters.isCfRuntime()) {
       runResult =
-          testForJvm()
+          testForJvm(parameters)
               .addProgramClasses(CLASSES)
               .addProgramClassFileData(DUMPS)
               .run(parameters.getRuntime(), Main.class);
diff --git a/src/test/java/com/android/tools/r8/resolution/duplicatedefinitions/MaximallySpecificAbstractOnIncompletePathTest.java b/src/test/java/com/android/tools/r8/resolution/duplicatedefinitions/MaximallySpecificAbstractOnIncompletePathTest.java
index 69f0801..82b018d 100644
--- a/src/test/java/com/android/tools/r8/resolution/duplicatedefinitions/MaximallySpecificAbstractOnIncompletePathTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/duplicatedefinitions/MaximallySpecificAbstractOnIncompletePathTest.java
@@ -83,8 +83,8 @@
 
   @Test
   public void testJvm() throws Exception {
-    assumeTrue(parameters.isCfRuntime());
-    testForJvm()
+    parameters.assumeJvmTestParameters();
+    testForJvm(parameters)
         .addRunClasspathFiles(libraryClasses)
         .addProgramClassFileData(getMainWithoutFoo(), getIOnProgram())
         .run(parameters.getRuntime(), Main.class)
@@ -93,7 +93,7 @@
 
   @Test
   public void testD8() throws Exception {
-    assumeTrue(parameters.isDexRuntime());
+    parameters.assumeDexRuntime();
     Version dexRuntime = parameters.getDexRuntimeVersion();
     testForD8(parameters.getBackend())
         .apply(this::setupTestBuilder)
diff --git a/src/test/java/com/android/tools/r8/resolution/duplicatedefinitions/MaximallySpecificDifferentParentHierarchyTest.java b/src/test/java/com/android/tools/r8/resolution/duplicatedefinitions/MaximallySpecificDifferentParentHierarchyTest.java
index a87967c..da99a4f 100644
--- a/src/test/java/com/android/tools/r8/resolution/duplicatedefinitions/MaximallySpecificDifferentParentHierarchyTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/duplicatedefinitions/MaximallySpecificDifferentParentHierarchyTest.java
@@ -110,8 +110,8 @@
 
   @Test
   public void testJvm() throws Exception {
-    assumeTrue(parameters.isCfRuntime());
-    testForJvm()
+    parameters.assumeJvmTestParameters();
+    testForJvm(parameters)
         .addRunClasspathFiles(libraryClasses)
         .addProgramClasses(Main.class)
         .addProgramClassFileData(getJProgram())
@@ -121,8 +121,8 @@
 
   @Test
   public void testD8() throws Exception {
-    assumeTrue(parameters.isDexRuntime());
-    testForD8(parameters.getBackend())
+    parameters.assumeDexRuntime();
+    testForD8()
         .apply(this::setupTestBuilder)
         .compile()
         .addBootClasspathFiles(buildOnDexRuntime(parameters, libraryClasses))
diff --git a/src/test/java/com/android/tools/r8/resolution/duplicatedefinitions/MaximallySpecificMultipleOnCompleteTest.java b/src/test/java/com/android/tools/r8/resolution/duplicatedefinitions/MaximallySpecificMultipleOnCompleteTest.java
index 75cc0cd..5d89fbd 100644
--- a/src/test/java/com/android/tools/r8/resolution/duplicatedefinitions/MaximallySpecificMultipleOnCompleteTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/duplicatedefinitions/MaximallySpecificMultipleOnCompleteTest.java
@@ -86,8 +86,8 @@
 
   @Test
   public void testJvm() throws Exception {
-    assumeTrue(parameters.isCfRuntime());
-    testForJvm()
+    parameters.assumeJvmTestParameters();
+    testForJvm(parameters)
         .addRunClasspathFiles(libraryClasses)
         .addProgramClasses(K.class, M.class)
         .addProgramClassFileData(getJOnProgram(), getMainWithAllImplements())
@@ -97,7 +97,7 @@
 
   @Test
   public void testD8() throws Exception {
-    assumeTrue(parameters.isDexRuntime());
+    parameters.assumeDexRuntime();
     runTest(testForD8(parameters.getBackend()));
   }
 
diff --git a/src/test/java/com/android/tools/r8/resolution/duplicatedefinitions/MaximallySpecificMultiplePathsICCETest.java b/src/test/java/com/android/tools/r8/resolution/duplicatedefinitions/MaximallySpecificMultiplePathsICCETest.java
index 910bc1d..0a0ce8c 100644
--- a/src/test/java/com/android/tools/r8/resolution/duplicatedefinitions/MaximallySpecificMultiplePathsICCETest.java
+++ b/src/test/java/com/android/tools/r8/resolution/duplicatedefinitions/MaximallySpecificMultiplePathsICCETest.java
@@ -112,8 +112,8 @@
 
   @Test
   public void testJvm() throws Exception {
-    assumeTrue(parameters.isCfRuntime());
-    testForJvm()
+    parameters.assumeJvmTestParameters();
+    testForJvm(parameters)
         .addRunClasspathFiles(libraryClasses)
         .addProgramClasses(I.class, J.class)
         .addProgramClassFileData(getMainWithInterfacesIAndJ())
@@ -123,7 +123,7 @@
 
   @Test
   public void testD8() throws Exception {
-    assumeTrue(parameters.isDexRuntime());
+    parameters.assumeDexRuntime();
     runTest(testForD8(parameters.getBackend()))
         .assertFailureWithErrorThatThrows(IncompatibleClassChangeError.class);
   }
diff --git a/src/test/java/com/android/tools/r8/resolution/duplicatedefinitions/MaximallySpecificMultiplePathsSuccessTest.java b/src/test/java/com/android/tools/r8/resolution/duplicatedefinitions/MaximallySpecificMultiplePathsSuccessTest.java
index 394540c..2852961 100644
--- a/src/test/java/com/android/tools/r8/resolution/duplicatedefinitions/MaximallySpecificMultiplePathsSuccessTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/duplicatedefinitions/MaximallySpecificMultiplePathsSuccessTest.java
@@ -113,8 +113,8 @@
 
   @Test
   public void testJvm() throws Exception {
-    assumeTrue(parameters.isCfRuntime());
-    testForJvm()
+    parameters.assumeJvmTestParameters();
+    testForJvm(parameters)
         .addRunClasspathFiles(libraryClasses)
         .addProgramClasses(Main.class)
         .addProgramClassFileData(getIProgram(), getJProgram())
@@ -125,7 +125,7 @@
 
   @Test
   public void testD8() throws Exception {
-    assumeTrue(parameters.isDexRuntime());
+    parameters.assumeDexRuntime();
     boolean isDalvik = parameters.getDexRuntimeVersion().isDalvik();
     runTest(testForD8(parameters.getBackend()))
         .assertSuccessWithOutputLinesIf(isDalvik, D8_R8_RESULT)
diff --git a/src/test/java/com/android/tools/r8/resolution/duplicatedefinitions/MaximallySpecificMultiplePathsThroughClassTest.java b/src/test/java/com/android/tools/r8/resolution/duplicatedefinitions/MaximallySpecificMultiplePathsThroughClassTest.java
index af98951..038ac20 100644
--- a/src/test/java/com/android/tools/r8/resolution/duplicatedefinitions/MaximallySpecificMultiplePathsThroughClassTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/duplicatedefinitions/MaximallySpecificMultiplePathsThroughClassTest.java
@@ -100,8 +100,8 @@
 
   @Test
   public void testJvm() throws Exception {
-    assumeTrue(parameters.isCfRuntime());
-    testForJvm()
+    parameters.assumeJvmTestParameters();
+    testForJvm(parameters)
         .addRunClasspathFiles(libraryClasses)
         .addProgramClasses(J.class, Main.class)
         .addProgramClassFileData(getAWithImplementsI(), getIProgram())
@@ -111,7 +111,7 @@
 
   @Test
   public void testD8() throws Exception {
-    assumeTrue(parameters.isDexRuntime());
+    parameters.assumeDexRuntime();
     runTest(testForD8(parameters.getBackend()), IncompatibleClassChangeError.class);
   }
 
diff --git a/src/test/java/com/android/tools/r8/resolution/duplicatedefinitions/MaximallySpecificSingleDominatingAfterJoinTest.java b/src/test/java/com/android/tools/r8/resolution/duplicatedefinitions/MaximallySpecificSingleDominatingAfterJoinTest.java
index f34097c..cc1812a 100644
--- a/src/test/java/com/android/tools/r8/resolution/duplicatedefinitions/MaximallySpecificSingleDominatingAfterJoinTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/duplicatedefinitions/MaximallySpecificSingleDominatingAfterJoinTest.java
@@ -97,8 +97,8 @@
 
   @Test
   public void testJvm() throws Exception {
-    assumeTrue(parameters.isCfRuntime());
-    testForJvm()
+    parameters.assumeJvmTestParameters();
+    testForJvm(parameters)
         .addRunClasspathFiles(libraryClasses)
         .addProgramClasses(K.class, Main.class)
         .run(parameters.getRuntime(), Main.class)
@@ -107,7 +107,7 @@
 
   @Test
   public void testD8() throws Exception {
-    assumeTrue(parameters.isDexRuntime());
+    parameters.assumeDexRuntime();
     runTest(
         testForD8(parameters.getBackend()),
         parameters.getDexRuntimeVersion().isDalvik()
diff --git a/src/test/java/com/android/tools/r8/resolution/duplicatedefinitions/MaximallySpecificSingleDominatingSubTest.java b/src/test/java/com/android/tools/r8/resolution/duplicatedefinitions/MaximallySpecificSingleDominatingSubTest.java
index c7ce7db..d5c657c 100644
--- a/src/test/java/com/android/tools/r8/resolution/duplicatedefinitions/MaximallySpecificSingleDominatingSubTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/duplicatedefinitions/MaximallySpecificSingleDominatingSubTest.java
@@ -99,8 +99,8 @@
 
   @Test
   public void testJvm() throws Exception {
-    assumeTrue(parameters.isCfRuntime());
-    testForJvm()
+    parameters.assumeJvmTestParameters();
+    testForJvm(parameters)
         .addRunClasspathFiles(libraryClasses)
         .addProgramClasses(K.class, Main.class)
         .addProgramClassFileData(getJOnProgram())
@@ -110,7 +110,7 @@
 
   @Test
   public void testD8() throws Exception {
-    assumeTrue(parameters.isDexRuntime());
+    parameters.assumeDexRuntime();
     runTest(testForD8(parameters.getBackend()));
   }
 
diff --git a/src/test/java/com/android/tools/r8/resolution/duplicatedefinitions/MaximallySpecificSingleLibraryPartialTest.java b/src/test/java/com/android/tools/r8/resolution/duplicatedefinitions/MaximallySpecificSingleLibraryPartialTest.java
index 32e82f1..e2fd96f 100644
--- a/src/test/java/com/android/tools/r8/resolution/duplicatedefinitions/MaximallySpecificSingleLibraryPartialTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/duplicatedefinitions/MaximallySpecificSingleLibraryPartialTest.java
@@ -111,8 +111,8 @@
 
   @Test
   public void testJvm() throws Exception {
-    assumeTrue(parameters.isCfRuntime());
-    testForJvm()
+    parameters.assumeJvmTestParameters();
+    testForJvm(parameters)
         .addRunClasspathFiles(libraryClasses)
         .addProgramClasses(Main.class)
         .addProgramClassFileData(getIProgram())
@@ -122,7 +122,7 @@
 
   @Test
   public void testD8() throws Exception {
-    assumeTrue(parameters.isDexRuntime());
+    parameters.assumeDexRuntime();
     // TODO(b/230289235): Extend resolution to support multiple definition results.
     runTest(testForD8(parameters.getBackend()))
         .assertFailureWithErrorThatThrowsIf(
diff --git a/src/test/java/com/android/tools/r8/resolution/duplicatedefinitions/MaximallySpecificSingleProgramPartialTest.java b/src/test/java/com/android/tools/r8/resolution/duplicatedefinitions/MaximallySpecificSingleProgramPartialTest.java
index a9c3e11..3d22646 100644
--- a/src/test/java/com/android/tools/r8/resolution/duplicatedefinitions/MaximallySpecificSingleProgramPartialTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/duplicatedefinitions/MaximallySpecificSingleProgramPartialTest.java
@@ -109,8 +109,8 @@
 
   @Test
   public void testJvm() throws Exception {
-    assumeTrue(parameters.isCfRuntime());
-    testForJvm()
+    parameters.assumeJvmTestParameters();
+    testForJvm(parameters)
         .addRunClasspathFiles(libraryClasses)
         .addProgramClassFileData(getMainImplementingI(), getIProgram())
         .run(parameters.getRuntime(), Main.class)
@@ -119,7 +119,7 @@
 
   @Test
   public void testD8() throws Exception {
-    assumeTrue(parameters.isDexRuntime());
+    parameters.assumeDexRuntime();
     // TODO(b/230289235): Extend to support multiple definition results.
     runTest(testForD8(parameters.getBackend()))
         .assertFailureWithErrorThatThrowsIf(
diff --git a/src/test/java/com/android/tools/r8/resource/DataResourceTest.java b/src/test/java/com/android/tools/r8/resource/DataResourceTest.java
index 653059c..b874072 100644
--- a/src/test/java/com/android/tools/r8/resource/DataResourceTest.java
+++ b/src/test/java/com/android/tools/r8/resource/DataResourceTest.java
@@ -4,77 +4,111 @@
 
 package com.android.tools.r8.resource;
 
-import com.android.tools.r8.ClassFileConsumer;
-import com.android.tools.r8.CompilationFailedException;
-import com.android.tools.r8.DexIndexedConsumer;
-import com.android.tools.r8.R8Command;
 import com.android.tools.r8.TestBase;
-import com.android.tools.r8.TestBase.Backend;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
 import com.android.tools.r8.ToolHelper;
-import com.android.tools.r8.ToolHelper.ProcessResult;
-import com.android.tools.r8.origin.Origin;
 import com.android.tools.r8.utils.FileUtils;
+import com.android.tools.r8.utils.StringUtils;
 import com.android.tools.r8.utils.TestDescriptionWatcher;
-import com.google.common.collect.ImmutableList;
-import java.io.IOException;
 import java.nio.file.Path;
 import java.nio.file.Paths;
-import org.junit.Assert;
 import org.junit.Rule;
 import org.junit.Test;
-import org.junit.rules.TemporaryFolder;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
 
 @RunWith(Parameterized.class)
-public class DataResourceTest {
+public class DataResourceTest extends TestBase {
 
-  private TestBase.Backend backend;
+  private static final String PACKAGE_NAME = "dataresource";
+  private static final String MAIN_CLASS_NAME = PACKAGE_NAME + ".ResourceTest";
+  private static final Path INPUT_JAR =
+      Paths.get(ToolHelper.EXAMPLES_BUILD_DIR, PACKAGE_NAME + FileUtils.JAR_EXTENSION);
+  private static final String EXPECTED_OUTPUT =
+      StringUtils.lines(
+          "LibClass dir: true",
+          "LibClass properties: true",
+          "LibClass property: com.test.lib.LibClass",
+          "LibClass text: this is a text with some content",
+          "- partly matching pattern 123dataresource.lib.LibClass123",
+          "- totally matching pattern dataresource.lib.LibClass and something after",
+          "- matching the package dataresource.lib",
+          "- matching class simple name LibClass",
+          "- or only single element of the package name: lib",
+          "- matching class descriptor dataresource/lib/LibClass",
+          "- matching class full descriptor Ldataresource/lib/LibClass;",
+          "- matching windows path dataresource\\lib\\LibClass",
+          "- matching pattern dataresource.lib.LibClass.",
+          "- matching pattern .dataresource.lib.LibClass",
+          "- matching pattern dataresource.lib.LibClass,",
+          "- matching pattern ,dataresource.lib.LibClass",
+          "- matching pattern =dataresource.lib.LibClass",
+          "- matching pattern dataresource.lib.LibClass=",
+          "- matching pattern dataresource.lib.LibClass/",
+          "- matching pattern /dataresource.lib.LibClass",
+          "- matching pattern ?dataresource.lib.LibClass",
+          "- matching pattern dataresource.lib.LibClass?",
+          "- matching pattern dataresource.lib.LibClass!",
+          "- matching pattern !dataresource.lib.LibClass",
+          "- matching pattern :dataresource.lib.LibClass",
+          "- matching pattern dataresource.lib.LibClass:",
+          "- matching pattern dataresource.lib.LibClass*",
+          "- matching pattern *dataresource.lib.LibClass",
+          "- matching pattern $dataresource.lib.LibClass",
+          "- matching pattern +dataresource.lib.LibClass",
+          "- matching pattern -dataresource.lib.LibClass",
+          "- matching pattern ^dataresource.lib.LibClass",
+          "- matching pattern @dataresource.lib.LibClass",
+          "- matching pattern (dataresource.lib.LibClass",
+          "- matching pattern )dataresource.lib.LibClass",
+          "- matching pattern àdataresource.lib.LibClass",
+          "- matching pattern |dataresource.lib.LibClass",
+          "- matching pattern [dataresource.lib.LibClass",
+          "- matching pattern 'dataresource.lib.LibClass",
+          "- matching pattern \"dataresource.lib.LibClass",
+          "- matching pattern `dataresource.lib.LibClass",
+          "- matching pattern ~dataresource.lib.LibClass",
+          "- matching pattern &dataresource.lib.LibClass",
+          "- matching pattern -dataresource.lib.LibClass",
+          "- matching pattern dataresource.lib.LibClass-",
+          "",
+          "LibClass const string: dataresource.lib.LibClass",
+          "LibClass concat string: dataresource.lib.LibClasscom.test.lib.LibClass",
+          "LibClass field: dataresource.lib.LibClass");
 
-  @Parameterized.Parameters(name = "Backend: {0}")
-  public static Backend[] data() {
-    return ToolHelper.getBackends();
+  @Parameter(0)
+  public TestParameters parameters;
+
+  @Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withAllRuntimesAndApiLevels().build();
   }
 
-  public DataResourceTest(TestBase.Backend backend) {
-    this.backend = backend;
-  }
-
-  @Rule
-  public TemporaryFolder temp = ToolHelper.getTemporaryFolderForTest();
-
   @Rule
   public TestDescriptionWatcher watcher = new TestDescriptionWatcher();
 
   @Test
-  public void dataResourceTest() throws IOException, CompilationFailedException {
-    String packageName = "dataresource";
-    String mainClassName = packageName + ".ResourceTest";
-    Path inputJar = Paths.get(ToolHelper.EXAMPLES_BUILD_DIR,
-        packageName + FileUtils.JAR_EXTENSION);
+  public void testJvm() throws Exception {
+    parameters.assumeJvmTestParameters();
+    testForJvm(parameters)
+        .addProgramFiles(INPUT_JAR)
+        .run(parameters.getRuntime(), MAIN_CLASS_NAME)
+        .assertSuccessWithOutput(EXPECTED_OUTPUT);
+  }
 
-    ProcessResult referenceResult = ToolHelper.runJava(inputJar, mainClassName);
-
-    assert backend == Backend.DEX || backend == Backend.CF;
-    Path r8Out = temp.getRoot().toPath().resolve("r8out.jar");
-    R8Command.Builder builder =
-        R8Command.builder()
-            .setDisableTreeShaking(true)
-            .setDisableMinification(true)
-            .addProgramFiles(inputJar)
-            .addProguardConfiguration(ImmutableList.of("-keepdirectories"), Origin.unknown())
-            .setProgramConsumer(
-                backend == Backend.DEX
-                    ? new DexIndexedConsumer.ArchiveConsumer(r8Out, true)
-                    : new ClassFileConsumer.ArchiveConsumer(r8Out, true));
-    ToolHelper.runR8(builder.build());
-
-    ProcessResult r8Result;
-    if (backend == Backend.DEX) {
-      r8Result = ToolHelper.runArtRaw(r8Out.toString(), mainClassName);
-    } else {
-      r8Result = ToolHelper.runJava(r8Out, mainClassName);
-    }
-    Assert.assertEquals(referenceResult.stdout, r8Result.stdout);
+  @Test
+  public void dataResourceTest() throws Exception {
+    testForR8(parameters.getBackend())
+        .addProgramFiles(INPUT_JAR)
+        .addKeepRules("-keepdirectories")
+        .addDontObfuscate()
+        .addDontShrink()
+        .setMinApi(parameters)
+        .compile()
+        .run(parameters.getRuntime(), MAIN_CLASS_NAME)
+        .assertSuccessWithOutput(EXPECTED_OUTPUT);
   }
 }
diff --git a/src/test/java/com/android/tools/r8/resource/KeepDirectoriesTest.java b/src/test/java/com/android/tools/r8/resource/KeepDirectoriesTest.java
index fedfb29..95db74a 100644
--- a/src/test/java/com/android/tools/r8/resource/KeepDirectoriesTest.java
+++ b/src/test/java/com/android/tools/r8/resource/KeepDirectoriesTest.java
@@ -33,6 +33,8 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
 
 class Main {
 
@@ -46,21 +48,17 @@
 @RunWith(Parameterized.class)
 public class KeepDirectoriesTest extends ProguardCompatibilityTestBase {
 
-  private Backend backend;
-  private final boolean minify;
+  @Parameter(0)
+  public boolean minify;
 
-  @Parameterized.Parameters(name = "Backend: {0}, Minify: {1}")
+  @Parameter(1)
+  public TestParameters parameters;
+
+  @Parameters(name = "{1}, minify: {0}")
   public static Collection<Object[]> data() {
     return buildParameters(
-        ToolHelper.getBackends(),
         BooleanUtils.values(),
-        TestParameters.builder().withNoneRuntime().build());
-  }
-
-  public KeepDirectoriesTest(Backend backend, boolean minify, TestParameters parameters) {
-    this.backend = backend;
-    this.minify = minify;
-    parameters.assertNoneRuntime();
+        getTestParameters().withDefaultRuntimes().withMinimumApiLevel().build());
   }
 
   // Return the original package name for this package.
@@ -102,7 +100,7 @@
   @Test
   public void testKeepSome1() throws Exception {
     CustomDataResourceConsumer dataResourceConsumer = new CustomDataResourceConsumer();
-    compileWithR8("-keepdirectories org/example/*", minify, dataResourceConsumer);
+    compileWithR8("-keepdirectories org/example/**", minify, dataResourceConsumer);
     Set<String> expected =
         getDataResources().stream()
             .map(DataResource::getName)
@@ -115,7 +113,7 @@
     return (int) s.chars().filter(c -> c == '/').count();
   }
 
-  class PrefixMapper implements Function<String, String> {
+  static class PrefixMapper implements Function<String, String> {
     private final String original;
     private final String mapped;
 
@@ -165,10 +163,9 @@
             + " class "
             + Main.class.getCanonicalName();
     R8Command command =
-        ToolHelper.prepareR8CommandBuilder(getAndroidApp(), emptyConsumer(backend))
-            .addProguardConfiguration(
-                ImmutableList.of(proguardConfig, "-printmapping", r), Origin.unknown())
-            .addLibraryFiles(runtimeJar(backend))
+        ToolHelper.prepareR8CommandBuilder(getAndroidApp(), emptyConsumer(parameters.getBackend()))
+            .addProguardConfiguration(ImmutableList.of(proguardConfig, r), Origin.unknown())
+            .addLibraryFiles(parameters.getDefaultRuntimeLibrary())
             .build();
     return ToolHelper.runR8(
         command, options -> options.dataResourceConsumer = dataResourceConsumer);
@@ -214,13 +211,13 @@
 
   private List<DataResource> getDataResources() {
     return ImmutableList.of(
-        DataDirectoryResource.fromName("org", Origin.unknown()),
-        DataDirectoryResource.fromName("org/example", Origin.unknown()),
-        DataDirectoryResource.fromName("org/example/test", Origin.unknown()),
-        DataDirectoryResource.fromName(pathForThisPackage(), Origin.unknown()),
-        DataDirectoryResource.fromName(pathForThisPackage() + "/subpackage1", Origin.unknown()),
-        DataDirectoryResource.fromName(pathForThisPackage() + "/subpackage2", Origin.unknown()),
+        DataDirectoryResource.fromName("org/", Origin.unknown()),
+        DataDirectoryResource.fromName("org/example/", Origin.unknown()),
+        DataDirectoryResource.fromName("org/example/test/", Origin.unknown()),
+        DataDirectoryResource.fromName(pathForThisPackage() + '/', Origin.unknown()),
+        DataDirectoryResource.fromName(pathForThisPackage() + "/subpackage1/", Origin.unknown()),
+        DataDirectoryResource.fromName(pathForThisPackage() + "/subpackage2/", Origin.unknown()),
         DataDirectoryResource.fromName(
-            pathForThisPackage() + "/subpackage2/subpackage", Origin.unknown()));
+            pathForThisPackage() + "/subpackage2/subpackage/", Origin.unknown()));
   }
 }
diff --git a/src/test/java/com/android/tools/r8/retrace/RetraceCompanionWithPreambleTest.java b/src/test/java/com/android/tools/r8/retrace/RetraceCompanionWithPreambleTest.java
index 50d4ce0..eb44cbd 100644
--- a/src/test/java/com/android/tools/r8/retrace/RetraceCompanionWithPreambleTest.java
+++ b/src/test/java/com/android/tools/r8/retrace/RetraceCompanionWithPreambleTest.java
@@ -7,7 +7,6 @@
 import static com.android.tools.r8.naming.retrace.StackTrace.isSameExceptForFileNameAndLineNumber;
 import static org.hamcrest.CoreMatchers.containsString;
 import static org.hamcrest.MatcherAssert.assertThat;
-import static org.junit.Assume.assumeTrue;
 
 import com.android.tools.r8.SingleTestRunResult;
 import com.android.tools.r8.TestBase;
@@ -53,8 +52,8 @@
 
   @Test
   public void testReference() throws Exception {
-    assumeTrue(parameters.isCfRuntime());
-    testForJvm()
+    parameters.assumeJvmTestParameters();
+    testForJvm(parameters)
         .addProgramClasses(Main.class, A.class)
         .addProgramClassFileData(getI())
         .run(parameters.getRuntime(), Main.class)
diff --git a/src/test/java/com/android/tools/r8/retrace/RetraceLambdaTest.java b/src/test/java/com/android/tools/r8/retrace/RetraceLambdaTest.java
index 11e53ef..eb871a6 100644
--- a/src/test/java/com/android/tools/r8/retrace/RetraceLambdaTest.java
+++ b/src/test/java/com/android/tools/r8/retrace/RetraceLambdaTest.java
@@ -27,6 +27,7 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
 import org.junit.runners.Parameterized.Parameters;
 
 @RunWith(Parameterized.class)
@@ -39,16 +40,13 @@
     return getTestParameters().withAllRuntimes().withAllApiLevelsAlsoForCf().build();
   }
 
-  private final TestParameters parameters;
-
-  public RetraceLambdaTest(TestParameters parameters) {
-    this.parameters = parameters;
-  }
+  @Parameter(0)
+  public TestParameters parameters;
 
   @Test
   public void testReference() throws Exception {
-    assumeTrue(parameters.isCfRuntime());
-    testForJvm()
+    parameters.assumeJvmTestParameters();
+    testForJvm(parameters)
         .addInnerClasses(getClass())
         .run(parameters.getRuntime(), Main.class)
         .apply(this::checkRunResult)
diff --git a/src/test/java/com/android/tools/r8/rewrite/assertions/AssertionConfigurationAssertionHandlerKotlinTestBase.java b/src/test/java/com/android/tools/r8/rewrite/assertions/AssertionConfigurationAssertionHandlerKotlinTestBase.java
index f6b6a9d..dd7ed39 100644
--- a/src/test/java/com/android/tools/r8/rewrite/assertions/AssertionConfigurationAssertionHandlerKotlinTestBase.java
+++ b/src/test/java/com/android/tools/r8/rewrite/assertions/AssertionConfigurationAssertionHandlerKotlinTestBase.java
@@ -4,7 +4,6 @@
 
 package com.android.tools.r8.rewrite.assertions;
 
-import static org.junit.Assume.assumeTrue;
 
 import com.android.tools.r8.KotlinTestBase;
 import com.android.tools.r8.KotlinTestParameters;
@@ -131,7 +130,7 @@
 
   @Test
   public void testD8() throws Exception {
-    assumeTrue(parameters.isDexRuntime());
+    parameters.assumeDexRuntime();
     testForD8()
         .apply(this::configureKotlinStdlib)
         .setMinApi(parameters)
diff --git a/src/test/java/com/android/tools/r8/rewrite/assertions/AssertionConfigurationAssertionHandlerTestBase.java b/src/test/java/com/android/tools/r8/rewrite/assertions/AssertionConfigurationAssertionHandlerTestBase.java
index 773d065..ccab095 100644
--- a/src/test/java/com/android/tools/r8/rewrite/assertions/AssertionConfigurationAssertionHandlerTestBase.java
+++ b/src/test/java/com/android/tools/r8/rewrite/assertions/AssertionConfigurationAssertionHandlerTestBase.java
@@ -4,7 +4,6 @@
 
 package com.android.tools.r8.rewrite.assertions;
 
-import static org.junit.Assume.assumeTrue;
 
 import com.android.tools.r8.R8TestBuilder;
 import com.android.tools.r8.TestBase;
@@ -55,8 +54,8 @@
 
   @Test
   public void testD8() throws Exception {
-    assumeTrue(parameters.isDexRuntime());
-    testForD8(parameters.getBackend())
+    parameters.assumeDexRuntime();
+    testForD8()
         .addProgramClasses(getAssertionHandlerClasses())
         .addProgramClasses(getTestClasses())
         .setMinApi(parameters)
diff --git a/src/test/java/com/android/tools/r8/rewrite/assertions/AssertionsConfigurationTest.java b/src/test/java/com/android/tools/r8/rewrite/assertions/AssertionsConfigurationTest.java
index 05c3861..e8001a8 100644
--- a/src/test/java/com/android/tools/r8/rewrite/assertions/AssertionsConfigurationTest.java
+++ b/src/test/java/com/android/tools/r8/rewrite/assertions/AssertionsConfigurationTest.java
@@ -433,7 +433,7 @@
   public void testInnerClassForJvm() throws Exception {
     Assume.assumeTrue(parameters.isCfRuntime());
     // Pointing to the outer class enables assertions for the inner as well.
-    testForJvm()
+    testForJvm(parameters)
         .addProgramClasses(TestClassForInnerClass.class, TestClassForInnerClass.InnerClass.class)
         .addVmArguments("-ea:" + TestClassForInnerClass.class.getCanonicalName())
         .run(parameters.getRuntime(), TestClassForInnerClass.class)
@@ -443,12 +443,12 @@
             "DONE");
 
     // Pointing to the inner class enables no assertions.
-    testForJvm()
+    testForJvm(parameters)
         .addProgramClasses(TestClassForInnerClass.class, TestClassForInnerClass.InnerClass.class)
         .addVmArguments("-ea:" + TestClassForInnerClass.InnerClass.class.getCanonicalName())
         .run(parameters.getRuntime(), TestClassForInnerClass.class)
         .assertSuccessWithOutputLines("DONE");
-    testForJvm()
+    testForJvm(parameters)
         .addProgramClasses(TestClassForInnerClass.class, TestClassForInnerClass.InnerClass.class)
         .addVmArguments("-ea:" + TestClassForInnerClass.InnerClass.class.getTypeName())
         .run(parameters.getRuntime(), TestClassForInnerClass.class)
diff --git a/src/test/java/com/android/tools/r8/rewrite/assertions/RemoveAssertionsTest.java b/src/test/java/com/android/tools/r8/rewrite/assertions/RemoveAssertionsTest.java
index e5e3b29..fc880c9 100644
--- a/src/test/java/com/android/tools/r8/rewrite/assertions/RemoveAssertionsTest.java
+++ b/src/test/java/com/android/tools/r8/rewrite/assertions/RemoveAssertionsTest.java
@@ -369,7 +369,7 @@
 
   @Test
   public void testD8() throws Exception {
-    assumeTrue(parameters.isDexRuntime());
+    parameters.assumeDexRuntime();
     checkResultWithAssertionsInactive(
         compileD8(builder -> builder.setCompileTimeDisable().setScopeAll().build()));
     checkResultWithAssertionsInactive(
diff --git a/src/test/java/com/android/tools/r8/rewrite/switches/SwitchRewritingJarTest.java b/src/test/java/com/android/tools/r8/rewrite/switches/SwitchRewritingJarTest.java
index 4f53fe2..db1c18b 100644
--- a/src/test/java/com/android/tools/r8/rewrite/switches/SwitchRewritingJarTest.java
+++ b/src/test/java/com/android/tools/r8/rewrite/switches/SwitchRewritingJarTest.java
@@ -5,14 +5,16 @@
 
 import static org.junit.Assert.assertEquals;
 
-import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.R8TestCompileResult;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
 import com.android.tools.r8.jasmin.JasminBuilder;
 import com.android.tools.r8.jasmin.JasminTestBase;
-import com.android.tools.r8.naming.MemberNaming.MethodSignature;
-import com.android.tools.r8.utils.AndroidApp;
+import com.android.tools.r8.utils.AndroidApiLevel;
 import com.android.tools.r8.utils.StringUtils;
 import com.android.tools.r8.utils.codeinspector.CodeInspector;
 import com.android.tools.r8.utils.codeinspector.InstructionSubject;
+import com.android.tools.r8.utils.codeinspector.MethodSubject;
 import com.google.common.collect.ImmutableList;
 import java.util.Iterator;
 import java.util.List;
@@ -20,19 +22,18 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
 
 @RunWith(Parameterized.class)
 public class SwitchRewritingJarTest extends JasminTestBase {
 
-  private Backend backend;
+  @Parameter(0)
+  public TestParameters parameters;
 
-  @Parameterized.Parameters(name = "Backend: {0}")
-  public static Backend[] data() {
-    return ToolHelper.getBackends();
-  }
-
-  public SwitchRewritingJarTest(Backend backend) {
-    this.backend = backend;
+  @Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withDefaultRuntimes().withApiLevel(AndroidApiLevel.B).build();
   }
 
   static class Statistics {
@@ -71,8 +72,9 @@
     }
   }
 
-  private Statistics countInstructions(Iterator<InstructionSubject> iterator) {
+  private Statistics countInstructions(MethodSubject methodSubject) {
     Statistics statistics = new Statistics();
+    Iterator<InstructionSubject> iterator = methodSubject.iterateInstructions();
     while (iterator.hasNext()) {
       InstructionSubject instruction = iterator.next();
       if (instruction.isIf()) {
@@ -127,19 +129,18 @@
         "    invokevirtual java/io/PrintStream/print(I)V",
         "    return");
 
-    AndroidApp app =
-        ToolHelper.runR8(
-            ToolHelper.prepareR8CommandBuilder(builder.build(), emptyConsumer(backend))
-                .setDisableTreeShaking(true)
-                .setDisableMinification(true)
-                .addLibraryFiles(runtimeJar(backend))
-                .build());
-
-    Iterator<InstructionSubject> iterator =
-        getMethodSubject(app, "Test", new MethodSignature("test", "int", ImmutableList.of("int")))
-            .iterateInstructions();
-    Statistics stat = countInstructions(iterator);
-    assertEquals(new Statistics(1, 0, 0), stat);
+    testForR8(parameters.getBackend())
+        .addProgramClassFileData(builder.buildClasses())
+        .addDontObfuscate()
+        .addDontShrink()
+        .setMinApi(parameters)
+        .compile()
+        .inspect(
+            inspector -> {
+              Statistics stat =
+                  countInstructions(inspector.clazz("Test").uniqueMethodWithOriginalName("test"));
+              assertEquals(new Statistics(1, 0, 0), stat);
+            });
   }
 
   @Test
@@ -197,18 +198,17 @@
         "    invokevirtual java/io/PrintStream/print(I)V",
         "    return");
 
-    AndroidApp app =
-        ToolHelper.runR8(
-            ToolHelper.prepareR8CommandBuilder(builder.build(), emptyConsumer(backend))
-                .setDisableTreeShaking(true)
-                .setDisableMinification(true)
-                .addLibraryFiles(runtimeJar(backend))
-                .build());
-
-    MethodSignature signature = new MethodSignature("test", "int", ImmutableList.of("int"));
+    CodeInspector inspector =
+        testForR8(parameters.getBackend())
+            .addProgramClassFileData(builder.buildClasses())
+            .addDontObfuscate()
+            .addDontShrink()
+            .setMinApi(parameters)
+            .compile()
+            .inspector();
 
     Statistics stat =
-        countInstructions(getMethodSubject(app, "Test", signature).iterateInstructions());
+        countInstructions(inspector.clazz("Test").uniqueMethodWithOriginalName("test"));
 
     int expectedIfCount = 0;
     int expectedPackedSwitchCount, expectedSparseSwitchCount;
@@ -219,7 +219,7 @@
       expectedPackedSwitchCount = 0;
       expectedSparseSwitchCount = 1;
     }
-    if (backend == Backend.DEX
+    if (parameters.isDexRuntime()
         && additionalLastKey != null
         && additionalLastKey == Integer.MAX_VALUE) {
       expectedIfCount = 1;
@@ -244,7 +244,7 @@
     // This is the maximal value possible with Jasmin with the generated code above. It depends on
     // the source, so making smaller source can raise this limit. However we never get close to the
     // class file max.
-    int totalKeys = backend == Backend.CF ? 4376 : 5503;
+    int totalKeys = parameters.isCfRuntime() ? 4376 : 5503;
     runLargerSwitchJarTest(0, 1, totalKeys, null);
   }
 
@@ -281,36 +281,27 @@
         "    ireturn");
 
     // Add the Jasmin class and a class from Java source with the main method.
-    AndroidApp.Builder appBuilder = AndroidApp.builder();
-    appBuilder.addClassProgramData(builder.buildClasses());
-    appBuilder.addProgramFiles(ToolHelper.getClassFileForTestClass(CheckSwitchInTestClass.class));
-    AndroidApp app =
-        ToolHelper.runR8(
-            ToolHelper.prepareR8CommandBuilder(appBuilder.build(), emptyConsumer(backend))
-                .setDisableTreeShaking(true)
-                .setDisableMinification(true)
-                .addLibraryFiles(runtimeJar(backend))
-                .build());
+    R8TestCompileResult compileResult =
+        testForR8(parameters.getBackend())
+            .addProgramClasses(CheckSwitchInTestClass.class)
+            .addProgramClassFileData(builder.buildClasses())
+            .addDontObfuscate()
+            .addDontShrink()
+            .setMinApi(parameters)
+            .compile();
 
-    CodeInspector inspector = new CodeInspector(app);
     Statistics stat =
         countInstructions(
-            inspector
-                .clazz("Test")
-                .method("int", "test", ImmutableList.of("int"))
-                .iterateInstructions());
+            compileResult.inspector().clazz("Test").uniqueMethodWithOriginalName("test"));
 
     assertEquals(new Statistics(expectedIfs, expectedPackedSwitches, expectedSparseSwitches), stat);
 
     // Run the code
     List<String> args = keys.stream().map(Object::toString).collect(Collectors.toList());
     args.add(Integer.toString(defaultValue));
-    if (backend == Backend.DEX) {
-      runOnArt(app, CheckSwitchInTestClass.class, args);
-    } else {
-      assert backend == Backend.CF;
-      runOnJava(app, CheckSwitchInTestClass.class, args);
-    }
+    compileResult
+        .run(parameters.getRuntime(), CheckSwitchInTestClass.class, args.toArray(new String[0]))
+        .assertSuccess();
   }
 
   @Test
@@ -320,7 +311,7 @@
     runConvertCasesToIf(ImmutableList.of(0, 1000, 2000), -100, 3, 0, 0);
     runConvertCasesToIf(ImmutableList.of(0, 1000, 2000, 3000), -100, 4, 0, 0);
     runConvertCasesToIf(ImmutableList.of(0, 1, 2), -100, 3, 0, 0);
-    if (backend == Backend.DEX) {
+    if (parameters.isDexRuntime()) {
       runConvertCasesToIf(ImmutableList.of(1000, 2000, 3000, 4000, 5000), -100, 5, 0, 0);
       runConvertCasesToIf(ImmutableList.of(0, 1, 2, 3), -100, 4, 0, 0);
       runConvertCasesToIf(ImmutableList.of(0, 1, 2, 3, 4), -100, 5, 0, 0);
@@ -347,7 +338,7 @@
         -100, 2, 1, 0);
 
     // Switches that are completely converted to a combination of ifs and switches.
-    if (backend == Backend.DEX) {
+    if (parameters.isDexRuntime()) {
       runConvertCasesToIf(
           ImmutableList.of(100, 200, 300, 400, 500, 600, 700, 800, 900, 1000), -100, 10, 0, 0);
       runConvertCasesToIf(
@@ -386,7 +377,7 @@
     // Switches that hit maximum number of switchs and ifs.
     runConvertCasesToIf(
         ImmutableList.of(100, 200, 300, 400, 500, 600, 700, 800, 900, 1000, 1100), -100, 0, 0, 1);
-    if (backend == Backend.DEX) {
+    if (parameters.isDexRuntime()) {
       runConvertCasesToIf(
           ImmutableList.of(
               0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
diff --git a/src/test/java/com/android/tools/r8/rewrite/switchmaps/RewriteSwitchMapsTest.java b/src/test/java/com/android/tools/r8/rewrite/switchmaps/RewriteSwitchMapsTest.java
index c6c5cc2..98d8604 100644
--- a/src/test/java/com/android/tools/r8/rewrite/switchmaps/RewriteSwitchMapsTest.java
+++ b/src/test/java/com/android/tools/r8/rewrite/switchmaps/RewriteSwitchMapsTest.java
@@ -8,6 +8,7 @@
 
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
 import com.android.tools.r8.ToolHelper;
 import com.android.tools.r8.utils.AndroidApiLevel;
 import com.google.common.collect.ImmutableList;
@@ -16,21 +17,18 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
 
 @RunWith(Parameterized.class)
 public class RewriteSwitchMapsTest extends TestBase {
 
-  private final Backend backend;
+  @Parameter(0)
+  public TestParameters parameters;
 
-  @Parameterized.Parameters(name = "{0}, backend: {1}")
-  public static List<Object[]> data() {
-    return buildParameters(
-        TestParameters.builder().withNoneRuntime().build(), ToolHelper.getBackends());
-  }
-
-  public RewriteSwitchMapsTest(TestParameters parameters, Backend backend) {
-    parameters.assertNoneRuntime();
-    this.backend = backend;
+  @Parameters(name = "{0}, {1}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withDefaultRuntimes().withApiLevel(AndroidApiLevel.B).build();
   }
 
   private static final String JAR_FILE = "switchmaps.jar";
@@ -42,14 +40,11 @@
 
   @Test
   public void checkSwitchMapsRemoved() throws Exception {
-    testForR8(backend)
+    testForR8(parameters.getBackend())
         .addProgramFiles(Paths.get(ToolHelper.EXAMPLES_BUILD_DIR).resolve(JAR_FILE))
         .addKeepRules(PG_CONFIG)
-        .setMinApi(AndroidApiLevel.B)
+        .setMinApi(parameters)
         .compile()
-        .inspect(
-            inspector -> {
-              assertThat(inspector.clazz(SWITCHMAP_CLASS_NAME), isAbsent());
-            });
+        .inspect(inspector -> assertThat(inspector.clazz(SWITCHMAP_CLASS_NAME), isAbsent()));
   }
 }
diff --git a/src/test/java/com/android/tools/r8/shaking/AtomicFieldUpdaterTest.java b/src/test/java/com/android/tools/r8/shaking/AtomicFieldUpdaterTest.java
index 7015177..e8146c2 100644
--- a/src/test/java/com/android/tools/r8/shaking/AtomicFieldUpdaterTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/AtomicFieldUpdaterTest.java
@@ -6,69 +6,72 @@
 
 import static com.android.tools.r8.utils.codeinspector.Matchers.isPresentAndRenamed;
 import static org.hamcrest.MatcherAssert.assertThat;
-import static org.junit.Assert.assertEquals;
 
-import com.android.tools.r8.StringConsumer.FileConsumer;
 import com.android.tools.r8.TestBase;
-import com.android.tools.r8.ToolHelper;
-import com.android.tools.r8.utils.AndroidApp;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.utils.StringUtils;
 import com.android.tools.r8.utils.codeinspector.ClassSubject;
-import com.android.tools.r8.utils.codeinspector.CodeInspector;
-import java.io.File;
-import java.nio.file.Path;
 import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
 import org.junit.runners.Parameterized.Parameters;
 
 @RunWith(Parameterized.class)
 public class AtomicFieldUpdaterTest extends TestBase {
 
-  private final Backend backend;
+  private static final String EXPECTED_OUTPUT = StringUtils.lines("Test succeeded");
 
-  @Parameters(name = "backend: {0}")
-  public static Backend[] data() {
-    return ToolHelper.getBackends();
-  }
+  @Parameter(0)
+  public TestParameters parameters;
 
-  public AtomicFieldUpdaterTest(Backend backend) {
-    this.backend = backend;
+  @Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withAllRuntimesAndApiLevels().build();
   }
 
   @Test
-  public void test() throws Exception {
-    AndroidApp input =
-        readClasses(AtomicFieldUpdaterTestClass.class, AtomicFieldUpdaterTestClass.A.class);
-    Path proguardMapPath = File.createTempFile("mapping", ".txt", temp.getRoot()).toPath();
-    AndroidApp output =
-        compileWithR8(
-            input,
-            keepMainProguardConfiguration(AtomicFieldUpdaterTestClass.class),
-            options -> options.proguardMapConsumer = new FileConsumer(proguardMapPath),
-            backend);
-    // Verify that the field is still there.
-    CodeInspector inspector = new CodeInspector(output, proguardMapPath);
-    ClassSubject classSubject = inspector.clazz(AtomicFieldUpdaterTestClass.A.class.getName());
-    assertThat(classSubject, isPresentAndRenamed());
-    assertThat(classSubject.field("int", "field"), isPresentAndRenamed());
-    // Check that the code runs.
-    assertEquals(
-        runOnJava(AtomicFieldUpdaterTestClass.class),
-        runOnVM(output, AtomicFieldUpdaterTestClass.class.getName(), backend));
-  }
-}
-
-class AtomicFieldUpdaterTestClass {
-
-  public static void main(String[] args) {
-    // Throws NoSuchFieldException if field is removed by tree shaking, or if the string "field" is
-    // not renamed as a result of minification.
-    AtomicIntegerFieldUpdater.newUpdater(AtomicFieldUpdaterTestClass.A.class, "field");
-    System.out.println("Test succeeded");
+  public void testJvm() throws Exception {
+    parameters.assumeJvmTestParameters();
+    testForJvm(parameters)
+        .addTestClasspath()
+        .run(parameters.getRuntime(), AtomicFieldUpdaterTestClass.class)
+        .assertSuccessWithOutput(EXPECTED_OUTPUT);
   }
 
-  static class A {
-    volatile int field;
+  @Test
+  public void testR8() throws Exception {
+    testForR8(parameters.getBackend())
+        .addInnerClasses(getClass())
+        .addKeepMainRule(AtomicFieldUpdaterTestClass.class)
+        .setMinApi(parameters)
+        .compile()
+        .inspect(
+            inspector -> {
+              // Verify that the field is still there.
+              ClassSubject classSubject =
+                  inspector.clazz(AtomicFieldUpdaterTestClass.A.class.getName());
+              assertThat(classSubject, isPresentAndRenamed());
+              assertThat(classSubject.field("int", "field"), isPresentAndRenamed());
+            })
+        .run(parameters.getRuntime(), AtomicFieldUpdaterTestClass.class)
+        .assertSuccessWithOutput(EXPECTED_OUTPUT);
+  }
+
+  static class AtomicFieldUpdaterTestClass {
+
+    public static void main(String[] args) {
+      // Throws NoSuchFieldException if field is removed by tree shaking, or if the string "field"
+      // is
+      // not renamed as a result of minification.
+      AtomicIntegerFieldUpdater.newUpdater(AtomicFieldUpdaterTestClass.A.class, "field");
+      System.out.println("Test succeeded");
+    }
+
+    static class A {
+      volatile int field;
+    }
   }
 }
diff --git a/src/test/java/com/android/tools/r8/shaking/InstantiatedLambdaReceiverTest.java b/src/test/java/com/android/tools/r8/shaking/InstantiatedLambdaReceiverTest.java
index 7d02ea9..7385d79 100644
--- a/src/test/java/com/android/tools/r8/shaking/InstantiatedLambdaReceiverTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/InstantiatedLambdaReceiverTest.java
@@ -4,7 +4,6 @@
 
 package com.android.tools.r8.shaking;
 
-import static org.junit.Assume.assumeTrue;
 
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
@@ -31,8 +30,8 @@
 
   @Test
   public void jvmTest() throws Exception {
-    assumeTrue(parameters.isCfRuntime());
-    testForJvm()
+    parameters.assumeJvmTestParameters();
+    testForJvm(parameters)
         .addTestClasspath()
         .run(parameters.getRuntime(), TestClass.class)
         .assertSuccessWithOutput(expectedOutput);
diff --git a/src/test/java/com/android/tools/r8/shaking/InvalidTypesTest.java b/src/test/java/com/android/tools/r8/shaking/InvalidTypesTest.java
index 6734ad6..c67394a 100644
--- a/src/test/java/com/android/tools/r8/shaking/InvalidTypesTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/InvalidTypesTest.java
@@ -262,7 +262,9 @@
 
     if (parameters.isCfRuntime()) {
       TestRunResult<?> jvmResult =
-          testForJvm().addClasspath(inputJar).run(parameters.getRuntime(), mainClass.name);
+          testForJvm(parameters)
+              .addClasspath(inputJar)
+              .run(parameters.getRuntime(), mainClass.name);
       checkTestRunResult(jvmResult, Compiler.JAVAC);
 
       ProguardTestRunResult proguardResult =
diff --git a/src/test/java/com/android/tools/r8/shaking/ProguardDirectoryInputsTest.java b/src/test/java/com/android/tools/r8/shaking/ProguardDirectoryInputsTest.java
index d74b5ae..a6d9dbb 100644
--- a/src/test/java/com/android/tools/r8/shaking/ProguardDirectoryInputsTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/ProguardDirectoryInputsTest.java
@@ -62,7 +62,7 @@
       consumer.finished(null);
     }
     if (parameters.isCfRuntime()) {
-      testForJvm()
+      testForJvm(parameters)
           .addProgramClasses(TestClass.class)
           .addClasspath(directory)
           .run(parameters.getRuntime(), TestClass.class)
diff --git a/src/test/java/com/android/tools/r8/shaking/ReturnTypeTest.java b/src/test/java/com/android/tools/r8/shaking/ReturnTypeTest.java
index 3133746..ea24ce8 100644
--- a/src/test/java/com/android/tools/r8/shaking/ReturnTypeTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/ReturnTypeTest.java
@@ -66,7 +66,7 @@
   @Test
   public void testJVMOutput() throws Exception {
     parameters.assumeJvmTestParameters();
-    testForJvm()
+    testForJvm(parameters)
         .addTestClasspath()
         .run(parameters.getRuntime(), MAIN)
         .assertSuccessWithOutput(JAVA_OUTPUT);
diff --git a/src/test/java/com/android/tools/r8/shaking/annotations/AnnotationsOnFieldsTest.java b/src/test/java/com/android/tools/r8/shaking/annotations/AnnotationsOnFieldsTest.java
index 2f5eab9..17d3a91 100644
--- a/src/test/java/com/android/tools/r8/shaking/annotations/AnnotationsOnFieldsTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/annotations/AnnotationsOnFieldsTest.java
@@ -10,7 +10,8 @@
 import com.android.tools.r8.NeverClassInline;
 import com.android.tools.r8.NoHorizontalClassMerging;
 import com.android.tools.r8.TestBase;
-import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
 import com.android.tools.r8.utils.codeinspector.ClassSubject;
 import com.android.tools.r8.utils.codeinspector.FieldSubject;
 import com.google.common.collect.ImmutableList;
@@ -20,6 +21,8 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
 
 @RunWith(Parameterized.class)
 public class AnnotationsOnFieldsTest extends TestBase {
@@ -33,20 +36,17 @@
           TestClass.class,
           MainClass.class);
 
-  private final Backend backend;
+  @Parameter(0)
+  public TestParameters parameters;
 
-  @Parameterized.Parameters(name = "Backend: {0}")
-  public static Backend[] data() {
-    return ToolHelper.getBackends();
-  }
-
-  public AnnotationsOnFieldsTest(Backend backend) {
-    this.backend = backend;
+  @Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withAllRuntimesAndApiLevels().build();
   }
 
   @Test
   public void test() throws Exception {
-    testForR8Compat(backend)
+    testForR8Compat(parameters.getBackend())
         .enableNeverClassInliningAnnotations()
         .addProgramClasses(CLASSES)
         .addKeepMainRule(MainClass.class)
@@ -56,6 +56,7 @@
             "-keepattributes *Annotation*")
         .enableSideEffectAnnotations()
         .enableNoHorizontalClassMergingAnnotations()
+        .setMinApi(parameters)
         .compile()
         .inspect(
             inspector -> {
@@ -74,7 +75,7 @@
                   staticField.annotation(StaticFieldAnnotation.class.getTypeName()), isPresent());
               assertThat(inspector.clazz(StaticFieldAnnotationUse.class), isPresentAndRenamed());
             })
-        .run(MainClass.class)
+        .run(parameters.getRuntime(), MainClass.class)
         .assertSuccess();
   }
 
diff --git a/src/test/java/com/android/tools/r8/shaking/annotations/AnnotationsOnTargetedMethodTest.java b/src/test/java/com/android/tools/r8/shaking/annotations/AnnotationsOnTargetedMethodTest.java
index 0524037..674e3dc 100644
--- a/src/test/java/com/android/tools/r8/shaking/annotations/AnnotationsOnTargetedMethodTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/annotations/AnnotationsOnTargetedMethodTest.java
@@ -66,7 +66,7 @@
     // No need to run R8 compat mode with extra -keep,allowshrinking rule.
     assumeTrue(!enableProguardCompatibilityMode || !keepAllowShrinking);
     if (parameters.isCfRuntime()) {
-      testForJvm()
+      testForJvm(parameters)
           .addTestClasspath()
           .run(parameters.getRuntime(), TestClass.class)
           .assertSuccessWithOutput(expectedOutput);
diff --git a/src/test/java/com/android/tools/r8/shaking/array/DeadArrayLengthTest.java b/src/test/java/com/android/tools/r8/shaking/array/DeadArrayLengthTest.java
index 71f9761..ac4e734 100644
--- a/src/test/java/com/android/tools/r8/shaking/array/DeadArrayLengthTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/array/DeadArrayLengthTest.java
@@ -6,7 +6,6 @@
 import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.junit.Assert.assertEquals;
-import static org.junit.Assume.assumeTrue;
 
 import com.android.tools.r8.NeverInline;
 import com.android.tools.r8.NeverPropagateValue;
@@ -61,7 +60,7 @@
 
   @Test
   public void testD8() throws Exception {
-    assumeTrue(parameters.isDexRuntime());
+    parameters.assumeDexRuntime();
     testForD8()
         .release()
         .addProgramClasses(MAIN)
diff --git a/src/test/java/com/android/tools/r8/shaking/assumenosideeffects/AssumenosideeffectsPropagationTest.java b/src/test/java/com/android/tools/r8/shaking/assumenosideeffects/AssumenosideeffectsPropagationTest.java
index 9f5eed2..845e598 100644
--- a/src/test/java/com/android/tools/r8/shaking/assumenosideeffects/AssumenosideeffectsPropagationTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/assumenosideeffects/AssumenosideeffectsPropagationTest.java
@@ -124,7 +124,7 @@
     assumeTrue(parameters.isCfRuntime());
     assumeTrue(config == TestConfig.SPECIFIC_RULES);
     assumeFalse(enableHorizontalClassMerging);
-    testForJvm()
+    testForJvm(parameters)
         .addTestClasspath()
         .run(parameters.getRuntime(), MAIN)
         .assertSuccessWithOutputLines(
diff --git a/src/test/java/com/android/tools/r8/shaking/assumevalues/SynthesizedRulesFromApiLevelTest.java b/src/test/java/com/android/tools/r8/shaking/assumevalues/SynthesizedRulesFromApiLevelTest.java
index ee49eb3..c61b850 100644
--- a/src/test/java/com/android/tools/r8/shaking/assumevalues/SynthesizedRulesFromApiLevelTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/assumevalues/SynthesizedRulesFromApiLevelTest.java
@@ -9,6 +9,7 @@
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
+import static org.junit.Assume.assumeTrue;
 
 import com.android.tools.r8.D8;
 import com.android.tools.r8.D8Command;
@@ -16,9 +17,10 @@
 import com.android.tools.r8.R8FullTestBuilder;
 import com.android.tools.r8.R8TestBuilder;
 import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
 import com.android.tools.r8.ThrowableConsumer;
-import com.android.tools.r8.ToolHelper;
-import com.android.tools.r8.ToolHelper.DexVm;
+import com.android.tools.r8.ToolHelper.DexVm.Version;
 import com.android.tools.r8.jasmin.JasminBuilder;
 import com.android.tools.r8.jasmin.JasminBuilder.ClassBuilder;
 import com.android.tools.r8.shaking.ProguardAssumeNoSideEffectRule;
@@ -30,26 +32,24 @@
 import com.google.common.collect.ImmutableList;
 import java.nio.file.Path;
 import java.util.List;
-import org.junit.Assume;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
 import org.junit.runners.Parameterized.Parameters;
 
 @RunWith(Parameterized.class)
 public class SynthesizedRulesFromApiLevelTest extends TestBase {
 
-  private final Backend backend;
-  private final String mainClassName = "MainClass";
-  private final String compatLibraryClassName = "CompatLibrary";
+  private static final String mainClassName = "MainClass";
+  private static final String compatLibraryClassName = "CompatLibrary";
 
-  public SynthesizedRulesFromApiLevelTest(Backend backend) {
-    this.backend = backend;
-  }
+  @Parameter(0)
+  public TestParameters parameters;
 
-  @Parameters(name = "Backend: {0}")
-  public static Backend[] data() {
-    return ToolHelper.getBackends();
+  @Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withDefaultRuntimes().build();
   }
 
   // Simple mock implementation of class android.os.Build$VERSION with just the SDK_INT field.
@@ -165,9 +165,9 @@
       SynthesizedRule synthesizedRule)
       throws Exception {
     assertTrue(runtimeApiLevel.getLevel() >= buildApiLevel.getLevel());
-    if (backend == Backend.DEX) {
+    if (parameters.isDexRuntime()) {
       Path androidRuntimeLibraryMock = mockAndroidRuntimeLibrary(runtimeApiLevel);
-      testForR8(backend)
+      testForR8(parameters.getBackend())
           .setMinApi(buildApiLevel)
           .addProgramFiles(buildApp(nativeApiLevel))
           .addClasspathFiles(androidRuntimeLibraryMock)
@@ -182,12 +182,11 @@
                   checkSynthesizedRuleExpectation(syntheticProguardRules, synthesizedRule))
           .inspect(inspector)
           .addRunClasspathFiles(buildMockAndroidRuntimeLibrary(androidRuntimeLibraryMock))
-          .run(mainClassName)
+          .run(parameters.getRuntime(), mainClassName)
           .assertSuccessWithOutput(expectedOutput);
     } else {
-      assert backend == Backend.CF;
       Path androidRuntimeLibraryMock = mockAndroidRuntimeLibrary(AndroidApiLevel.D);
-      testForR8(backend)
+      testForR8(parameters.getBackend())
           .addProgramFiles(buildApp(nativeApiLevel))
           .addKeepMainRule(mainClassName)
           .addKeepRules(additionalKeepRules)
@@ -196,7 +195,7 @@
           .compile()
           .inspectSyntheticProguardRules(this::noSynthesizedRules)
           .addRunClasspathFiles(androidRuntimeLibraryMock)
-          .run(mainClassName)
+          .run(parameters.getRuntime(), mainClassName)
           .assertSuccessWithOutput(expectedResultForCompat(AndroidApiLevel.D));
     }
   }
@@ -241,7 +240,8 @@
 
   @Test
   public void testNoExplicitAssumeValuesRuleNative() throws Exception {
-    Assume.assumeTrue(ToolHelper.getDexVm().isNewerThan(DexVm.ART_7_0_0_HOST));
+    assumeTrue(
+        parameters.isCfRuntime() || parameters.getDexRuntimeVersion().isNewerThan(Version.V7_0_0));
     runTest(
         AndroidApiLevel.O_MR1,
         AndroidApiLevel.O_MR1,
@@ -252,7 +252,8 @@
 
   @Test
   public void testNoExplicitAssumeValuesRuleCompatPresent() throws Exception {
-    Assume.assumeTrue(ToolHelper.getDexVm().isNewerThan(DexVm.ART_7_0_0_HOST));
+    assumeTrue(
+        parameters.isCfRuntime() || parameters.getDexRuntimeVersion().isNewerThan(Version.V7_0_0));
     runTest(
         AndroidApiLevel.O,
         AndroidApiLevel.O_MR1,
@@ -263,7 +264,8 @@
 
   @Test
   public void testNoExplicitAssumeValuesRuleCompatUsed() throws Exception {
-    Assume.assumeTrue(ToolHelper.getDexVm().isNewerThan(DexVm.ART_7_0_0_HOST));
+    assumeTrue(
+        parameters.isCfRuntime() || parameters.getDexRuntimeVersion().isNewerThan(Version.V7_0_0));
     runTest(
         AndroidApiLevel.O,
         AndroidApiLevel.O,
@@ -274,7 +276,8 @@
 
   @Test
   public void testExplicitAssumeValuesRuleWhichMatchAndDontKeepCompat() throws Exception {
-    Assume.assumeTrue(ToolHelper.getDexVm().isNewerThan(DexVm.ART_7_0_0_HOST));
+    assumeTrue(
+        parameters.isCfRuntime() || parameters.getDexRuntimeVersion().isNewerThan(Version.V7_0_0));
     runTest(
         AndroidApiLevel.O_MR1,
         AndroidApiLevel.O_MR1,
@@ -282,7 +285,7 @@
         expectedResultForNative(AndroidApiLevel.O_MR1),
         builder -> {
           // android.os.Build$VERSION only exists in the Android runtime.
-          builder.allowUnusedProguardConfigurationRules(backend == Backend.CF);
+          builder.allowUnusedProguardConfigurationRules(parameters.isCfRuntime());
         },
         this::compatCodeNotPresent,
         ImmutableList.of(
@@ -294,7 +297,8 @@
 
   @Test
   public void testExplicitAssumeValuesRulesWhichMatchAndKeepCompat() throws Exception {
-    Assume.assumeTrue(ToolHelper.getDexVm().isNewerThan(DexVm.ART_7_0_0_HOST));
+    assumeTrue(
+        parameters.isCfRuntime() || parameters.getDexRuntimeVersion().isNewerThan(Version.V7_0_0));
     String[] rules =
         new String[] {
           "-assumevalues class android.os.Build$VERSION { int SDK_INT return 1..1000; }",
@@ -316,7 +320,7 @@
           expectedResultForNative(AndroidApiLevel.O_MR1),
           builder ->
               builder.allowUnusedProguardConfigurationRules(
-                  backend == Backend.CF || finalRuleIndex >= 4),
+                  parameters.isCfRuntime() || finalRuleIndex >= 4),
           this::compatCodePresent,
           ImmutableList.of(rule),
           SynthesizedRule.NOT_PRESENT);
@@ -325,7 +329,8 @@
 
   @Test
   public void testExplicitAssumeValuesRulesWhichDoesNotMatch() throws Exception {
-    Assume.assumeTrue(ToolHelper.getDexVm().isNewerThan(DexVm.ART_7_0_0_HOST));
+    assumeTrue(
+        parameters.isCfRuntime() || parameters.getDexRuntimeVersion().isNewerThan(Version.V7_0_0));
     String[] rules = new String[] {
         "-assumevalues class * { !public int SDK_INT return 1..1000; }",
         "-assumevalues class * { !static int SDK_INT return 1..1000; }",
diff --git a/src/test/java/com/android/tools/r8/shaking/clinit/InterfaceInitializedByInvokeStaticOnSubInterfaceTest.java b/src/test/java/com/android/tools/r8/shaking/clinit/InterfaceInitializedByInvokeStaticOnSubInterfaceTest.java
index 1177193..32da7369 100644
--- a/src/test/java/com/android/tools/r8/shaking/clinit/InterfaceInitializedByInvokeStaticOnSubInterfaceTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/clinit/InterfaceInitializedByInvokeStaticOnSubInterfaceTest.java
@@ -4,7 +4,6 @@
 
 package com.android.tools.r8.shaking.clinit;
 
-import static org.junit.Assume.assumeTrue;
 
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.TestParametersCollection;
@@ -53,8 +52,8 @@
 
   @Test
   public void testJvm() throws Exception {
-    assumeTrue(parameters.isCfRuntime());
-    testForJvm()
+    parameters.assumeJvmTestParameters();
+    testForJvm(parameters)
         .addTestClasspath()
         .run(parameters.getRuntime(), TestClass.class)
         .assertSuccessWithOutputLines("J");
diff --git a/src/test/java/com/android/tools/r8/shaking/clinit/InterfaceInitializedByInvokeStaticTest.java b/src/test/java/com/android/tools/r8/shaking/clinit/InterfaceInitializedByInvokeStaticTest.java
index 3613950..d483632 100644
--- a/src/test/java/com/android/tools/r8/shaking/clinit/InterfaceInitializedByInvokeStaticTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/clinit/InterfaceInitializedByInvokeStaticTest.java
@@ -4,7 +4,6 @@
 
 package com.android.tools.r8.shaking.clinit;
 
-import static org.junit.Assume.assumeTrue;
 
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.TestParametersCollection;
@@ -53,8 +52,8 @@
 
   @Test
   public void testJvm() throws Exception {
-    assumeTrue(parameters.isCfRuntime());
-    testForJvm()
+    parameters.assumeJvmTestParameters();
+    testForJvm(parameters)
         .addTestClasspath()
         .run(parameters.getRuntime(), TestClass.class)
         .assertSuccessWithOutputLines("I", "J");
diff --git a/src/test/java/com/android/tools/r8/shaking/clinit/InterfaceInitializedByStaticGetOnSubClassTest.java b/src/test/java/com/android/tools/r8/shaking/clinit/InterfaceInitializedByStaticGetOnSubClassTest.java
index 12dc078..9179aeb 100644
--- a/src/test/java/com/android/tools/r8/shaking/clinit/InterfaceInitializedByStaticGetOnSubClassTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/clinit/InterfaceInitializedByStaticGetOnSubClassTest.java
@@ -4,7 +4,6 @@
 
 package com.android.tools.r8.shaking.clinit;
 
-import static org.junit.Assume.assumeTrue;
 
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.TestParametersCollection;
@@ -32,7 +31,7 @@
 
   @Test
   public void testD8() throws Exception {
-    assumeTrue(parameters.isDexRuntime());
+    parameters.assumeDexRuntime();
     testForD8()
         .addInnerClasses(getClass())
         .setMinApi(parameters)
@@ -55,8 +54,8 @@
 
   @Test
   public void testJvm() throws Exception {
-    assumeTrue(parameters.isCfRuntime());
-    testForJvm()
+    parameters.assumeJvmTestParameters();
+    testForJvm(parameters)
         .addTestClasspath()
         .run(parameters.getRuntime(), TestClass.class)
         .assertSuccessWithOutputLines("A");
diff --git a/src/test/java/com/android/tools/r8/shaking/clinit/InterfaceInitializedByStaticGetOnSubInterfaceTest.java b/src/test/java/com/android/tools/r8/shaking/clinit/InterfaceInitializedByStaticGetOnSubInterfaceTest.java
index b123d58..beb7177 100644
--- a/src/test/java/com/android/tools/r8/shaking/clinit/InterfaceInitializedByStaticGetOnSubInterfaceTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/clinit/InterfaceInitializedByStaticGetOnSubInterfaceTest.java
@@ -4,7 +4,6 @@
 
 package com.android.tools.r8.shaking.clinit;
 
-import static org.junit.Assume.assumeTrue;
 
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.TestParametersCollection;
@@ -32,7 +31,7 @@
 
   @Test
   public void testD8() throws Exception {
-    assumeTrue(parameters.isDexRuntime());
+    parameters.assumeDexRuntime();
     testForD8()
         .addInnerClasses(getClass())
         .setMinApi(parameters)
@@ -55,8 +54,8 @@
 
   @Test
   public void testJvm() throws Exception {
-    assumeTrue(parameters.isCfRuntime());
-    testForJvm()
+    parameters.assumeJvmTestParameters();
+    testForJvm(parameters)
         .addTestClasspath()
         .run(parameters.getRuntime(), TestClass.class)
         .assertSuccessWithOutputLines("J");
diff --git a/src/test/java/com/android/tools/r8/shaking/clinit/InterfaceInitializedByStaticGetTest.java b/src/test/java/com/android/tools/r8/shaking/clinit/InterfaceInitializedByStaticGetTest.java
index f43cbc0..e9b3bb0 100644
--- a/src/test/java/com/android/tools/r8/shaking/clinit/InterfaceInitializedByStaticGetTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/clinit/InterfaceInitializedByStaticGetTest.java
@@ -4,7 +4,6 @@
 
 package com.android.tools.r8.shaking.clinit;
 
-import static org.junit.Assume.assumeTrue;
 
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.TestParametersCollection;
@@ -32,7 +31,7 @@
 
   @Test
   public void testD8() throws Exception {
-    assumeTrue(parameters.isDexRuntime());
+    parameters.assumeDexRuntime();
     testForD8()
         .addInnerClasses(getClass())
         .setMinApi(parameters)
@@ -55,8 +54,8 @@
 
   @Test
   public void testJvm() throws Exception {
-    assumeTrue(parameters.isCfRuntime());
-    testForJvm()
+    parameters.assumeJvmTestParameters();
+    testForJvm(parameters)
         .addTestClasspath()
         .run(parameters.getRuntime(), TestClass.class)
         .assertSuccessWithOutputLines("I");
diff --git a/src/test/java/com/android/tools/r8/shaking/clinit/InterfaceNotInitializedByInvokeStaticOnSubClassTest.java b/src/test/java/com/android/tools/r8/shaking/clinit/InterfaceNotInitializedByInvokeStaticOnSubClassTest.java
index e3dcdff..0eba914 100644
--- a/src/test/java/com/android/tools/r8/shaking/clinit/InterfaceNotInitializedByInvokeStaticOnSubClassTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/clinit/InterfaceNotInitializedByInvokeStaticOnSubClassTest.java
@@ -5,7 +5,6 @@
 package com.android.tools.r8.shaking.clinit;
 
 import static org.junit.Assert.assertEquals;
-import static org.junit.Assume.assumeTrue;
 
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.TestParametersCollection;
@@ -33,7 +32,7 @@
 
   @Test
   public void testD8() throws Exception {
-    assumeTrue(parameters.isDexRuntime());
+    parameters.assumeDexRuntime();
     testForD8()
         .addInnerClasses(getClass())
         .setMinApi(parameters)
@@ -57,8 +56,8 @@
 
   @Test
   public void testJvm() throws Exception {
-    assumeTrue(parameters.isCfRuntime());
-    testForJvm()
+    parameters.assumeJvmTestParameters();
+    testForJvm(parameters)
         .addTestClasspath()
         .run(parameters.getRuntime(), TestClass.class)
         .assertSuccessWithEmptyOutput();
diff --git a/src/test/java/com/android/tools/r8/shaking/clinit/InterfaceWithDefaultMethodInitializedByInvokeStaticOnSubClassTest.java b/src/test/java/com/android/tools/r8/shaking/clinit/InterfaceWithDefaultMethodInitializedByInvokeStaticOnSubClassTest.java
index d4c1c3b..b71a3a3 100644
--- a/src/test/java/com/android/tools/r8/shaking/clinit/InterfaceWithDefaultMethodInitializedByInvokeStaticOnSubClassTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/clinit/InterfaceWithDefaultMethodInitializedByInvokeStaticOnSubClassTest.java
@@ -4,7 +4,6 @@
 
 package com.android.tools.r8.shaking.clinit;
 
-import static org.junit.Assume.assumeTrue;
 
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.TestParametersCollection;
@@ -33,7 +32,7 @@
 
   @Test
   public void testD8() throws Exception {
-    assumeTrue(parameters.isDexRuntime());
+    parameters.assumeDexRuntime();
     testForD8()
         .addInnerClasses(getClass())
         .setMinApi(parameters)
@@ -71,8 +70,8 @@
 
   @Test
   public void testJvm() throws Exception {
-    assumeTrue(parameters.isCfRuntime());
-    testForJvm()
+    parameters.assumeJvmTestParameters();
+    testForJvm(parameters)
         .addTestClasspath()
         .run(parameters.getRuntime(), TestClass.class)
         .assertSuccessWithOutputLines("I");
diff --git a/src/test/java/com/android/tools/r8/shaking/clinit/InterfaceWithDefaultMethodInitializedByInvokeStaticOnSubInterfaceTest.java b/src/test/java/com/android/tools/r8/shaking/clinit/InterfaceWithDefaultMethodInitializedByInvokeStaticOnSubInterfaceTest.java
index 7ae4305..64da709 100644
--- a/src/test/java/com/android/tools/r8/shaking/clinit/InterfaceWithDefaultMethodInitializedByInvokeStaticOnSubInterfaceTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/clinit/InterfaceWithDefaultMethodInitializedByInvokeStaticOnSubInterfaceTest.java
@@ -4,7 +4,6 @@
 
 package com.android.tools.r8.shaking.clinit;
 
-import static org.junit.Assume.assumeTrue;
 
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.TestParametersCollection;
@@ -33,7 +32,7 @@
 
   @Test
   public void testD8() throws Exception {
-    assumeTrue(parameters.isDexRuntime());
+    parameters.assumeDexRuntime();
     testForD8()
         .addInnerClasses(getClass())
         .setMinApi(parameters)
@@ -56,8 +55,8 @@
 
   @Test
   public void testJvm() throws Exception {
-    assumeTrue(parameters.isCfRuntime());
-    testForJvm()
+    parameters.assumeJvmTestParameters();
+    testForJvm(parameters)
         .addTestClasspath()
         .run(parameters.getRuntime(), TestClass.class)
         .assertSuccessWithEmptyOutput();
diff --git a/src/test/java/com/android/tools/r8/shaking/clinit/InterfaceWithDefaultMethodInitializedByStaticGetOnSubClassTest.java b/src/test/java/com/android/tools/r8/shaking/clinit/InterfaceWithDefaultMethodInitializedByStaticGetOnSubClassTest.java
index 9f6e0c8..6358815 100644
--- a/src/test/java/com/android/tools/r8/shaking/clinit/InterfaceWithDefaultMethodInitializedByStaticGetOnSubClassTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/clinit/InterfaceWithDefaultMethodInitializedByStaticGetOnSubClassTest.java
@@ -4,7 +4,6 @@
 
 package com.android.tools.r8.shaking.clinit;
 
-import static org.junit.Assume.assumeTrue;
 
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.TestParametersCollection;
@@ -32,7 +31,7 @@
 
   @Test
   public void testD8() throws Exception {
-    assumeTrue(parameters.isDexRuntime());
+    parameters.assumeDexRuntime();
     testForD8()
         .addInnerClasses(getClass())
         .setMinApi(parameters)
@@ -70,8 +69,8 @@
 
   @Test
   public void testJvm() throws Exception {
-    assumeTrue(parameters.isCfRuntime());
-    testForJvm()
+    parameters.assumeJvmTestParameters();
+    testForJvm(parameters)
         .addTestClasspath()
         .run(parameters.getRuntime(), TestClass.class)
         .assertSuccessWithOutputLines("I", "A");
diff --git a/src/test/java/com/android/tools/r8/shaking/clinit/InterfaceWithDefaultMethodInitializedByStaticGetOnSubInterfaceTest.java b/src/test/java/com/android/tools/r8/shaking/clinit/InterfaceWithDefaultMethodInitializedByStaticGetOnSubInterfaceTest.java
index 6413582..f19eabc 100644
--- a/src/test/java/com/android/tools/r8/shaking/clinit/InterfaceWithDefaultMethodInitializedByStaticGetOnSubInterfaceTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/clinit/InterfaceWithDefaultMethodInitializedByStaticGetOnSubInterfaceTest.java
@@ -4,7 +4,6 @@
 
 package com.android.tools.r8.shaking.clinit;
 
-import static org.junit.Assume.assumeTrue;
 
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.TestParametersCollection;
@@ -33,7 +32,7 @@
 
   @Test
   public void testD8() throws Exception {
-    assumeTrue(parameters.isDexRuntime());
+    parameters.assumeDexRuntime();
     testForD8()
         .addInnerClasses(getClass())
         .setMinApi(parameters)
@@ -56,8 +55,8 @@
 
   @Test
   public void testJvm() throws Exception {
-    assumeTrue(parameters.isCfRuntime());
-    testForJvm()
+    parameters.assumeJvmTestParameters();
+    testForJvm(parameters)
         .addTestClasspath()
         .run(parameters.getRuntime(), TestClass.class)
         .assertSuccessWithOutputLines("J");
diff --git a/src/test/java/com/android/tools/r8/shaking/clinit/InterfaceWithDefaultMethodNotInitializedByInvokeStaticOnSubInterfaceTest.java b/src/test/java/com/android/tools/r8/shaking/clinit/InterfaceWithDefaultMethodNotInitializedByInvokeStaticOnSubInterfaceTest.java
index c5dfe9e..3edb693 100644
--- a/src/test/java/com/android/tools/r8/shaking/clinit/InterfaceWithDefaultMethodNotInitializedByInvokeStaticOnSubInterfaceTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/clinit/InterfaceWithDefaultMethodNotInitializedByInvokeStaticOnSubInterfaceTest.java
@@ -5,7 +5,6 @@
 package com.android.tools.r8.shaking.clinit;
 
 import static org.junit.Assert.assertEquals;
-import static org.junit.Assume.assumeTrue;
 
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.TestParametersCollection;
@@ -34,7 +33,7 @@
 
   @Test
   public void testD8() throws Exception {
-    assumeTrue(parameters.isDexRuntime());
+    parameters.assumeDexRuntime();
     testForD8()
         .addInnerClasses(getClass())
         .setMinApi(parameters)
@@ -58,8 +57,8 @@
 
   @Test
   public void testJvm() throws Exception {
-    assumeTrue(parameters.isCfRuntime());
-    testForJvm()
+    parameters.assumeJvmTestParameters();
+    testForJvm(parameters)
         .addTestClasspath()
         .run(parameters.getRuntime(), TestClass.class)
         .assertSuccessWithEmptyOutput();
diff --git a/src/test/java/com/android/tools/r8/shaking/constructor/InitMatchingTest.java b/src/test/java/com/android/tools/r8/shaking/constructor/InitMatchingTest.java
index 073003b..1590adf 100644
--- a/src/test/java/com/android/tools/r8/shaking/constructor/InitMatchingTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/constructor/InitMatchingTest.java
@@ -9,23 +9,25 @@
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.fail;
-import static org.junit.Assume.assumeTrue;
 
 import com.android.tools.r8.CompilationFailedException;
 import com.android.tools.r8.ProguardTestCompileResult;
+import com.android.tools.r8.ProguardVersion;
 import com.android.tools.r8.R8TestCompileResult;
 import com.android.tools.r8.TestBase;
-import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.utils.AndroidApiLevel;
 import com.android.tools.r8.utils.codeinspector.ClassSubject;
 import com.android.tools.r8.utils.codeinspector.CodeInspector;
 import com.android.tools.r8.utils.codeinspector.MethodSubject;
 import com.google.common.collect.ImmutableList;
-import java.util.Collection;
 import java.util.List;
 import org.junit.BeforeClass;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
 
 class InitMatchingTestClass {
   // Trivial <clinit>
@@ -46,18 +48,18 @@
       "public void <clinit>", "static void <clinit>", "XYZ <clinit>", "private XYZ <init>"
   );
 
-  @Parameterized.Parameters(name = "{0} \"{1}\"")
-  public static Collection<Object[]> data() {
-    return buildParameters(ToolHelper.getBackends(), INIT_NAMES);
+  @Parameters(name = "{0} \"{1}\"")
+  public static List<Object[]> data() {
+    return buildParameters(
+        getTestParameters().withDefaultRuntimes().withApiLevel(AndroidApiLevel.B).build(),
+        INIT_NAMES);
   }
 
-  private final Backend backend;
-  private final String initName;
+  @Parameter(0)
+  public TestParameters parameters;
 
-  public InitMatchingTest(Backend backend, String initName) {
-    this.backend = backend;
-    this.initName = initName;
-  }
+  @Parameter(1)
+  public String initName;
 
   private String createKeepRule() {
     return "-keep class * { " + initName + "(...); }";
@@ -83,11 +85,11 @@
 
   @Test
   public void testProguard() throws Exception {
-    assumeTrue(backend == Backend.CF);
+    parameters.assumeProguardTestParameters();
     ProguardTestCompileResult result;
     try {
       result =
-          testForProguard()
+          testForProguard(ProguardVersion.V6_0_1)
               .addProgramClasses(InitMatchingTestClass.class)
               .addKeepRules(createKeepRule())
               .compile();
@@ -144,9 +146,10 @@
     R8TestCompileResult result;
     try {
       result =
-          testForR8(backend)
+          testForR8(parameters.getBackend())
               .addProgramClasses(InitMatchingTestClass.class)
               .addKeepRules(createKeepRule())
+              .setMinApi(parameters)
               .compile();
       if (!ALLOWED_INIT_NAMES.contains(initName)) {
         fail("Expect to fail");
diff --git a/src/test/java/com/android/tools/r8/shaking/forceproguardcompatibility/defaultctor/ImplicitlyKeptDefaultConstructorTest.java b/src/test/java/com/android/tools/r8/shaking/forceproguardcompatibility/defaultctor/ImplicitlyKeptDefaultConstructorTest.java
index 7752712..c5fc066 100644
--- a/src/test/java/com/android/tools/r8/shaking/forceproguardcompatibility/defaultctor/ImplicitlyKeptDefaultConstructorTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/forceproguardcompatibility/defaultctor/ImplicitlyKeptDefaultConstructorTest.java
@@ -11,9 +11,11 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
 
-import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
 import com.android.tools.r8.shaking.forceproguardcompatibility.ProguardCompatibilityTestBase;
 import com.android.tools.r8.smali.ConstantFoldingTest.TriConsumer;
+import com.android.tools.r8.utils.AndroidApiLevel;
 import com.android.tools.r8.utils.codeinspector.ClassSubject;
 import com.android.tools.r8.utils.codeinspector.CodeInspector;
 import com.google.common.collect.ImmutableList;
@@ -21,6 +23,8 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
 
 class SuperClass {
 
@@ -98,15 +102,12 @@
 @RunWith(Parameterized.class)
 public class ImplicitlyKeptDefaultConstructorTest extends ProguardCompatibilityTestBase {
 
-  private Backend backend;
+  @Parameter(0)
+  public TestParameters parameters;
 
-  @Parameterized.Parameters(name = "Backend: {0}")
-  public static Backend[] data() {
-    return ToolHelper.getBackends();
-  }
-
-  public ImplicitlyKeptDefaultConstructorTest(Backend backend) {
-    this.backend = backend;
+  @Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withDefaultRuntimes().withApiLevel(AndroidApiLevel.B).build();
   }
 
   private void checkPresentWithDefaultConstructor(ClassSubject clazz) {
@@ -152,7 +153,7 @@
       TriConsumer<Class, List<Class<?>>, CodeInspector> proguardChecker)
       throws Exception {
     CodeInspector inspector =
-        inspectR8CompatResult(programClasses, proguardConfiguration, null, backend);
+        inspectR8CompatResult(programClasses, proguardConfiguration, null, parameters.getBackend());
     r8Checker.accept(mainClass, programClasses, inspector);
 
     if (isRunProguard()) {
diff --git a/src/test/java/com/android/tools/r8/shaking/forceproguardcompatibility/keepinterface/CompatKeepInterfaceAsInstantiatedTest.java b/src/test/java/com/android/tools/r8/shaking/forceproguardcompatibility/keepinterface/CompatKeepInterfaceAsInstantiatedTest.java
index c68e841..d931285 100644
--- a/src/test/java/com/android/tools/r8/shaking/forceproguardcompatibility/keepinterface/CompatKeepInterfaceAsInstantiatedTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/forceproguardcompatibility/keepinterface/CompatKeepInterfaceAsInstantiatedTest.java
@@ -117,7 +117,7 @@
   }
 
   private void testReference(Class<?> main) throws Exception {
-    testForJvm()
+    testForJvm(parameters)
         .addProgramClasses(main, Foo.class, Bar.class)
         .run(parameters.getRuntime(), main)
         .assertSuccessWithOutput(expected);
diff --git a/src/test/java/com/android/tools/r8/shaking/ifrule/IfOnTargetedMethodTest.java b/src/test/java/com/android/tools/r8/shaking/ifrule/IfOnTargetedMethodTest.java
index efba0d2..f5aba70 100644
--- a/src/test/java/com/android/tools/r8/shaking/ifrule/IfOnTargetedMethodTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/ifrule/IfOnTargetedMethodTest.java
@@ -24,19 +24,27 @@
 @RunWith(Parameterized.class)
 public class IfOnTargetedMethodTest extends TestBase {
 
+  private static final String EXPECTED_OUTPUT = StringUtils.lines("Hello world!");
+
   @Parameters(name = "{0}")
   public static TestParametersCollection data() {
     return getTestParameters().withAllRuntimes().withApiLevel(AndroidApiLevel.B).build();
   }
 
-  @Parameter public TestParameters parameters;
+  @Parameter(0)
+  public TestParameters parameters;
 
   @Test
-  public void test() throws Exception {
-    String expectedOutput = StringUtils.lines("Hello world!");
+  public void testJvm() throws Exception {
+    parameters.assumeJvmTestParameters();
+    testForJvm(parameters)
+        .addTestClasspath()
+        .run(parameters.getRuntime(), TestClass.class)
+        .assertSuccessWithOutput(EXPECTED_OUTPUT);
+  }
 
-    testForJvm().addTestClasspath().run(TestClass.class).assertSuccessWithOutput(expectedOutput);
-
+  @Test
+  public void testR8() throws Exception {
     CodeInspector inspector =
         testForR8(parameters.getBackend())
             .setMinApi(parameters)
@@ -46,7 +54,7 @@
                 "-if interface * { @" + MyAnnotation.class.getTypeName() + " <methods>; }",
                 "-keep,allowobfuscation interface <1>")
             .run(parameters.getRuntime(), TestClass.class)
-            .assertSuccessWithOutput(expectedOutput)
+            .assertSuccessWithOutput(EXPECTED_OUTPUT)
             .inspector();
 
     ClassSubject interfaceSubject = inspector.clazz(Interface.class);
diff --git a/src/test/java/com/android/tools/r8/shaking/ifrule/StaticFinalFieldInliningTest.java b/src/test/java/com/android/tools/r8/shaking/ifrule/StaticFinalFieldInliningTest.java
index 8149782..5f7d1f8 100644
--- a/src/test/java/com/android/tools/r8/shaking/ifrule/StaticFinalFieldInliningTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/ifrule/StaticFinalFieldInliningTest.java
@@ -51,7 +51,7 @@
                 ToolHelper.getSourceFileForTestClass(StaticFinalFieldInliningSource.class))
             .compile();
 
-    testForJvm()
+    testForJvm(parameters)
         .addProgramFiles(output)
         .run(parameters.getRuntime(), StaticFinalFieldInliningSource.class)
         .assertSuccessWithOutput(EXPECTED);
diff --git a/src/test/java/com/android/tools/r8/shaking/ifrule/classinlining/IfRuleWithClassInlining.java b/src/test/java/com/android/tools/r8/shaking/ifrule/classinlining/IfRuleWithClassInlining.java
index 165a160..35854ba 100644
--- a/src/test/java/com/android/tools/r8/shaking/ifrule/classinlining/IfRuleWithClassInlining.java
+++ b/src/test/java/com/android/tools/r8/shaking/ifrule/classinlining/IfRuleWithClassInlining.java
@@ -9,7 +9,8 @@
 import static org.hamcrest.MatcherAssert.assertThat;
 
 import com.android.tools.r8.TestBase;
-import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.utils.AndroidApiLevel;
 import com.android.tools.r8.utils.BooleanUtils;
 import com.android.tools.r8.utils.StringUtils;
 import com.android.tools.r8.utils.codeinspector.CodeInspector;
@@ -17,25 +18,27 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
 import org.junit.runners.Parameterized.Parameters;
 
 @RunWith(Parameterized.class)
 public class IfRuleWithClassInlining extends TestBase {
 
-  private final Backend backend;
-  private final boolean enableClassInlining;
-  private final boolean enableIfRule;
+  @Parameter(0)
+  public TestParameters parameters;
 
-  public IfRuleWithClassInlining(
-      Backend backend, boolean enableClassInlining, boolean enableIfRule) {
-    this.backend = backend;
-    this.enableClassInlining = enableClassInlining;
-    this.enableIfRule = enableIfRule;
-  }
+  @Parameter(1)
+  public boolean enableClassInlining;
 
-  @Parameters(name = "Backend: {0}, class inlining: {1}, with if rule: {2}")
+  @Parameter(2)
+  public boolean enableIfRule;
+
+  @Parameters(name = "{0}, class inlining: {1}, with if rule: {2}")
   public static List<Object[]> data() {
-    return buildParameters(ToolHelper.getBackends(), BooleanUtils.values(), BooleanUtils.values());
+    return buildParameters(
+        getTestParameters().withDefaultRuntimes().withApiLevel(AndroidApiLevel.B).build(),
+        BooleanUtils.values(),
+        BooleanUtils.values());
   }
 
   @Test
@@ -45,13 +48,14 @@
             "-if class " + StringBox.Builder.class.getTypeName(),
             "-keep class " + Unused.class.getTypeName());
     CodeInspector inspector =
-        testForR8(backend)
+        testForR8(parameters.getBackend())
             .addInnerClasses(IfRuleWithClassInlining.class)
             .addKeepMainRule(TestClass.class)
             .addKeepRules(enableIfRule ? ifRule : "")
             .addOptionsModification(options -> options.enableClassInlining = enableClassInlining)
             // TODO(b/120061431): Should not be needed for this example.
             .allowAccessModification()
+            .setMinApi(parameters)
             .compile()
             .inspector();
     if (enableIfRule || !enableClassInlining) {
diff --git a/src/test/java/com/android/tools/r8/shaking/ifrule/classstaticizer/IfRuleWithClassStaticizerTest.java b/src/test/java/com/android/tools/r8/shaking/ifrule/classstaticizer/IfRuleWithClassStaticizerTest.java
index ee59f24..eaf5faa 100644
--- a/src/test/java/com/android/tools/r8/shaking/ifrule/classstaticizer/IfRuleWithClassStaticizerTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/ifrule/classstaticizer/IfRuleWithClassStaticizerTest.java
@@ -43,7 +43,7 @@
     String expectedOutput = StringUtils.lines("In method()");
 
     if (parameters.isCfRuntime()) {
-      testForJvm()
+      testForJvm(parameters)
           .addTestClasspath()
           .run(parameters.getRuntime(), TestClass.class)
           .assertSuccessWithOutput(expectedOutput);
diff --git a/src/test/java/com/android/tools/r8/shaking/ifrule/interfacemethoddesugaring/IfRuleWithInterfaceMethodDesugaringTest.java b/src/test/java/com/android/tools/r8/shaking/ifrule/interfacemethoddesugaring/IfRuleWithInterfaceMethodDesugaringTest.java
index 075e0f6..86d1074 100644
--- a/src/test/java/com/android/tools/r8/shaking/ifrule/interfacemethoddesugaring/IfRuleWithInterfaceMethodDesugaringTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/ifrule/interfacemethoddesugaring/IfRuleWithInterfaceMethodDesugaringTest.java
@@ -12,7 +12,6 @@
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
-import static org.junit.Assume.assumeTrue;
 
 import com.android.tools.r8.NeverClassInline;
 import com.android.tools.r8.NeverInline;
@@ -54,8 +53,8 @@
 
   @Test
   public void testReference() throws Exception {
-    assumeTrue(parameters.isCfRuntime());
-    testForJvm()
+    parameters.assumeJvmTestParameters();
+    testForJvm(parameters)
         .addTestClasspath()
         .run(parameters.getRuntime(), TestClass.class)
         .assertSuccessWithOutput(EXPECTED_OUTPUT);
diff --git a/src/test/java/com/android/tools/r8/shaking/ifrule/verticalclassmerging/IfRuleWithVerticalClassMerging.java b/src/test/java/com/android/tools/r8/shaking/ifrule/verticalclassmerging/IfRuleWithVerticalClassMerging.java
index 1346579..f2b946e 100644
--- a/src/test/java/com/android/tools/r8/shaking/ifrule/verticalclassmerging/IfRuleWithVerticalClassMerging.java
+++ b/src/test/java/com/android/tools/r8/shaking/ifrule/verticalclassmerging/IfRuleWithVerticalClassMerging.java
@@ -10,7 +10,7 @@
 
 import com.android.tools.r8.NeverClassInline;
 import com.android.tools.r8.TestBase;
-import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.utils.BooleanUtils;
 import com.android.tools.r8.utils.InternalOptions;
 import com.android.tools.r8.utils.StringUtils;
@@ -22,6 +22,7 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
 import org.junit.runners.Parameterized.Parameters;
 
 @NeverClassInline
@@ -68,18 +69,17 @@
   private static final List<Class<?>> CLASSES =
       ImmutableList.of(A.class, B.class, C.class, D.class, Main.class);
 
-  private final Backend backend;
-  private final boolean enableVerticalClassMerging;
+  @Parameter(0)
+  public TestParameters parameters;
 
-  public IfRuleWithVerticalClassMerging(Backend backend, boolean enableVerticalClassMerging) {
-    this.backend = backend;
-    this.enableVerticalClassMerging = enableVerticalClassMerging;
-  }
+  @Parameter(1)
+  public boolean enableVerticalClassMerging;
 
-  @Parameters(name = "Backend: {0}, vertical class merging: {1}")
+  @Parameters(name = "{0}, vertical class merging: {1}")
   public static Collection<Object[]> data() {
     // We don't run this on Proguard, as Proguard does not merge A into B.
-    return buildParameters(ToolHelper.getBackends(), BooleanUtils.values());
+    return buildParameters(
+        getTestParameters().withAllRuntimesAndApiLevels().build(), BooleanUtils.values());
   }
 
   private void configure(InternalOptions options) {
@@ -124,13 +124,14 @@
 
   private void runTestWithProguardConfig(String config) throws Exception {
     CodeInspector inspector =
-        testForR8(backend)
+        testForR8(parameters.getBackend())
             .addProgramClasses(CLASSES)
             .addKeepMainRule(Main.class)
             .addKeepRules(config)
             .enableNeverClassInliningAnnotations()
             .addOptionsModification(this::configure)
-            .run(Main.class)
+            .setMinApi(parameters)
+            .run(parameters.getRuntime(), Main.class)
             .assertSuccessWithOutput("123456")
             .inspector();
 
diff --git a/src/test/java/com/android/tools/r8/shaking/keepclassmembers/KeepClassMembersTest.java b/src/test/java/com/android/tools/r8/shaking/keepclassmembers/KeepClassMembersTest.java
index 5b54ed0..ba6034d 100644
--- a/src/test/java/com/android/tools/r8/shaking/keepclassmembers/KeepClassMembersTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/keepclassmembers/KeepClassMembersTest.java
@@ -11,7 +11,8 @@
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 
-import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
 import com.android.tools.r8.shaking.forceproguardcompatibility.ProguardCompatibilityTestBase;
 import com.android.tools.r8.utils.codeinspector.ClassSubject;
 import com.android.tools.r8.utils.codeinspector.CodeInspector;
@@ -21,23 +22,25 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
 
 @RunWith(Parameterized.class)
 public class KeepClassMembersTest extends ProguardCompatibilityTestBase {
 
-  private Backend backend;
+  @Parameter public TestParameters parameters;
 
-  @Parameterized.Parameters(name = "Backend: {0}")
-  public static Backend[] data() {
-    return ToolHelper.getBackends();
+  @Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withAllRuntimesAndApiLevels().build();
   }
 
-  public KeepClassMembersTest(Backend backend) {
-    this.backend = backend;
-  }
-
-  private void check(CodeInspector inspector, Class mainClass, Class<?> staticClass,
-      boolean forceProguardCompatibility, boolean fromProguard) {
+  private void check(
+      CodeInspector inspector,
+      Class<?> mainClass,
+      Class<?> staticClass,
+      boolean forceProguardCompatibility,
+      boolean fromProguard) {
     assertTrue(inspector.clazz(mainClass).isPresent());
     ClassSubject staticClassSubject = inspector.clazz(staticClass);
     assertThat(staticClassSubject, isPresent());
@@ -72,26 +75,25 @@
     assertThat(staticClassSubject.field("int", "j"), not(isPresent()));
   }
 
-  private void runTest(Class mainClass, Class<?> staticClass,
-      boolean forceProguardCompatibility) throws Exception {
+  private void runTest(Class<?> mainClass, Class<?> staticClass, boolean forceProguardCompatibility)
+      throws Exception {
     String proguardConfig = String.join("\n", ImmutableList.of(
-        "-keepclassmembers class **.PureStatic* {",
-        "  public static int b;",
-        "  public static int getA();",
-        "}",
-        "-keep class **.MainUsing* {",
-        "  public static void main(java.lang.String[]);",
-        "}",
-        "-dontoptimize", "-dontobfuscate"
     ));
     CodeInspector inspector;
     inspector =
-        new CodeInspector(
-            compileWithR8(
-                readClasses(ImmutableList.of(mainClass, staticClass)),
-                proguardConfig,
-                options -> options.forceProguardCompatibility = forceProguardCompatibility,
-                backend));
+        testForR8Compat(parameters.getBackend(), forceProguardCompatibility)
+            .addProgramClasses(mainClass, staticClass)
+            .addKeepMainRule(mainClass)
+            .addKeepRules(
+                "-keepclassmembers class **.PureStatic* {",
+                "  public static int b;",
+                "  public static int getA();",
+                "}")
+            .addDontObfuscate()
+            .addDontOptimize()
+            .setMinApi(parameters)
+            .compile()
+            .inspector();
     check(inspector, mainClass, staticClass, forceProguardCompatibility, false);
 
     if (isRunProguard()) {
diff --git a/src/test/java/com/android/tools/r8/shaking/keptgraph/KeptByAnnotatedClassTestRunner.java b/src/test/java/com/android/tools/r8/shaking/keptgraph/KeptByAnnotatedClassTestRunner.java
index 3f3c43e..053ec70 100644
--- a/src/test/java/com/android/tools/r8/shaking/keptgraph/KeptByAnnotatedClassTestRunner.java
+++ b/src/test/java/com/android/tools/r8/shaking/keptgraph/KeptByAnnotatedClassTestRunner.java
@@ -7,7 +7,8 @@
 import static org.junit.Assert.assertEquals;
 
 import com.android.tools.r8.TestBase;
-import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
 import com.android.tools.r8.origin.Origin;
 import com.android.tools.r8.references.MethodReference;
 import com.android.tools.r8.utils.StringUtils;
@@ -16,6 +17,7 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
 import org.junit.runners.Parameterized.Parameters;
 
 @RunWith(Parameterized.class)
@@ -24,15 +26,12 @@
   private static final Class<KeptByAnnotatedClassTest> CLASS = KeptByAnnotatedClassTest.class;
   private final String EXPECTED = StringUtils.lines("called bar");
 
-  private final Backend backend;
+  @Parameter(0)
+  public TestParameters parameters;
 
   @Parameters(name = "{0}")
-  public static Backend[] data() {
-    return ToolHelper.getBackends();
-  }
-
-  public KeptByAnnotatedClassTestRunner(Backend backend) {
-    this.backend = backend;
+  public static TestParametersCollection data() {
+    return getTestParameters().withAllRuntimesAndApiLevels().build();
   }
 
   @Test
@@ -42,14 +41,15 @@
     MethodReference bazMethod = methodFromMethod(CLASS.getDeclaredMethod("baz"));
 
     GraphInspector inspector =
-        testForR8(backend)
+        testForR8(parameters.getBackend())
             .enableGraphInspector()
             .enableInliningAnnotations()
             .addProgramClasses(CLASS)
             .addKeepAnnotation()
             .addKeepRules("-keep @com.android.tools.r8.Keep class * { public *; }")
             .addInliningAnnotations()
-            .run(CLASS)
+            .setMinApi(parameters)
+            .run(parameters.getRuntime(), CLASS)
             .assertSuccessWithOutput(EXPECTED)
             .graphInspector();
 
diff --git a/src/test/java/com/android/tools/r8/shaking/keptgraph/KeptByAnnotatedMethodTestRunner.java b/src/test/java/com/android/tools/r8/shaking/keptgraph/KeptByAnnotatedMethodTestRunner.java
index a5fb706..d4825c1 100644
--- a/src/test/java/com/android/tools/r8/shaking/keptgraph/KeptByAnnotatedMethodTestRunner.java
+++ b/src/test/java/com/android/tools/r8/shaking/keptgraph/KeptByAnnotatedMethodTestRunner.java
@@ -7,7 +7,8 @@
 import static org.junit.Assert.assertEquals;
 
 import com.android.tools.r8.TestBase;
-import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
 import com.android.tools.r8.origin.Origin;
 import com.android.tools.r8.references.MethodReference;
 import com.android.tools.r8.references.Reference;
@@ -19,6 +20,7 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
 import org.junit.runners.Parameterized.Parameters;
 
 @RunWith(Parameterized.class)
@@ -30,15 +32,18 @@
 
   private final String EXPECTED = StringUtils.lines("called bar");
 
-  private final Backend backend;
+  @Parameter(0)
+  public TestParameters parameters;
 
   @Parameters(name = "{0}")
-  public static Backend[] data() {
-    return ToolHelper.getBackends();
+  public static TestParametersCollection data() {
+    return getTestParameters().withAllRuntimesAndApiLevels().build();
   }
 
-  public KeptByAnnotatedMethodTestRunner(Backend backend) {
-    this.backend = backend;
+  @Test
+  public void testJvm() throws Exception {
+    parameters.assumeJvmTestParameters();
+    testForJvm(parameters).addProgramClasses(CLASSES).run(CLASS).assertSuccessWithOutput(EXPECTED);
   }
 
   @Test
@@ -48,24 +53,21 @@
     MethodReference barMethod = methodFromMethod(INNER.getDeclaredMethod("bar"));
     MethodReference bazMethod = methodFromMethod(INNER.getDeclaredMethod("baz"));
 
-    if (backend == Backend.CF) {
-      testForJvm().addProgramClasses(CLASSES).run(CLASS).assertSuccessWithOutput(EXPECTED);
-    }
-
     Origin ruleOrigin = Origin.unknown();
 
     String keepAnnotatedMethodsRule = "-keepclassmembers class * { @com.android.tools.r8.Keep *; }";
     String keepClassesOfAnnotatedMethodsRule =
         "-keep,allowobfuscation class * { <init>(); @com.android.tools.r8.Keep *; }";
     GraphInspector inspector =
-        testForR8(backend)
+        testForR8(parameters.getBackend())
             .enableGraphInspector()
             .enableInliningAnnotations()
             .addProgramClasses(CLASSES)
             .addKeepAnnotation()
             .addKeepMainRule(CLASS)
             .addKeepRules(keepAnnotatedMethodsRule, keepClassesOfAnnotatedMethodsRule)
-            .run(CLASS)
+            .setMinApi(parameters)
+            .run(parameters.getRuntime(), CLASS)
             .assertSuccessWithOutput(EXPECTED)
             .graphInspector();
 
diff --git a/src/test/java/com/android/tools/r8/shaking/keptgraph/KeptByFieldReflectionTestRunner.java b/src/test/java/com/android/tools/r8/shaking/keptgraph/KeptByFieldReflectionTestRunner.java
index 02d8481..b3a97a6 100644
--- a/src/test/java/com/android/tools/r8/shaking/keptgraph/KeptByFieldReflectionTestRunner.java
+++ b/src/test/java/com/android/tools/r8/shaking/keptgraph/KeptByFieldReflectionTestRunner.java
@@ -8,7 +8,8 @@
 import static org.junit.Assert.assertEquals;
 
 import com.android.tools.r8.TestBase;
-import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
 import com.android.tools.r8.origin.Origin;
 import com.android.tools.r8.references.FieldReference;
 import com.android.tools.r8.references.MethodReference;
@@ -23,6 +24,7 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
 import org.junit.runners.Parameterized.Parameters;
 
 @RunWith(Parameterized.class)
@@ -42,15 +44,21 @@
           "|- is referenced in keep rule:",
           "|  -keep class " + TYPE_NAME + " { public static void main(java.lang.String[]); }");
 
-  private final Backend backend;
+  @Parameter(0)
+  public TestParameters parameters;
 
   @Parameters(name = "{0}")
-  public static Backend[] data() {
-    return ToolHelper.getBackends();
+  public static TestParametersCollection data() {
+    return getTestParameters().withAllRuntimesAndApiLevels().build();
   }
 
-  public KeptByFieldReflectionTestRunner(Backend backend) {
-    this.backend = backend;
+  @Test
+  public void testJvm() throws Exception {
+    parameters.assumeJvmTestParameters();
+    testForJvm(parameters)
+        .addProgramClasses(CLASSES)
+        .run(parameters.getRuntime(), CLASS)
+        .assertSuccessWithOutput(EXPECTED_STDOUT);
   }
 
   @Test
@@ -59,18 +67,15 @@
     FieldReference fooField = fieldFromField(CLASS.getDeclaredField("foo"));
     MethodReference fooInit = methodFromMethod(CLASS.getDeclaredConstructor());
 
-    if (backend == Backend.CF) {
-      testForJvm().addProgramClasses(CLASSES).run(CLASS).assertSuccessWithOutput(EXPECTED_STDOUT);
-    }
-
     WhyAreYouKeepingConsumer consumer = new WhyAreYouKeepingConsumer(null);
     GraphInspector inspector =
-        testForR8(backend)
+        testForR8(parameters.getBackend())
             .enableGraphInspector(consumer)
             .addProgramClasses(CLASSES)
             .addKeepAnnotation()
             .addKeepMainRule(CLASS)
-            .run(CLASS)
+            .setMinApi(parameters)
+            .run(parameters.getRuntime(), CLASS)
             .assertSuccessWithOutput(EXPECTED_STDOUT)
             .graphInspector();
 
diff --git a/src/test/java/com/android/tools/r8/shaking/keptgraph/KeptByMethodReflectionTestRunner.java b/src/test/java/com/android/tools/r8/shaking/keptgraph/KeptByMethodReflectionTestRunner.java
index be0fcff..28ab3d8 100644
--- a/src/test/java/com/android/tools/r8/shaking/keptgraph/KeptByMethodReflectionTestRunner.java
+++ b/src/test/java/com/android/tools/r8/shaking/keptgraph/KeptByMethodReflectionTestRunner.java
@@ -7,7 +7,8 @@
 import static org.junit.Assert.assertEquals;
 
 import com.android.tools.r8.TestBase;
-import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
 import com.android.tools.r8.origin.Origin;
 import com.android.tools.r8.references.MethodReference;
 import com.android.tools.r8.shaking.WhyAreYouKeepingConsumer;
@@ -21,6 +22,7 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
 import org.junit.runners.Parameterized.Parameters;
 
 @RunWith(Parameterized.class)
@@ -40,15 +42,21 @@
           "|- is referenced in keep rule:",
           "|  -keep class " + TYPE_NAME + " { public static void main(java.lang.String[]); }");
 
-  private final Backend backend;
+  @Parameter(0)
+  public TestParameters parameters;
 
   @Parameters(name = "{0}")
-  public static Backend[] data() {
-    return ToolHelper.getBackends();
+  public static TestParametersCollection data() {
+    return getTestParameters().withAllRuntimesAndApiLevels().build();
   }
 
-  public KeptByMethodReflectionTestRunner(Backend backend) {
-    this.backend = backend;
+  @Test
+  public void testJvm() throws Exception {
+    parameters.assumeJvmTestParameters();
+    testForJvm(parameters)
+        .addProgramClasses(CLASSES)
+        .run(parameters.getRuntime(), CLASS)
+        .assertSuccessWithOutput(EXPECTED_STDOUT);
   }
 
   @Test
@@ -56,18 +64,15 @@
     MethodReference mainMethod = methodFromMethod(CLASS.getDeclaredMethod("main", String[].class));
     MethodReference fooMethod = methodFromMethod(CLASS.getDeclaredMethod("foo"));
 
-    if (backend == Backend.CF) {
-      testForJvm().addProgramClasses(CLASSES).run(CLASS).assertSuccessWithOutput(EXPECTED_STDOUT);
-    }
-
     WhyAreYouKeepingConsumer consumer = new WhyAreYouKeepingConsumer(null);
     GraphInspector inspector =
-        testForR8(backend)
+        testForR8(parameters.getBackend())
             .enableGraphInspector(consumer)
             .addProgramClasses(CLASSES)
             .addKeepAnnotation()
             .addKeepMainRule(CLASS)
-            .run(CLASS)
+            .setMinApi(parameters)
+            .run(parameters.getRuntime(), CLASS)
             .assertSuccessWithOutput(EXPECTED_STDOUT)
             .graphInspector();
 
diff --git a/src/test/java/com/android/tools/r8/shaking/keptgraph/KeptByTwoRulesTestRunner.java b/src/test/java/com/android/tools/r8/shaking/keptgraph/KeptByTwoRulesTestRunner.java
index 042679f..66aef0f 100644
--- a/src/test/java/com/android/tools/r8/shaking/keptgraph/KeptByTwoRulesTestRunner.java
+++ b/src/test/java/com/android/tools/r8/shaking/keptgraph/KeptByTwoRulesTestRunner.java
@@ -8,7 +8,8 @@
 import static org.junit.Assert.assertEquals;
 
 import com.android.tools.r8.TestBase;
-import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
 import com.android.tools.r8.references.MethodReference;
 import com.android.tools.r8.utils.StringUtils;
 import com.android.tools.r8.utils.graphinspector.GraphInspector;
@@ -18,6 +19,7 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
 import org.junit.runners.Parameterized.Parameters;
 
 @RunWith(Parameterized.class)
@@ -28,15 +30,21 @@
 
   private final String EXPECTED = StringUtils.lines("called foo");
 
-  private final Backend backend;
+  @Parameter(0)
+  public TestParameters parameters;
 
   @Parameters(name = "{0}")
-  public static Backend[] data() {
-    return ToolHelper.getBackends();
+  public static TestParametersCollection data() {
+    return getTestParameters().withAllRuntimesAndApiLevels().build();
   }
 
-  public KeptByTwoRulesTestRunner(Backend backend) {
-    this.backend = backend;
+  @Test
+  public void testJvm() throws Exception {
+    parameters.assumeJvmTestParameters();
+    testForJvm(parameters)
+        .addProgramClasses(CLASSES)
+        .run(parameters.getRuntime(), CLASS)
+        .assertSuccessWithOutput(EXPECTED);
   }
 
   @Test
@@ -44,19 +52,16 @@
     MethodReference mainMethod = methodFromMethod(CLASS.getDeclaredMethod("main", String[].class));
     MethodReference fooMethod = methodFromMethod(CLASS.getDeclaredMethod("foo"));
 
-    if (backend == Backend.CF) {
-      testForJvm().addProgramClasses(CLASSES).run(CLASS).assertSuccessWithOutput(EXPECTED);
-    }
-
     String keepPublicRule = "-keep @com.android.tools.r8.Keep class * {  public *; }";
     String keepFooRule = "-keep class " + CLASS.getTypeName() + " { public void foo(); }";
     GraphInspector inspector =
-        testForR8(backend)
+        testForR8(parameters.getBackend())
             .enableGraphInspector()
             .addProgramClasses(CLASSES)
             .addKeepAnnotation()
             .addKeepRules(keepPublicRule, keepFooRule)
-            .run(CLASS)
+            .setMinApi(parameters)
+            .run(parameters.getRuntime(), CLASS)
             .assertSuccessWithOutput(EXPECTED)
             .graphInspector();
 
diff --git a/src/test/java/com/android/tools/r8/shaking/keptgraph/KeptMethodTestRunner.java b/src/test/java/com/android/tools/r8/shaking/keptgraph/KeptMethodTestRunner.java
index 81ba033..8d0efbad 100644
--- a/src/test/java/com/android/tools/r8/shaking/keptgraph/KeptMethodTestRunner.java
+++ b/src/test/java/com/android/tools/r8/shaking/keptgraph/KeptMethodTestRunner.java
@@ -7,7 +7,8 @@
 import static org.junit.Assert.assertEquals;
 
 import com.android.tools.r8.TestBase;
-import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
 import com.android.tools.r8.origin.Origin;
 import com.android.tools.r8.references.MethodReference;
 import com.android.tools.r8.utils.StringUtils;
@@ -16,6 +17,7 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
 import org.junit.runners.Parameterized.Parameters;
 
 @RunWith(Parameterized.class)
@@ -24,15 +26,12 @@
   private static final Class<KeptMethodTest> CLASS = KeptMethodTest.class;
   private static final String EXPECTED = StringUtils.lines("called bar");
 
-  private final Backend backend;
+  @Parameter(0)
+  public TestParameters parameters;
 
   @Parameters(name = "{0}")
-  public static Backend[] data() {
-    return ToolHelper.getBackends();
-  }
-
-  public KeptMethodTestRunner(Backend backend) {
-    this.backend = backend;
+  public static TestParametersCollection data() {
+    return getTestParameters().withAllRuntimesAndApiLevels().build();
   }
 
   @Test
@@ -42,12 +41,13 @@
     MethodReference bazMethod = methodFromMethod(CLASS.getDeclaredMethod("baz"));
 
     GraphInspector inspector =
-        testForR8(backend)
+        testForR8(parameters.getBackend())
             .enableGraphInspector()
             .enableInliningAnnotations()
             .addProgramClasses(CLASS)
             .addKeepMethodRules(mainMethod)
-            .run(CLASS)
+            .setMinApi(parameters)
+            .run(parameters.getRuntime(), CLASS)
             .assertSuccessWithOutput(EXPECTED)
             .graphInspector();
 
diff --git a/src/test/java/com/android/tools/r8/shaking/reflection/ReflectiveNewInstanceTest.java b/src/test/java/com/android/tools/r8/shaking/reflection/ReflectiveNewInstanceTest.java
index 65b5ed6..301c06a 100644
--- a/src/test/java/com/android/tools/r8/shaking/reflection/ReflectiveNewInstanceTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/reflection/ReflectiveNewInstanceTest.java
@@ -42,7 +42,7 @@
         StringUtils.lines("Success", "Success", "Success", "Success", "Success");
 
     if (parameters.isCfRuntime()) {
-      testForJvm()
+      testForJvm(parameters)
           .addTestClasspath()
           .run(parameters.getRuntime(), TestClass.class)
           .assertSuccessWithOutput(expectedOutput);
diff --git a/src/test/java/com/android/tools/r8/shaking/serviceloader/ServiceLoaderMultipleTest.java b/src/test/java/com/android/tools/r8/shaking/serviceloader/ServiceLoaderMultipleTest.java
index 2514958..c3d3efb 100644
--- a/src/test/java/com/android/tools/r8/shaking/serviceloader/ServiceLoaderMultipleTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/serviceloader/ServiceLoaderMultipleTest.java
@@ -4,7 +4,6 @@
 
 package com.android.tools.r8.shaking.serviceloader;
 
-import static org.junit.Assume.assumeTrue;
 
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
@@ -96,7 +95,7 @@
 
   @Test
   public void testMultipleServicesWithSameImplementationJVM() throws Exception {
-    assumeTrue(parameters.isCfRuntime());
+    parameters.assumeJvmTestParameters();
     testForJvm(parameters)
         .addClasspath(jarWithServiceInterface, jarWithMultipleImpl1, jarWithMultipleImpl1)
         .addProgramClasses(TestClass.class)
diff --git a/src/test/java/com/android/tools/r8/shaking/synthetic/StaticCallInSyntheticMethodAsmTest.java b/src/test/java/com/android/tools/r8/shaking/synthetic/StaticCallInSyntheticMethodAsmTest.java
index d0968c5..b1f69e8 100644
--- a/src/test/java/com/android/tools/r8/shaking/synthetic/StaticCallInSyntheticMethodAsmTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/synthetic/StaticCallInSyntheticMethodAsmTest.java
@@ -4,22 +4,23 @@
 package com.android.tools.r8.shaking.synthetic;
 
 import com.android.tools.r8.AsmTestBase;
-import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
 
 @RunWith(Parameterized.class)
 public class StaticCallInSyntheticMethodAsmTest extends AsmTestBase {
-  private final Backend backend;
 
-  @Parameterized.Parameters(name = "backend: {0}")
-  public static Backend[] data() {
-    return ToolHelper.getBackends();
-  }
+  @Parameter(0)
+  public TestParameters parameters;
 
-  public StaticCallInSyntheticMethodAsmTest(Backend backend) {
-    this.backend = backend;
+  @Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withAllRuntimesAndApiLevels().build();
   }
 
   // class Base {
@@ -29,10 +30,10 @@
   // class Sub extends Base {}
   @Test
   public void test() throws Exception {
-    testForR8(backend)
+    testForR8(parameters.getBackend())
         .addProgramClassFileData(Base.dump(), Sub.dump())
-        .addKeepRules("-dontshrink")
+        .addDontShrink()
+        .setMinApi(parameters)
         .compile();
   }
-
 }
diff --git a/src/test/java/com/android/tools/r8/testing/JvmVmArgumentsTest.java b/src/test/java/com/android/tools/r8/testing/JvmVmArgumentsTest.java
index 8fdc339..4d48949 100644
--- a/src/test/java/com/android/tools/r8/testing/JvmVmArgumentsTest.java
+++ b/src/test/java/com/android/tools/r8/testing/JvmVmArgumentsTest.java
@@ -27,7 +27,7 @@
 
   @Test
   public void testArguments() throws Exception {
-    testForJvm()
+    testForJvm(parameters)
         .addTestClasspath()
         .addVmArguments("-ea")
         .run(parameters.getRuntime(), TestClass.class)
@@ -36,13 +36,13 @@
 
   @Test
   public void testMultipleArguments() throws Exception {
-    testForJvm()
+    testForJvm(parameters)
         .addTestClasspath()
         .addVmArguments("-ea", "-da")
         .run(parameters.getRuntime(), TestClass.class)
         .assertSuccessWithOutputLines("DONE");
 
-    testForJvm()
+    testForJvm(parameters)
         .addTestClasspath()
         .addVmArguments("-ea")
         .addVmArguments("-da")
@@ -52,7 +52,7 @@
 
   @Test
   public void testNoArguments() throws Exception {
-    testForJvm()
+    testForJvm(parameters)
         .addTestClasspath()
         .addVmArguments()
         .run(parameters.getRuntime(), TestClass.class)
diff --git a/src/test/java/com/android/tools/r8/testing/StackTraceTest.java b/src/test/java/com/android/tools/r8/testing/StackTraceTest.java
index eddc3cf..04cfaf8 100644
--- a/src/test/java/com/android/tools/r8/testing/StackTraceTest.java
+++ b/src/test/java/com/android/tools/r8/testing/StackTraceTest.java
@@ -175,8 +175,8 @@
 
   @Test
   public void testJvmStackTraceFromRunning() throws Exception {
-    assumeTrue(parameters.isCfRuntime());
-    testForJvm()
+    parameters.assumeJvmTestParameters();
+    testForJvm(parameters)
         .addInnerClasses(StackTraceTest.class)
         .run(parameters.getRuntime(), Main.class)
         .assertFailure()
diff --git a/src/test/java/com/android/tools/r8/workaround/InputWithAbstractMethodOnNonAbstractClassTest.java b/src/test/java/com/android/tools/r8/workaround/InputWithAbstractMethodOnNonAbstractClassTest.java
index f091151..0efc386 100644
--- a/src/test/java/com/android/tools/r8/workaround/InputWithAbstractMethodOnNonAbstractClassTest.java
+++ b/src/test/java/com/android/tools/r8/workaround/InputWithAbstractMethodOnNonAbstractClassTest.java
@@ -8,7 +8,6 @@
 import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
 import static org.hamcrest.CoreMatchers.not;
 import static org.hamcrest.MatcherAssert.assertThat;
-import static org.junit.Assume.assumeTrue;
 
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
@@ -36,7 +35,7 @@
 
   @Test
   public void testD8() throws Exception {
-    assumeTrue(parameters.isDexRuntime());
+    parameters.assumeDexRuntime();
     testForD8()
         .addProgramClasses(TestClass.class)
         .addProgramClassFileData(transformer(Greeter.class).unsetAbstract().transform())
@@ -63,8 +62,8 @@
 
   @Test
   public void testJVM() throws Exception {
-    assumeTrue(parameters.isCfRuntime());
-    testForJvm()
+    parameters.assumeJvmTestParameters();
+    testForJvm(parameters)
         .addProgramClasses(TestClass.class)
         .addProgramClassFileData(transformer(Greeter.class).unsetAbstract().transform())
         .run(parameters.getRuntime(), TestClass.class)