Add test_base module

In preperation of adding support for running jdk version specific tests add a base module to contain the testing utils.

This allows us to easily share these across other modules, without having to depend on the test_java8 module

This also moves all common test dependencies to the test_base module, with other modules depending on this jar

Bug: 327326057
Change-Id: Iaccc178c410fb75c64ec1af67e33c5070355aef3
diff --git a/d8_r8/test/build.gradle.kts b/d8_r8/test/build.gradle.kts
index 2f81edc..ef3e504 100644
--- a/d8_r8/test/build.gradle.kts
+++ b/d8_r8/test/build.gradle.kts
@@ -25,8 +25,9 @@
 val r8WithRelocatedDepsTask = projectTask("main", "r8WithRelocatedDeps")
 val mainSourcesTask = projectTask("main", "sourcesJar")
 val resourceShrinkerSourcesTask = projectTask("resourceshrinker", "sourcesJar")
+val javaTestBaseJarTask = projectTask("testbase", "testJar")
+val javaTestBaseDepsJar = projectTask("testbase", "depsJar")
 val java8TestJarTask = projectTask("tests_java_8", "testJar")
-val java8TestsDepsJarTask = projectTask("tests_java_8", "depsJar")
 val bootstrapTestsDepsJarTask = projectTask("tests_bootstrap", "depsJar")
 val testsJava8SourceSetDependenciesTask = projectTask("tests_java_8", "sourceSetDependencyTask")
 
@@ -62,15 +63,23 @@
   }
 
   val packageTestDeps by registering(Jar::class) {
-    dependsOn(bootstrapTestsDepsJarTask, java8TestsDepsJarTask)
+    dependsOn(bootstrapTestsDepsJarTask, javaTestBaseDepsJar)
     from(bootstrapTestsDepsJarTask.outputs.getFiles().map(::zipTree))
-    from(java8TestsDepsJarTask.outputs.getFiles().map(::zipTree))
+    from(javaTestBaseDepsJar.outputs.getFiles().map(::zipTree))
     exclude("META-INF/*.kotlin_module", "**/*.kotlin_metadata")
     duplicatesStrategy = DuplicatesStrategy.EXCLUDE
     destinationDirectory.set(getRoot().resolveAll("build", "libs"))
     archiveFileName.set("test_deps_all.jar")
   }
 
+  val packageTestBase by registering(Jar::class) {
+    dependsOn(javaTestBaseJarTask)
+    from(javaTestBaseJarTask.outputs.files.map(::zipTree))
+    exclude("META-INF/*.kotlin_module", "**/*.kotlin_metadata")
+    destinationDirectory.set(getRoot().resolveAll("build", "libs"))
+    archiveFileName.set("r8test_base.jar")
+  }
+
   // When testing R8 lib with relocated deps we must relocate kotlinx.metadata in the tests, since
   // types from kotlinx.metadata are used on the R8 main/R8 test boundary.
   //
@@ -95,27 +104,23 @@
   }
 
   fun Exec.generateKeepRulesForR8Lib(
-          targetJarProvider: Task, testJarProvider: TaskProvider<*>, artifactName: String) {
+          targetJarProvider: Task, testJarProviders: List<TaskProvider<*>>, artifactName: String) {
     dependsOn(
             mainDepsJarTask,
             packageTestDeps,
             r8WithRelocatedDepsTask,
-            targetJarProvider,
-            testJarProvider)
+            targetJarProvider)
+    testJarProviders.forEach(::dependsOn)
     val mainDepsJar = mainDepsJarTask.getSingleOutputFile()
     val rtJar = resolve(ThirdPartyDeps.java8Runtime, "rt.jar").getSingleFile()
     val r8WithRelocatedDepsJar = r8WithRelocatedDepsTask.getSingleOutputFile()
     val targetJar = targetJarProvider.getSingleOutputFile()
     val testDepsJar = packageTestDeps.getSingleOutputFile()
-    val testJar = testJarProvider.getSingleOutputFile()
-    inputs.files(mainDepsJar, rtJar, r8WithRelocatedDepsJar, targetJar, testDepsJar, testJar)
+    inputs.files(mainDepsJar, rtJar, r8WithRelocatedDepsJar, targetJar, testDepsJar)
+    inputs.files(testJarProviders.map{it.getSingleOutputFile()})
     val output = file(Paths.get("build", "libs", artifactName))
     outputs.file(output)
-    commandLine = baseCompilerCommandLine(
-            r8WithRelocatedDepsJar,
-            "tracereferences",
-            listOf(
-                    "--keep-rules",
+    val argList = mutableListOf("--keep-rules",
                     "--allowobfuscation",
                     "--lib",
                     "$rtJar",
@@ -125,23 +130,30 @@
                     "$testDepsJar",
                     "--target",
                     "$targetJar",
-                    "--source",
-                    "$testJar",
                     "--output",
-                    "$output"))
+                    "$output")
+    testJarProviders.forEach{
+      argList.add("--source")
+      argList.add("${it.getSingleOutputFile()}")
+    }
+    commandLine = baseCompilerCommandLine(
+            r8WithRelocatedDepsJar,
+            "tracereferences",
+            argList
+    )
   }
 
   val generateKeepRulesForR8LibWithRelocatedDeps by registering(Exec::class) {
     generateKeepRulesForR8Lib(
             r8WithRelocatedDepsTask,
-            relocateTestsForR8LibWithRelocatedDeps,
+            listOf(relocateTestsForR8LibWithRelocatedDeps, packageTestBase),
             "generated-keep-rules-r8lib.txt")
   }
 
   val generateKeepRulesForR8LibNoDeps by registering(Exec::class) {
     generateKeepRulesForR8Lib(
             swissArmyKnifeTask,
-            packageTests,
+            listOf(packageTests, packageTestBase),
             "generated-keep-rules-r8lib-exclude-deps.txt")
   }
 
@@ -237,40 +249,48 @@
           keepRulesFileProvider: TaskProvider<Task>,
           r8JarProvider: Task,
           testJarProvider: TaskProvider<*>,
-          artifactName: String) {
+          artifactName: String,
+          addTestBaseClasspath: Boolean) {
     dependsOn(
             keepRulesFileProvider,
             packageTestDeps,
             relocateTestsForR8LibWithRelocatedDeps,
             r8JarProvider,
             r8WithRelocatedDepsTask,
-            testJarProvider)
+            testJarProvider,
+            packageTestBase)
     val keepRulesFile = keepRulesFileProvider.getSingleOutputFile()
     val rtJar = resolve(ThirdPartyDeps.java8Runtime, "rt.jar").getSingleFile()
     val r8Jar = r8JarProvider.getSingleOutputFile()
     val r8WithRelocatedDepsJar = r8WithRelocatedDepsTask.getSingleOutputFile()
+    val testBaseJar = packageTestBase.getSingleOutputFile()
     val testDepsJar = packageTestDeps.getSingleOutputFile()
     val testJar = testJarProvider.getSingleOutputFile()
     inputs.files(keepRulesFile, rtJar, r8Jar, r8WithRelocatedDepsJar, testDepsJar, testJar)
     val outputJar = getRoot().resolveAll("build", "libs", artifactName)
     outputs.file(outputJar)
+    val args = mutableListOf(
+      "--classfile",
+      "--debug",
+      "--lib",
+      "$rtJar",
+      "--classpath",
+      "$r8Jar",
+      "--classpath",
+      "$testDepsJar",
+      "--output",
+      "$outputJar",
+      "--pg-conf",
+      "$keepRulesFile",
+      "$testJar")
+    if (addTestBaseClasspath) {
+      args.add("--classpath")
+      args.add("$testBaseJar")
+    }
     commandLine = baseCompilerCommandLine(
             r8WithRelocatedDepsJar,
             "r8",
-            listOf(
-                    "--classfile",
-                    "--debug",
-                    "--lib",
-                    "$rtJar",
-                    "--classpath",
-                    "$r8Jar",
-                    "--classpath",
-                    "$testDepsJar",
-                    "--output",
-                    "$outputJar",
-                    "--pg-conf",
-                    "$keepRulesFile",
-                    "$testJar"))
+            args)
   }
 
   val rewriteTestsForR8LibWithRelocatedDeps by registering(Exec::class) {
@@ -278,7 +298,17 @@
             generateTestKeepRulesR8LibWithRelocatedDeps,
             r8WithRelocatedDepsTask,
             relocateTestsForR8LibWithRelocatedDeps,
-            "r8libtestdeps-cf.jar")
+            "r8libtestdeps-cf.jar",
+            true)
+  }
+
+  val rewriteTestBaseForR8LibWithRelocatedDeps by registering(Exec::class) {
+    rewriteTestsForR8Lib(
+            generateTestKeepRulesR8LibWithRelocatedDeps,
+            r8WithRelocatedDepsTask,
+            packageTestBase,
+            "r8libtestbase-cf.jar",
+            false)
   }
 
   val rewriteTestsForR8LibNoDeps by registering(Exec::class) {
@@ -286,7 +316,8 @@
             generateTestKeepRulesR8LibNoDeps,
             swissArmyKnifeTask,
             packageTests,
-            "r8lib-exclude-deps-testdeps-cf.jar")
+            "r8lib-exclude-deps-testdeps-cf.jar",
+            true)
   }
 
   val cleanUnzipTests by registering(Delete::class) {
@@ -340,6 +371,7 @@
             r8Lib,
             r8WithRelocatedDepsTask,
             testsJava8SourceSetDependenciesTask,
+            rewriteTestBaseForR8LibWithRelocatedDeps,
             unzipRewrittenTests,
             unzipTests,
             gradle.includedBuild("shared").task(":downloadDeps"))
@@ -356,7 +388,8 @@
     classpath = files(
             packageTestDeps.get().getOutputs().getFiles(),
             r8LibJar,
-            unzipRewrittenTests.get().getOutputs().getFiles())
+            unzipRewrittenTests.get().getOutputs().getFiles(),
+            rewriteTestBaseForR8LibWithRelocatedDeps.getSingleOutputFile())
     testClassesDirs = unzipRewrittenTests.get().getOutputs().getFiles()
     systemProperty("TEST_DATA_LOCATION", unzipTests.getSingleOutputFile())
     systemProperty(
@@ -408,4 +441,4 @@
 
 fun TaskOutputs.getSingleOutputFile(): File = getFiles().getSingleFile()
 
-fun TaskProvider<*>.getSingleOutputFile(): File = get().getSingleOutputFile()
\ No newline at end of file
+fun TaskProvider<*>.getSingleOutputFile(): File = get().getSingleOutputFile()
diff --git a/d8_r8/test/settings.gradle.kts b/d8_r8/test/settings.gradle.kts
index 5c2726d..d114948 100644
--- a/d8_r8/test/settings.gradle.kts
+++ b/d8_r8/test/settings.gradle.kts
@@ -28,6 +28,7 @@
 includeBuild(root.resolve("keepanno"))
 includeBuild(root.resolve("main"))
 includeBuild(root.resolve("resourceshrinker"))
+includeBuild(root.resolve("test_modules").resolve("testbase"))
 includeBuild(root.resolve("test_modules").resolve("tests_bootstrap"))
 includeBuild(root.resolve("test_modules").resolve("tests_java_8"))
 includeBuild(root.resolve("test_modules").resolve("tests_java_9"))
diff --git a/d8_r8/test_modules/testbase/build.gradle.kts b/d8_r8/test_modules/testbase/build.gradle.kts
new file mode 100644
index 0000000..2d66a1c
--- /dev/null
+++ b/d8_r8/test_modules/testbase/build.gradle.kts
@@ -0,0 +1,117 @@
+// Copyright (c) 2024, 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.
+
+import org.gradle.api.JavaVersion
+import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
+
+plugins {
+  `kotlin-dsl`
+  `java-library`
+  id("dependencies-plugin")
+}
+
+val root = getRoot()
+
+java {
+  sourceSets.main.configure {
+    java {
+      srcDir(root.resolveAll("src", "test", "testbase", "java"))
+    }
+  }
+
+  // We are using a new JDK to compile to an older language version, which is not directly
+  // compatible with java toolchains.
+  sourceCompatibility = JavaVersion.VERSION_1_8
+  targetCompatibility = JavaVersion.VERSION_1_8
+}
+
+// If we depend on keepanno by referencing the project source outputs we get an error regarding
+// incompatible java class file version. By depending on the jar we circumvent that.
+val keepAnnoJarTask = projectTask("keepanno", "jar")
+val keepAnnoCompileTask = projectTask("keepanno", "compileJava")
+val mainCompileTask = projectTask("main", "compileJava")
+val mainDepsJarTask = projectTask("main", "depsJar")
+val resourceShrinkerJavaCompileTask = projectTask("resourceshrinker", "compileJava")
+val resourceShrinkerKotlinCompileTask = projectTask("resourceshrinker", "compileKotlin")
+val resourceShrinkerDepsJarTask = projectTask("resourceshrinker", "depsJar")
+
+dependencies {
+  implementation(keepAnnoJarTask.outputs.files)
+  implementation(mainCompileTask.outputs.files)
+  implementation(projectTask("main", "processResources").outputs.files)
+  implementation(resourceShrinkerJavaCompileTask.outputs.files)
+  implementation(resourceShrinkerKotlinCompileTask.outputs.files)
+  implementation(resourceShrinkerDepsJarTask.outputs.files)
+  implementation(Deps.asm)
+  implementation(Deps.asmCommons)
+  implementation(Deps.asmUtil)
+  implementation(Deps.gson)
+  implementation(Deps.guava)
+  implementation(Deps.javassist)
+  implementation(Deps.junit)
+  implementation(Deps.kotlinStdLib)
+  implementation(Deps.kotlinReflect)
+  implementation(Deps.kotlinMetadata)
+  implementation(resolve(ThirdPartyDeps.ddmLib,"ddmlib.jar"))
+  implementation(resolve(ThirdPartyDeps.jasmin,"jasmin-2.4.jar"))
+  implementation(resolve(ThirdPartyDeps.jdwpTests,"apache-harmony-jdwp-tests-host.jar"))
+  implementation(Deps.fastUtil)
+  implementation(Deps.smali)
+  implementation(Deps.smaliUtil)
+}
+
+
+fun testDependencies() : FileCollection {
+  return sourceSets
+    .test
+    .get()
+    .compileClasspath
+    .filter {
+        "$it".contains("third_party")
+          && !"$it".contains("errorprone")
+          && !"$it".contains("third_party/gradle")
+    }
+}
+
+tasks {
+  withType<JavaCompile> {
+    dependsOn(gradle.includedBuild("keepanno").task(":jar"))
+    dependsOn(gradle.includedBuild("resourceshrinker").task(":jar"))
+    dependsOn(gradle.includedBuild("main").task(":compileJava"))
+    dependsOn(gradle.includedBuild("main").task(":processResources"))
+    dependsOn(gradle.includedBuild("shared").task(":downloadDeps"))
+  }
+
+  withType<JavaExec> {
+    if (name.endsWith("main()")) {
+      // IntelliJ pass the main execution through a stream which is
+      // not compatible with gradle configuration cache.
+      notCompatibleWithConfigurationCache("JavaExec created by IntelliJ")
+    }
+  }
+
+  withType<KotlinCompile> {
+    enabled = false
+  }
+
+  val testJar by registering(Jar::class) {
+    from(sourceSets.main.get().output)
+    // TODO(b/296486206): Seems like IntelliJ has a problem depending on test source sets. Renaming
+    //  this from the default name (testbase.jar) will allow IntelliJ to find the resources in
+    //  the jar and not show red underlines. However, navigation to base classes will not work.
+    archiveFileName.set("not_named_testbase.jar")
+  }
+
+  val depsJar by registering(Jar::class) {
+    dependsOn(gradle.includedBuild("shared").task(":downloadDeps"))
+    dependsOn(gradle.includedBuild("keepanno").task(":jar"))
+    dependsOn(gradle.includedBuild("resourceshrinker").task(":jar"))
+    from(testDependencies().map(::zipTree))
+    from(resourceShrinkerDepsJarTask.outputs.getFiles().map(::zipTree))
+    from(keepAnnoJarTask.outputs.getFiles().map(::zipTree))
+    exclude("com/android/tools/r8/keepanno/annotations/**")
+    duplicatesStrategy = DuplicatesStrategy.EXCLUDE
+    archiveFileName.set("deps.jar")
+  }
+}
diff --git a/d8_r8/test_modules/testbase/settings.gradle.kts b/d8_r8/test_modules/testbase/settings.gradle.kts
new file mode 100644
index 0000000..97fe72b
--- /dev/null
+++ b/d8_r8/test_modules/testbase/settings.gradle.kts
@@ -0,0 +1,33 @@
+// Copyright (c) 2024, 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.
+
+pluginManagement {
+  repositories {
+    maven {
+      url = uri("file:../../../third_party/dependencies_plugin")
+    }
+    maven {
+      url = uri("file:../../../third_party/dependencies")
+    }
+  }
+}
+
+dependencyResolutionManagement {
+  repositories {
+    maven {
+      url = uri("file:../../../third_party/dependencies")
+    }
+  }
+}
+
+rootProject.name = "testbase"
+
+val root = rootProject.projectDir.parentFile.parentFile
+includeBuild(root.resolve("shared"))
+includeBuild(root.resolve("keepanno"))
+includeBuild(root.resolve("resourceshrinker"))
+
+// We need to include src/main as a composite-build otherwise our test-modules
+// will compete with the test to compile the source files.
+includeBuild(root.resolve("main"))
diff --git a/d8_r8/test_modules/tests_java_8/build.gradle.kts b/d8_r8/test_modules/tests_java_8/build.gradle.kts
index 98ab1c9..1d76606 100644
--- a/d8_r8/test_modules/tests_java_8/build.gradle.kts
+++ b/d8_r8/test_modules/tests_java_8/build.gradle.kts
@@ -28,6 +28,10 @@
   targetCompatibility = JavaVersion.VERSION_1_8
 }
 
+
+val testbaseJavaCompileTask = projectTask("testbase", "compileJava")
+val testbaseDepsJarTask = projectTask("testbase", "depsJar")
+
 // If we depend on keepanno by referencing the project source outputs we get an error regarding
 // incompatible java class file version. By depending on the jar we circumvent that.
 val keepAnnoJarTask = projectTask("keepanno", "jar")
@@ -45,22 +49,8 @@
   implementation(resourceShrinkerJavaCompileTask.outputs.files)
   implementation(resourceShrinkerKotlinCompileTask.outputs.files)
   implementation(resourceShrinkerDepsJarTask.outputs.files)
-  implementation(Deps.asm)
-  implementation(Deps.asmCommons)
-  implementation(Deps.asmUtil)
-  implementation(Deps.gson)
-  implementation(Deps.guava)
-  implementation(Deps.javassist)
-  implementation(Deps.junit)
-  implementation(Deps.kotlinStdLib)
-  implementation(Deps.kotlinReflect)
-  implementation(Deps.kotlinMetadata)
-  implementation(resolve(ThirdPartyDeps.ddmLib,"ddmlib.jar"))
-  implementation(resolve(ThirdPartyDeps.jasmin,"jasmin-2.4.jar"))
-  implementation(resolve(ThirdPartyDeps.jdwpTests,"apache-harmony-jdwp-tests-host.jar"))
-  implementation(Deps.fastUtil)
-  implementation(Deps.smali)
-  implementation(Deps.smaliUtil)
+  implementation(testbaseDepsJarTask.outputs.files)
+  implementation(testbaseJavaCompileTask.outputs.files)
 }
 
 val sourceSetDependenciesTasks = arrayOf(
@@ -102,9 +92,11 @@
     commandLine("python3", createArtTestsScript)
   }
   "compileTestJava" {
+    dependsOn(testbaseJavaCompileTask)
     dependsOn(gradle.includedBuild("shared").task(":downloadDeps"))
   }
   withType<JavaCompile> {
+    dependsOn(testbaseJavaCompileTask)
     dependsOn(createArtTests)
     dependsOn(gradle.includedBuild("keepanno").task(":jar"))
     dependsOn(gradle.includedBuild("resourceshrinker").task(":jar"))
@@ -164,16 +156,4 @@
     //  the jar and not show red underlines. However, navigation to base classes will not work.
     archiveFileName.set("not_named_tests_java_8.jar")
   }
-
-  val depsJar by registering(Jar::class) {
-    dependsOn(gradle.includedBuild("shared").task(":downloadDeps"))
-    dependsOn(gradle.includedBuild("keepanno").task(":jar"))
-    dependsOn(gradle.includedBuild("resourceshrinker").task(":jar"))
-    from(testDependencies().map(::zipTree))
-    from(resourceShrinkerDepsJarTask.outputs.getFiles().map(::zipTree))
-    from(keepAnnoJarTask.outputs.getFiles().map(::zipTree))
-    exclude("com/android/tools/r8/keepanno/annotations/**")
-    duplicatesStrategy = DuplicatesStrategy.EXCLUDE
-    archiveFileName.set("deps.jar")
-  }
 }
diff --git a/d8_r8/test_modules/tests_java_8/settings.gradle.kts b/d8_r8/test_modules/tests_java_8/settings.gradle.kts
index d54c456..a28a94f 100644
--- a/d8_r8/test_modules/tests_java_8/settings.gradle.kts
+++ b/d8_r8/test_modules/tests_java_8/settings.gradle.kts
@@ -31,6 +31,7 @@
 // We need to include src/main as a composite-build otherwise our test-modules
 // will compete with the test to compile the source files.
 includeBuild(root.resolve("main"))
+includeBuild(root.resolve("test_modules").resolve("testbase"))
 includeBuild(root.resolve("test_modules").resolve("tests_java_9"))
 includeBuild(root.resolve("test_modules").resolve("tests_java_10"))
 includeBuild(root.resolve("test_modules").resolve("tests_java_11"))
diff --git a/src/test/java/com/android/tools/r8/ThrowableConsumer.java b/src/test/testbase/java/com/android/tools/r8/ThrowableConsumer.java
similarity index 100%
rename from src/test/java/com/android/tools/r8/ThrowableConsumer.java
rename to src/test/testbase/java/com/android/tools/r8/ThrowableConsumer.java