Clean up code duplication in tests with gradleRunner

Test: ./gradlew room:int-test:room-inc-anno-proc:test
      ./gradlew nav:nav-safe-args-gr-plugin:test
      ./gradlew bench:bench-gradle-plugin:test

Change-Id: I13743a39854ca71fdb8b818a5229dda0d5f43fc5
diff --git a/testutils/testutils-gradle-plugin/build.gradle b/testutils/testutils-gradle-plugin/build.gradle
new file mode 100644
index 0000000..43650cb
--- /dev/null
+++ b/testutils/testutils-gradle-plugin/build.gradle
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import static androidx.build.dependencies.DependenciesKt.*
+
+plugins {
+    id("AndroidXPlugin")
+    id("kotlin")
+}
+
+dependencies {
+    implementation(KOTLIN_STDLIB)
+    implementation(ANDROIDX_TEST_EXT_JUNIT)
+    implementation(ANDROIDX_TEST_CORE)
+    implementation(ANDROIDX_TEST_RULES)
+}
+
+androidx {
+    toolingProject = true
+}
diff --git a/testutils/testutils-gradle-plugin/src/main/java/androidx/testutils/gradle/ProjectSetupRule.kt b/testutils/testutils-gradle-plugin/src/main/java/androidx/testutils/gradle/ProjectSetupRule.kt
new file mode 100644
index 0000000..8fcd36a
--- /dev/null
+++ b/testutils/testutils-gradle-plugin/src/main/java/androidx/testutils/gradle/ProjectSetupRule.kt
@@ -0,0 +1,137 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.testutils.gradle
+
+import org.junit.rules.ExternalResource
+import org.junit.rules.TemporaryFolder
+import org.junit.runner.Description
+import org.junit.runners.model.Statement
+import java.io.File
+import java.lang.IllegalStateException
+import java.util.Properties
+
+/**
+ * Test rule that helps to setup android project in tests that run gradle.
+ *
+ * It should be used along side with SdkResourceGenerator in your build.gradle file
+ */
+class ProjectSetupRule : ExternalResource() {
+    val testProjectDir = TemporaryFolder()
+
+    lateinit var props: ProjectProps
+
+    val rootDir: File
+        get() = testProjectDir.root
+
+    val buildFile: File
+        get() = File(rootDir, "build.gradle")
+
+    val gradlePropertiesFile: File
+        get() = File(rootDir, "gradle.properties")
+
+    private val repositories: String
+        get() = """
+            repositories {
+                maven { url "${props.prebuiltsRoot}/androidx/external" }
+                maven { url "${props.prebuiltsRoot}/androidx/internal" }
+            }
+        """.trimIndent()
+
+    val androidProject: String
+        get() = """
+            android {
+                compileSdkVersion ${props.compileSdkVersion}
+                buildToolsVersion "${props.buildToolsVersion}"
+
+                defaultConfig {
+                    minSdkVersion ${props.minSdkVersion}
+                }
+            }
+        """.trimIndent()
+
+    private val defaultBuildGradle: String
+        get() = "\n$repositories\n\n$androidProject\n\n"
+
+    fun writeDefaultBuildGradle(prefix: String, suffix: String) {
+        buildFile.writeText(prefix)
+        buildFile.appendText(defaultBuildGradle)
+        buildFile.appendText(suffix)
+
+        println(buildFile.readText())
+    }
+
+    override fun apply(base: Statement, description: Description): Statement {
+        return testProjectDir.apply(super.apply(base, description), description)
+    }
+
+    override fun before() {
+        props = ProjectProps.load()
+        buildFile.createNewFile()
+        copyLocalProperties()
+        writeGradleProperties()
+    }
+
+    private fun copyLocalProperties() {
+        val localProperties = File(props.rootProjectPath, "local.properties")
+        if (localProperties.exists()) {
+            localProperties.copyTo(File(rootDir, "local.properties"), overwrite = true)
+        } else {
+            throw IllegalStateException("local.properties doesn't exist at: $localProperties")
+        }
+    }
+
+    private fun writeGradleProperties() {
+        gradlePropertiesFile.writer().use {
+            val props = Properties()
+            props.setProperty("android.useAndroidX", "true")
+            props.store(it, null)
+        }
+    }
+}
+
+data class ProjectProps(
+    val prebuiltsRoot: String,
+    val compileSdkVersion: String,
+    val buildToolsVersion: String,
+    val minSdkVersion: String,
+    val debugKeystore: String,
+    var navigationCommon: String,
+    val kotlinStblib: String,
+    val rootProjectPath: String,
+    val localSupportRepo: String,
+    val agpDependency: String
+) {
+    companion object {
+        fun load(): ProjectProps {
+            val stream = ProjectSetupRule::class.java.classLoader.getResourceAsStream("sdk.prop")
+            val properties = Properties()
+            properties.load(stream)
+            return ProjectProps(
+                prebuiltsRoot = properties.getProperty("prebuiltsRoot"),
+                compileSdkVersion = properties.getProperty("compileSdkVersion"),
+                buildToolsVersion = properties.getProperty("buildToolsVersion"),
+                minSdkVersion = properties.getProperty("minSdkVersion"),
+                debugKeystore = properties.getProperty("debugKeystore"),
+                navigationCommon = properties.getProperty("navigationCommon"),
+                kotlinStblib = properties.getProperty("kotlinStdlib"),
+                rootProjectPath = properties.getProperty("rootProjectPath"),
+                localSupportRepo = properties.getProperty("localSupportRepo"),
+                agpDependency = properties.getProperty("agpDependency")
+            )
+        }
+    }
+}