Extend test parameters to partial compilation

This extends the TestParameters to include a PartialCompilationTestParameters, which is either NONE (default), INCLUDE_ALL, EXCLUDE_ALL or RANDOM.

The non-default PartialCompilationTestParameters can be obtained by calling .withPartialCompilation() on the TestParametersBuilder.

Change-Id: I74dce0e116100403b44764bd883d33319a9000bf
diff --git a/src/test/examplesJava21/desugaredlibrary/Java21CollectionTest.java b/src/test/examplesJava21/desugaredlibrary/Java21CollectionTest.java
index 6b1c8fe..d86ef1d 100644
--- a/src/test/examplesJava21/desugaredlibrary/Java21CollectionTest.java
+++ b/src/test/examplesJava21/desugaredlibrary/Java21CollectionTest.java
@@ -60,7 +60,7 @@
   @Parameters(name = "{0}, spec: {1}, {2}")
   public static List<Object[]> data() {
     return buildParameters(
-        getTestParameters().withDexRuntimesIncludingMaster().withAllApiLevels().build(),
+        getTestParameters().withDexRuntimesAndAllApiLevels().build(),
         // Note that JDK8 is completely broken here.
         ImmutableList.of(JDK11, JDK11_PATH),
         DEFAULT_SPECIFICATIONS);
diff --git a/src/test/examplesJava21/desugaredlibrary/MapMultiTest.java b/src/test/examplesJava21/desugaredlibrary/MapMultiTest.java
index 32bf566..cd3203b 100644
--- a/src/test/examplesJava21/desugaredlibrary/MapMultiTest.java
+++ b/src/test/examplesJava21/desugaredlibrary/MapMultiTest.java
@@ -41,7 +41,7 @@
   @Parameters(name = "{0}, spec: {1}, {2}")
   public static List<Object[]> data() {
     return buildParameters(
-        getTestParameters().withDexRuntimesIncludingMaster().withAllApiLevels().build(),
+        getTestParameters().withDexRuntimesAndAllApiLevels().build(),
         // Note that JDK8 is completely broken here.
         ImmutableList.of(JDK11, JDK11_PATH),
         DEFAULT_SPECIFICATIONS);
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/LinkedListJdk8BrokenByAndroidVUpdateTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/LinkedListJdk8BrokenByAndroidVUpdateTest.java
index 3555c2d..0800f37 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/LinkedListJdk8BrokenByAndroidVUpdateTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/LinkedListJdk8BrokenByAndroidVUpdateTest.java
@@ -38,7 +38,7 @@
   @Parameters(name = "{0}, spec: {1}, {2}")
   public static List<Object[]> data() {
     return buildParameters(
-        getTestParameters().withDexRuntimesIncludingMaster().withAllApiLevels().build(),
+        getTestParameters().withDexRuntimesAndAllApiLevels().build(),
         ImmutableList.of(JDK8, JDK11, JDK11_PATH),
         DEFAULT_SPECIFICATIONS);
   }
diff --git a/src/test/testbase/java/com/android/tools/r8/PartialCompilationTestParameters.java b/src/test/testbase/java/com/android/tools/r8/PartialCompilationTestParameters.java
new file mode 100644
index 0000000..74fc752
--- /dev/null
+++ b/src/test/testbase/java/com/android/tools/r8/PartialCompilationTestParameters.java
@@ -0,0 +1,31 @@
+// Copyright (c) 2025, 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;
+
+public enum PartialCompilationTestParameters {
+  NONE,
+  INCLUDE_ALL,
+  EXCLUDE_ALL,
+  RANDOM;
+
+  public boolean isNone() {
+    return this == NONE;
+  }
+
+  public boolean isSome() {
+    return !isNone();
+  }
+
+  public boolean isIncludeAll() {
+    return this == INCLUDE_ALL;
+  }
+
+  public boolean isExcludeAll() {
+    return this == EXCLUDE_ALL;
+  }
+
+  public boolean isRandom() {
+    return this == RANDOM;
+  }
+}
diff --git a/src/test/testbase/java/com/android/tools/r8/TestParameters.java b/src/test/testbase/java/com/android/tools/r8/TestParameters.java
index ef797e2..3eaa3c1 100644
--- a/src/test/testbase/java/com/android/tools/r8/TestParameters.java
+++ b/src/test/testbase/java/com/android/tools/r8/TestParameters.java
@@ -22,21 +22,29 @@
 
   private final TestRuntime runtime;
   private final AndroidApiLevel apiLevel;
+  private final PartialCompilationTestParameters partialCompilationTestParameters;
   private final boolean representativeApiLevelForRuntime;
 
   public TestParameters(TestRuntime runtime) {
-    this(runtime, null);
-  }
-
-  public TestParameters(TestRuntime runtime, AndroidApiLevel apiLevel) {
-    this(runtime, apiLevel, true);
+    this(runtime, null, PartialCompilationTestParameters.NONE);
   }
 
   public TestParameters(
-      TestRuntime runtime, AndroidApiLevel apiLevel, boolean representativeApiLevelForRuntime) {
+      TestRuntime runtime,
+      AndroidApiLevel apiLevel,
+      PartialCompilationTestParameters partialCompilationTestParameters) {
+    this(runtime, apiLevel, partialCompilationTestParameters, true);
+  }
+
+  public TestParameters(
+      TestRuntime runtime,
+      AndroidApiLevel apiLevel,
+      PartialCompilationTestParameters partialCompilationTestParameters,
+      boolean representativeApiLevelForRuntime) {
     assert runtime != null;
     this.runtime = runtime;
     this.apiLevel = apiLevel;
+    this.partialCompilationTestParameters = partialCompilationTestParameters;
     this.representativeApiLevelForRuntime = representativeApiLevelForRuntime;
   }
 
@@ -205,6 +213,10 @@
     return runtime.asCf();
   }
 
+  public PartialCompilationTestParameters getPartialCompilationTestParameters() {
+    return partialCompilationTestParameters;
+  }
+
   // Access to underlying runtime/wrapper.
   public TestRuntime getRuntime() {
     return runtime;
@@ -222,10 +234,14 @@
 
   @Override
   public String toString() {
+    StringBuilder builder = new StringBuilder(runtime.toString());
     if (apiLevel != null) {
-      return runtime.toString() + ", api:" + apiLevel.getLevel();
+      builder.append(", api:").append(apiLevel.getLevel());
     }
-    return runtime.toString();
+    if (partialCompilationTestParameters.isSome()) {
+      builder.append(", partial:").append(partialCompilationTestParameters);
+    }
+    return builder.toString();
   }
 
   public void assertCfRuntime() {
@@ -308,4 +324,11 @@
     assertTrue(isDexRuntime());
     return getRuntime().asDex().getVm().getVersion();
   }
+
+  TestParameters withPartialCompilationTestParameters(
+      PartialCompilationTestParameters partialCompilationTestParameters) {
+    assert getPartialCompilationTestParameters().isNone();
+    return new TestParameters(
+        runtime, apiLevel, partialCompilationTestParameters, representativeApiLevelForRuntime);
+  }
 }
diff --git a/src/test/testbase/java/com/android/tools/r8/TestParametersBuilder.java b/src/test/testbase/java/com/android/tools/r8/TestParametersBuilder.java
index 16a0997..36ecb2f 100644
--- a/src/test/testbase/java/com/android/tools/r8/TestParametersBuilder.java
+++ b/src/test/testbase/java/com/android/tools/r8/TestParametersBuilder.java
@@ -3,6 +3,8 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8;
 
+import static com.google.common.base.Predicates.alwaysFalse;
+
 import com.android.tools.r8.TestRuntime.CfRuntime;
 import com.android.tools.r8.TestRuntime.CfVm;
 import com.android.tools.r8.TestRuntime.DexRuntime;
@@ -25,10 +27,9 @@
 
   // Predicate describing which test parameters are applicable to the test.
   // Built via the methods found below. Defaults to no applicable parameters, i.e., the emtpy set.
-  private Predicate<TestParameters> filter = param -> false;
+  private Predicate<TestParameters> filter = alwaysFalse();
+  private Predicate<TestParameters> partialFilter = alwaysFalse();
   private boolean hasDexRuntimeFilter = false;
-  // TODO(b/245066448): Enable bot with testing new art master.
-  private boolean allowMaster = System.getProperty("com.android.tools.r8.artmaster") != null;
 
   TestParametersBuilder() {}
 
@@ -46,10 +47,17 @@
     return withFilter(
         p ->
             p.isDexRuntime()
-                && (allowMaster || p.getDexRuntimeVersion().isOlderThan(DexVm.Version.MASTER))
+                && p.getDexRuntimeVersion().isOlderThan(DexVm.Version.MASTER)
                 && predicate.test(p.getDexRuntimeVersion()));
   }
 
+  private TestParametersBuilder withPartialCompilationFilter(
+      Predicate<PartialCompilationTestParameters> predicate) {
+    enablePartialCompilation = true;
+    partialFilter = partialFilter.or(p -> predicate.test(p.getPartialCompilationTestParameters()));
+    return this;
+  }
+
   public TestParametersBuilder withNoneRuntime() {
     return withFilter(p -> p.getRuntime() == NoneRuntime.getInstance());
   }
@@ -120,32 +128,11 @@
     return withCfRuntimeFilter(startInclusive::lessThanOrEqual);
   }
 
-  /** Add all available CF runtimes starting from and excluding {@param startExcluding}. */
-  public TestParametersBuilder withCfRuntimesStartingFromExcluding(CfVm startExcluding) {
-    return withCfRuntimeFilter(startExcluding::lessThan);
-  }
-
-  /** Add all available CF runtimes ending at and including {@param endInclusive}. */
-  public TestParametersBuilder withCfRuntimesEndingAtIncluding(CfVm endInclusive) {
-    return withCfRuntimeFilter(vm -> vm.lessThanOrEqual(endInclusive));
-  }
-
   /** Add all available CF runtimes ending at and excluding {@param endExclusive}. */
   public TestParametersBuilder withCfRuntimesEndingAtExcluding(CfVm endExclusive) {
     return withCfRuntimeFilter(vm -> vm.lessThan(endExclusive));
   }
 
-  /** Add all available DEX runtimes including master. */
-  public TestParametersBuilder withDexRuntimesIncludingMaster() {
-    this.allowMaster = true;
-    return withDexRuntimes();
-  }
-
-  public TestParametersBuilder allowMaster() {
-    this.allowMaster = true;
-    return this;
-  }
-
   /** Add all available DEX runtimes except master. */
   public TestParametersBuilder withDexRuntimes() {
     return withDexRuntimeFilter(vm -> true);
@@ -165,11 +152,6 @@
     return withDexRuntimesStartingFromIncluding(DexVm.Version.V5_1_1);
   }
 
-  /** Add all available DEX runtimes that do not support native multidex. */
-  public TestParametersBuilder withMainDexRuntimes() {
-    return withDexRuntimesEndingAtExcluding(DexVm.Version.V5_1_1);
-  }
-
   /** Add all available DEX runtimes starting from and including {@param startInclusive}. */
   public TestParametersBuilder withDexRuntimesStartingFromIncluding(DexVm.Version startInclusive) {
     return withDexRuntimeFilter(startInclusive::isOlderThanOrEqual);
@@ -181,14 +163,22 @@
         vm -> vm != startExcluding && startExcluding.isOlderThanOrEqual(vm));
   }
 
-  /** Add all available DEX runtimes ending at and including {@param endInclusive}. */
-  public TestParametersBuilder withDexRuntimesEndingAtIncluding(DexVm.Version endInclusive) {
-    return withDexRuntimeFilter(vm -> vm.isOlderThanOrEqual(endInclusive));
+  public TestParametersBuilder withPartialCompilation() {
+    return withIncludeAllPartialCompilation()
+        .withExcludeAllPartialCompilation()
+        .withRandomPartialCompilation();
   }
 
-  /** Add all available DEX runtimes ending at and excluding {@param endExclusive}. */
-  public TestParametersBuilder withDexRuntimesEndingAtExcluding(DexVm.Version endExclusive) {
-    return withDexRuntimeFilter(vm -> vm != endExclusive && vm.isOlderThanOrEqual(endExclusive));
+  public TestParametersBuilder withIncludeAllPartialCompilation() {
+    return withPartialCompilationFilter(PartialCompilationTestParameters::isIncludeAll);
+  }
+
+  public TestParametersBuilder withExcludeAllPartialCompilation() {
+    return withPartialCompilationFilter(PartialCompilationTestParameters::isExcludeAll);
+  }
+
+  public TestParametersBuilder withRandomPartialCompilation() {
+    return withPartialCompilationFilter(PartialCompilationTestParameters::isRandom);
   }
 
   /**
@@ -202,10 +192,10 @@
 
   private boolean enableApiLevels = false;
   private boolean enableApiLevelsForCf = false;
+  private boolean enablePartialCompilation = false;
 
   private BiPredicate<AndroidApiLevel, TestRuntime> apiLevelFilter = (api, runtime) -> false;
-  private List<AndroidApiLevel> explicitApiLevels = new ArrayList<>();
-  private List<TestRuntime> customRuntimes = new ArrayList<>();
+  private final List<AndroidApiLevel> explicitApiLevels = new ArrayList<>();
 
   private TestParametersBuilder withApiFilter(BiPredicate<AndroidApiLevel, TestRuntime> filter) {
     enableApiLevels = true;
@@ -243,10 +233,6 @@
     return withApiFilter((api, runtime) -> startInclusive.getLevel() <= api.getLevel());
   }
 
-  public TestParametersBuilder withApiLevelsStartingAtExcluding(AndroidApiLevel startExclusive) {
-    return withApiFilter((api, runtime) -> startExclusive.getLevel() < api.getLevel());
-  }
-
   public TestParametersBuilder withApiLevelsEndingAtIncluding(AndroidApiLevel endInclusive) {
     return withApiFilter((api, runtime) -> api.getLevel() <= endInclusive.getLevel());
   }
@@ -255,34 +241,52 @@
     return withApiFilter((api, runtime) -> api.getLevel() < endExclusive.getLevel());
   }
 
-  public TestParametersBuilder withApiLevelsWithoutNativeMultiDex() {
-    return withApiLevelsEndingAtExcluding(AndroidApiLevel.L);
-  }
-
   public TestParametersBuilder apiLevelWithDefaultMethodsSupport() {
     return withApiLevelsStartingAtIncluding(TestBase.apiLevelWithDefaultInterfaceMethodsSupport());
   }
 
-  public TestParametersBuilder withCustomRuntime(TestRuntime runtime) {
-    assert getUnfilteredAvailableRuntimes().noneMatch(r -> r == runtime);
-    customRuntimes.add(runtime);
-    return this;
-  }
-
   public TestParametersCollection build() {
     assert !enableApiLevels || enableApiLevelsForCf || hasDexRuntimeFilter;
     List<TestParameters> availableParameters =
         getAvailableRuntimes()
-            .flatMap(this::createParameters)
+            .flatMap(this::createTestParameters)
             .filter(filter)
             .collect(Collectors.toList());
-    List<TestParameters> customParameters =
-        customRuntimes.stream().flatMap(this::createParameters).collect(Collectors.toList());
-    availableParameters.addAll(customParameters);
     return new TestParametersCollection(availableParameters);
   }
 
-  public Stream<TestParameters> createParameters(TestRuntime runtime) {
+  private Stream<TestParameters> createTestParameters(TestRuntime runtime) {
+    Stream<TestParameters> parameters = createBasicTestParametersForRuntime(runtime);
+    if (enablePartialCompilation) {
+      parameters = createPartialCompilationTestParameters(parameters);
+    }
+    return parameters;
+  }
+
+  private Stream<TestParameters> createPartialCompilationTestParameters(
+      Stream<TestParameters> parameters) {
+    return parameters.flatMap(this::createPartialCompilationTestParameters);
+  }
+
+  private Stream<TestParameters> createPartialCompilationTestParameters(TestParameters parameters) {
+    if (!parameters.isR8PartialTestParameters()) {
+      return Stream.of(parameters);
+    }
+    assert parameters.getPartialCompilationTestParameters().isNone();
+    Stream.Builder<TestParameters> builder = Stream.builder();
+    builder.add(parameters);
+    for (PartialCompilationTestParameters partialCompilationTestParameters :
+        PartialCompilationTestParameters.values()) {
+      TestParameters newParameters =
+          parameters.withPartialCompilationTestParameters(partialCompilationTestParameters);
+      if (partialFilter.test(newParameters)) {
+        builder.add(newParameters);
+      }
+    }
+    return builder.build();
+  }
+
+  private Stream<TestParameters> createBasicTestParametersForRuntime(TestRuntime runtime) {
     if (!enableApiLevels) {
       return Stream.of(new TestParameters(runtime));
     }
@@ -319,14 +323,19 @@
               .map(
                   api -> {
                     TestParameters parameters =
-                        new TestParameters(runtime, api, representativeApiLevelForRuntime.get());
+                        new TestParameters(
+                            runtime,
+                            api,
+                            PartialCompilationTestParameters.NONE,
+                            representativeApiLevelForRuntime.get());
                     representativeApiLevelForRuntime.unset();
                     return parameters;
                   });
         }
       }
     }
-    return Stream.of(new TestParameters(runtime, lowestApplicable));
+    return Stream.of(
+        new TestParameters(runtime, lowestApplicable, PartialCompilationTestParameters.NONE, true));
   }
 
   // Public method to check that the CF runtime coincides with the system runtime.
@@ -371,18 +380,4 @@
     }
     return getUnfilteredAvailableRuntimes();
   }
-
-  public static List<CfVm> getAvailableCfVms() {
-    return getAvailableRuntimes()
-        .filter(TestRuntime::isCf)
-        .map(runtime -> runtime.asCf().getVm())
-        .collect(Collectors.toList());
-  }
-
-  public static List<DexVm> getAvailableDexVms() {
-    return getAvailableRuntimes()
-        .filter(TestRuntime::isDex)
-        .map(runtime -> runtime.asDex().getVm())
-        .collect(Collectors.toList());
-  }
 }