Add support for an API level test parameter.

First iteration just supports specifying indifference to the level in tests and
that will cause the configurations for DEX runtimes to have two configurations,
one for the lowest and largest API level for that runtime.

Change-Id: Iabb777a6c55ae9c54f9aa76ae01649d11ec23911
diff --git a/src/test/java/com/android/tools/r8/TestParameters.java b/src/test/java/com/android/tools/r8/TestParameters.java
index 1c0b755..d73f975 100644
--- a/src/test/java/com/android/tools/r8/TestParameters.java
+++ b/src/test/java/com/android/tools/r8/TestParameters.java
@@ -4,15 +4,22 @@
 package com.android.tools.r8;
 
 import com.android.tools.r8.TestBase.Backend;
+import com.android.tools.r8.utils.AndroidApiLevel;
 
 // Actual test parameters for a specific configuration. Currently just the runtime configuration.
 public class TestParameters {
 
   private final TestRuntime runtime;
+  private final AndroidApiLevel apiLevel;
 
   public TestParameters(TestRuntime runtime) {
+    this(runtime, null);
+  }
+
+  public TestParameters(TestRuntime runtime, AndroidApiLevel apiLevel) {
     assert runtime != null;
     this.runtime = runtime;
+    this.apiLevel = apiLevel;
   }
 
   // Convenience predicates.
@@ -24,6 +31,14 @@
     return runtime.isCf();
   }
 
+  public AndroidApiLevel getApiLevel() {
+    if (runtime.isDex() && apiLevel == null) {
+      throw new RuntimeException(
+          "Use of getApiLevel without configured API levels for TestParametersCollection.");
+    }
+    return apiLevel;
+  }
+
   // Access to underlying runtime/wrapper.
   public TestRuntime getRuntime() {
     return runtime;
@@ -36,6 +51,9 @@
 
   @Override
   public String toString() {
+    if (apiLevel != null) {
+      return runtime.toString() + ", api:" + apiLevel.getLevel();
+    }
     return runtime.toString();
   }
 }
diff --git a/src/test/java/com/android/tools/r8/TestParametersBuilder.java b/src/test/java/com/android/tools/r8/TestParametersBuilder.java
index 1c3f77c..89f071a 100644
--- a/src/test/java/com/android/tools/r8/TestParametersBuilder.java
+++ b/src/test/java/com/android/tools/r8/TestParametersBuilder.java
@@ -9,6 +9,7 @@
 import com.android.tools.r8.TestRuntime.NoneRuntime;
 import com.android.tools.r8.ToolHelper.DexVm;
 import com.android.tools.r8.errors.Unreachable;
+import com.android.tools.r8.utils.AndroidApiLevel;
 import java.util.Arrays;
 import java.util.List;
 import java.util.function.Predicate;
@@ -132,14 +133,42 @@
     return withDexRuntimeFilter(vm -> vm != endExclusive && vm.isOlderThanOrEqual(endExclusive));
   }
 
+  /**
+   * API level configuration.
+   *
+   * <p>Currently enabling API level config will by default configure each DEX VM to be configured
+   * with two parameters, one running at the highest api-level supported by the VM and one at the
+   * lowest supported by the compiler (i.e., B).
+   */
+  private static final AndroidApiLevel lowestCompilerApiLevel = AndroidApiLevel.B;
+
+  private boolean enableAllApiLevels = false;
+
+  public TestParametersBuilder withAllApiLevels() {
+    enableAllApiLevels = true;
+    return this;
+  }
+
   public TestParametersCollection build() {
     return new TestParametersCollection(
         getAvailableRuntimes()
-            .map(TestParameters::new)
+            .flatMap(this::createParameters)
             .filter(filter)
             .collect(Collectors.toList()));
   }
 
+  public Stream<TestParameters> createParameters(TestRuntime runtime) {
+    if (enableAllApiLevels && runtime.isDex()) {
+      AndroidApiLevel vmLevel = runtime.asDex().getMinApiLevel();
+      if (vmLevel != lowestCompilerApiLevel) {
+        return Stream.of(
+            new TestParameters(runtime, vmLevel),
+            new TestParameters(runtime, lowestCompilerApiLevel));
+      }
+    }
+    return Stream.of(new TestParameters(runtime));
+  }
+
   // Public method to check that the CF runtime coincides with the system runtime.
   public static boolean isSystemJdk(CfVm vm) {
     String version = System.getProperty("java.version");
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 d727ce3..f4917c7 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
@@ -4,12 +4,11 @@
 
 package com.android.tools.r8.shaking.annotations;
 
-import static org.junit.Assume.assumeTrue;
-
 import com.android.tools.r8.NeverInline;
 import com.android.tools.r8.NeverMerge;
 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 java.lang.annotation.Annotation;
 import java.lang.annotation.ElementType;
@@ -31,34 +30,33 @@
           "In OtherInterfaceImpl.targetedMethod()",
           MyAnnotation.class.getName());
 
-  private final Backend backend;
+  private final TestParameters parameters;
 
-  @Parameters(name = "Backend: {0}")
-  public static Backend[] data() {
-    return ToolHelper.getBackends();
+  @Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withAllRuntimes().withAllApiLevels().build();
   }
 
-  public AnnotationsOnTargetedMethodTest(Backend backend) {
-    this.backend = backend;
+  public AnnotationsOnTargetedMethodTest(TestParameters parameters) {
+    this.parameters = parameters;
   }
 
   @Test
-  public void jvmTest() throws Exception {
-    assumeTrue(
-        "JVM test independent of Art version - only run when testing on latest",
-        ToolHelper.getDexVm().getVersion().isLatest());
-    testForJvm().addTestClasspath().run(TestClass.class).assertSuccessWithOutput(expectedOutput);
-  }
-
-  @Test
-  public void r8Test() throws Exception {
-    testForR8(backend)
+  public void test() throws Exception {
+    if (parameters.isCfRuntime()) {
+      testForJvm()
+          .addTestClasspath()
+          .run(parameters.getRuntime(), TestClass.class)
+          .assertSuccessWithOutput(expectedOutput);
+    }
+    testForR8(parameters.getBackend())
         .addInnerClasses(AnnotationsOnTargetedMethodTest.class)
         .addKeepMainRule(TestClass.class)
         .addKeepRules("-keepattributes *Annotation*", "-dontobfuscate")
         .enableInliningAnnotations()
         .enableMergeAnnotations()
-        .run(TestClass.class)
+        .setMinApi(parameters.getApiLevel())
+        .run(parameters.getRuntime(), TestClass.class)
         .assertSuccessWithOutput(expectedOutput);
   }