1 /*
<lambda>null2  * Copyright 2023 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package androidx.baselineprofile.gradle.apptarget
18 
19 import androidx.baselineprofile.gradle.utils.BaselineProfileProjectSetupRule
20 import androidx.baselineprofile.gradle.utils.TestAgpVersion
21 import androidx.baselineprofile.gradle.utils.TestAgpVersion.TEST_AGP_VERSION_8_1_1
22 import androidx.baselineprofile.gradle.utils.build
23 import androidx.baselineprofile.gradle.utils.buildAndAssertThatOutput
24 import androidx.baselineprofile.gradle.utils.containsOnly
25 import com.google.common.truth.Truth.assertThat
26 import java.io.File
27 import org.junit.Rule
28 import org.junit.Test
29 import org.junit.runner.RunWith
30 import org.junit.runners.Parameterized
31 
32 private fun createBuildGradle(overrideExtendedBuildTypesForRelease: Boolean = false) =
33     """
34     import static com.android.build.gradle.internal.ProguardFileType.EXPLICIT;
35 
36     plugins {
37         id("com.android.application")
38         id("androidx.baselineprofile.apptarget")
39     }
40 
41     android {
42         namespace 'com.example.namespace'
43         buildTypes {
44 
45             ${
46         if (overrideExtendedBuildTypesForRelease) """
47 
48             benchmarkRelease {
49                 initWith(release)
50                 profileable true
51             }
52             nonMinifiedRelease {
53                 initWith(release)
54             }
55 
56             """.trimIndent() else ""
57     }
58 
59             anotherRelease {
60                 initWith(release)
61                 minifyEnabled true
62                 postprocessing {
63                     proguardFile("proguard-rules1.pro")
64                 }
65             }
66             myCustomRelease {
67                 initWith(release)
68                 minifyEnabled false
69                 proguardFiles "proguard-rules2.pro"
70             }
71             benchmarkMyCustomRelease {
72                 initWith(myCustomRelease)
73 
74                 // These are the opposite of default ensure the plugin doesn't modify them
75                 minifyEnabled false
76                 shrinkResources false
77             }
78             nonMinifiedMyCustomRelease {
79                 initWith(myCustomRelease)
80 
81                 // These are the opposite of default ensure the plugin does modify them
82                 debuggable true
83                 minifyEnabled true
84                 shrinkResources true
85                 profileable false
86             }
87         }
88     }
89 
90     def printVariantsTaskProvider = tasks.register("printVariants", PrintTask) { t ->
91         t.text.set("")
92     }
93 
94     androidComponents {
95         onVariants(selector()) { variant ->
96             printVariantsTaskProvider.configure { t ->
97                 t.text.set(t.text.get() + "\n" + "print-variant:" + variant.name)
98             }
99             tasks.register(variant.name + "BuildProperties", PrintTask) { t ->
100                 def buildType = android.buildTypes[variant.buildType]
101                 def text = "minifyEnabled=" + buildType.minifyEnabled.toString() + "\n"
102                 text += "testCoverageEnabled=" + buildType.testCoverageEnabled.toString() + "\n"
103                 text += "debuggable=" + buildType.debuggable.toString() + "\n"
104                 text += "profileable=" + buildType.profileable.toString() + "\n"
105                 text += "proguardFiles=" + buildType.proguardFiles.toString() + "\n"
106                 text += "postProcessingProguardFiles=" + buildType.postprocessing.getProguardFiles(EXPLICIT) + "\n"
107                 t.text.set(text)
108             }
109             tasks.register(variant.name + "JavaSources", DisplaySourceSets) { t ->
110                 t.srcs.set(variant.sources.java.all)
111             }
112             tasks.register(variant.name + "KotlinSources", DisplaySourceSets) { t ->
113                 t.srcs.set(variant.sources.kotlin.all)
114             }
115         }
116     }
117     """
118         .trimIndent()
119 
120 @RunWith(Parameterized::class)
121 class BaselineProfileAppTargetPluginTestWithAgp81AndAbove(agpVersion: TestAgpVersion) {
122 
123     companion object {
124         @Parameterized.Parameters(name = "agpVersion={0}")
125         @JvmStatic
parametersnull126         fun parameters() = TestAgpVersion.atLeast(TEST_AGP_VERSION_8_1_1)
127     }
128 
129     @get:Rule
130     val projectSetup = BaselineProfileProjectSetupRule(forceAgpVersion = agpVersion.versionString)
131 
132     private val buildGradle = createBuildGradle()
133 
134     @Test
135     fun additionalBuildTypesShouldNotBeCreatedForExistingNonMinifiedAndBenchmarkBuildTypes() =
136         arrayOf(
137                 true,
138                 false,
139             )
140             .forEach { overrideExtendedBuildTypesForRelease ->
141                 projectSetup.appTarget.setBuildGradle(
142                     buildGradleContent =
143                         createBuildGradle(
144                             overrideExtendedBuildTypesForRelease =
145                                 overrideExtendedBuildTypesForRelease,
146                         )
147                 )
148                 projectSetup.appTarget.gradleRunner.build("printVariants") {
149                     val variants =
150                         it.lines()
151                             .filter { l -> l.startsWith("print-variant:") }
152                             .map { l -> l.substringAfter("print-variant:").trim() }
153                             .toSet()
154                             .toList()
155 
156                     assertThat(
157                             variants.containsOnly(
158                                 "debug",
159                                 "release",
160                                 "benchmarkRelease",
161                                 "nonMinifiedRelease",
162                                 "anotherRelease",
163                                 "nonMinifiedAnotherRelease",
164                                 "benchmarkAnotherRelease",
165                                 "myCustomRelease",
166                                 "nonMinifiedMyCustomRelease",
167                                 "benchmarkMyCustomRelease",
168                             )
169                         )
170                         .isTrue()
171                 }
172             }
173 
174     @Test
verifyUnitTestDisablednull175     fun verifyUnitTestDisabled() {
176         projectSetup.appTarget.setBuildGradle(buildGradle)
177         projectSetup.appTarget.gradleRunner.buildAndAssertThatOutput("test", "--dry-run") {
178             contains(":testDebugUnitTest ")
179             contains(":testReleaseUnitTest ")
180             contains(":testAnotherReleaseUnitTest ")
181             doesNotContain(":testNonMinifiedReleaseUnitTest ")
182             doesNotContain(":testBenchmarkReleaseUnitTest ")
183             doesNotContain(":testNonMinifiedAnotherReleaseUnitTest ")
184             doesNotContain(":testBenchmarkAnotherReleaseUnitTest ")
185         }
186     }
187 
188     @Test
verifyNewBuildTypesnull189     fun verifyNewBuildTypes() {
190         projectSetup.appTarget.setBuildGradle(buildGradle)
191 
192         // Assert properties of the benchmark build types
193         projectSetup.appTarget.gradleRunner.buildAndAssertThatOutput(
194             "benchmarkReleaseBuildProperties"
195         ) {
196             contains("testCoverageEnabled=false")
197             contains("debuggable=false")
198             contains("profileable=true")
199 
200             // This value is false for `release` so it should be copied over.
201             contains("minifyEnabled=false")
202         }
203 
204         projectSetup.appTarget.gradleRunner.buildAndAssertThatOutput(
205             "benchmarkAnotherReleaseBuildProperties"
206         ) {
207             contains("testCoverageEnabled=false")
208             contains("debuggable=false")
209             contains("profileable=true")
210 
211             // This value is true for `release` so it should be copied over.
212             contains("minifyEnabled=true")
213         }
214 
215         // Assert properties of the baseline profile build types.
216         arrayOf("nonMinifiedReleaseBuildProperties", "nonMinifiedAnotherReleaseBuildProperties")
217             .forEach { taskName ->
218                 projectSetup.appTarget.gradleRunner.buildAndAssertThatOutput(taskName) {
219                     contains("minifyEnabled=false")
220                     contains("testCoverageEnabled=false")
221                     contains("debuggable=false")
222                     contains("profileable=true")
223                 }
224             }
225     }
226 
227     @Test
verifyOverrideBuildTypesnull228     fun verifyOverrideBuildTypes() {
229         projectSetup.appTarget.setBuildGradle(buildGradle)
230 
231         projectSetup.appTarget.gradleRunner.buildAndAssertThatOutput(
232             "benchmarkMyCustomReleaseBuildProperties"
233         ) {
234 
235             // Should be overridden
236             contains("testCoverageEnabled=false")
237             contains("debuggable=false")
238             contains("profileable=true")
239 
240             // Should not be overridden
241             contains("minifyEnabled=false")
242         }
243 
244         projectSetup.appTarget.gradleRunner.buildAndAssertThatOutput(
245             "nonMinifiedMyCustomReleaseBuildProperties"
246         ) {
247 
248             // Should all be overridden
249             contains("minifyEnabled=false")
250             contains("testCoverageEnabled=false")
251             contains("debuggable=false")
252             contains("profileable=true")
253         }
254     }
255 
256     @Test
verifyProguardFilesAreCopiedInExtendedBuildTypesnull257     fun verifyProguardFilesAreCopiedInExtendedBuildTypes() {
258         projectSetup.appTarget.setBuildGradle(buildGradle)
259 
260         data class TaskAndExpected(
261             val benchmarkBuildType: String,
262             val baselineProfileBuildType: String,
263             val expectedProguardFile: String?,
264             val expectedPostProcessingProguardFile: String?
265         )
266 
267         arrayOf(
268                 TaskAndExpected(
269                     benchmarkBuildType = "benchmarkRelease",
270                     baselineProfileBuildType = "nonMinifiedRelease",
271                     expectedProguardFile = null,
272                     expectedPostProcessingProguardFile = null,
273                 ),
274                 TaskAndExpected(
275                     benchmarkBuildType = "benchmarkAnotherRelease",
276                     baselineProfileBuildType = "nonMinifiedAnotherRelease",
277                     expectedProguardFile = null,
278                     expectedPostProcessingProguardFile = "proguard-rules1.pro",
279                 ),
280                 TaskAndExpected(
281                     benchmarkBuildType = "benchmarkMyCustomRelease",
282                     baselineProfileBuildType = "nonMinifiedMyCustomRelease",
283                     expectedProguardFile = "proguard-rules2.pro",
284                     expectedPostProcessingProguardFile = null,
285                 ),
286             )
287             .forEach {
288                 projectSetup.appTarget.gradleRunner.buildAndAssertThatOutput(
289                     "${it.benchmarkBuildType}BuildProperties"
290                 ) {
291                     if (it.expectedProguardFile != null) {
292                         contains(
293                             "proguardFiles=[${
294                                 File(
295                                     projectSetup.appTarget.rootDir.canonicalFile,
296                                     it.expectedProguardFile
297                                 )
298                             }]"
299                         )
300                     }
301                     if (it.expectedPostProcessingProguardFile != null) {
302                         containsMatch(
303                             "postProcessingProguardFiles=\\[[^,]+, ${
304                                 File(
305                                     projectSetup.appTarget.rootDir.canonicalFile,
306                                     it.expectedPostProcessingProguardFile
307                                 )
308                             }"
309                         )
310                     }
311                 }
312                 projectSetup.appTarget.gradleRunner.buildAndAssertThatOutput(
313                     "${it.baselineProfileBuildType}BuildProperties"
314                 ) {
315                     if (it.expectedProguardFile != null) {
316                         contains(
317                             "proguardFiles=[${
318                                 File(
319                                     projectSetup.appTarget.rootDir.canonicalFile,
320                                     it.expectedProguardFile
321                                 )
322                             }]"
323                         )
324                     }
325                     if (it.expectedPostProcessingProguardFile != null) {
326                         containsMatch(
327                             "postProcessingProguardFiles=\\[[^,]+, ${
328                                 File(
329                                     projectSetup.appTarget.rootDir.canonicalFile,
330                                     it.expectedPostProcessingProguardFile
331                                 )
332                             }"
333                         )
334                     }
335                 }
336             }
337     }
338 }
339 
340 @RunWith(Parameterized::class)
341 class BaselineProfileAppTargetPluginTestWithAgp80AndAbove(agpVersion: TestAgpVersion) {
342 
343     companion object {
344         @Parameterized.Parameters(name = "agpVersion={0}")
345         @JvmStatic
parametersnull346         fun parameters() = TestAgpVersion.atLeast(TEST_AGP_VERSION_8_1_1)
347     }
348 
349     @get:Rule
350     val projectSetup = BaselineProfileProjectSetupRule(forceAgpVersion = agpVersion.versionString)
351 
352     private val buildGradle = createBuildGradle()
353 
354     @Test
355     fun testSrcSetAreAddedToVariantsForApplications() {
356         projectSetup.appTarget.setBuildGradle(buildGradle)
357 
358         data class TaskAndExpected(val taskName: String, val expectedDirs: List<String>)
359 
360         arrayOf(
361                 TaskAndExpected(
362                     taskName = "nonMinifiedAnotherReleaseJavaSources",
363                     expectedDirs =
364                         listOf(
365                             "src/main/java",
366                             "src/anotherRelease/java",
367                             "src/nonMinifiedAnotherRelease/java",
368                         )
369                 ),
370                 TaskAndExpected(
371                     taskName = "nonMinifiedReleaseJavaSources",
372                     expectedDirs =
373                         listOf(
374                             "src/main/java",
375                             "src/release/java",
376                             "src/nonMinifiedRelease/java",
377                         )
378                 ),
379                 TaskAndExpected(
380                     taskName = "nonMinifiedAnotherReleaseKotlinSources",
381                     expectedDirs =
382                         listOf(
383                             "src/main/kotlin",
384                             "src/anotherRelease/kotlin",
385                             "src/nonMinifiedAnotherRelease/kotlin",
386                         )
387                 ),
388                 TaskAndExpected(
389                     taskName = "nonMinifiedReleaseKotlinSources",
390                     expectedDirs =
391                         listOf(
392                             "src/main/kotlin",
393                             "src/release/kotlin",
394                             "src/nonMinifiedRelease/kotlin",
395                         )
396                 )
397             )
398             .forEach { t ->
399 
400                 // Runs the task and assert
401                 projectSetup.appTarget.gradleRunner.buildAndAssertThatOutput(t.taskName) {
402                     t.expectedDirs
403                         .map { File(projectSetup.appTarget.rootDir, it) }
404                         .forEach { e -> contains(e.absolutePath) }
405                 }
406             }
407     }
408 
409     @Test
additionalBuildTypesShouldNotBeCreatedForExistingNonMinifiedAndBenchmarkBuildTypesnull410     fun additionalBuildTypesShouldNotBeCreatedForExistingNonMinifiedAndBenchmarkBuildTypes() =
411         arrayOf(
412                 true,
413                 false,
414             )
415             .forEach { overrideExtendedBuildTypesForRelease ->
416                 projectSetup.appTarget.setBuildGradle(
417                     buildGradleContent =
418                         createBuildGradle(
419                             overrideExtendedBuildTypesForRelease =
420                                 overrideExtendedBuildTypesForRelease,
421                         )
422                 )
423 
424                 projectSetup.appTarget.gradleRunner.build("printVariants") {
425                     val variants =
426                         it.lines()
427                             .filter { l -> l.startsWith("print-variant:") }
428                             .map { l -> l.substringAfter("print-variant:").trim() }
429                             .toSet()
430                             .toList()
431 
432                     assertThat(
433                             variants.containsOnly(
434                                 "debug",
435                                 "release",
436                                 "nonMinifiedRelease",
437                                 "anotherRelease",
438                                 "nonMinifiedAnotherRelease",
439                                 "myCustomRelease",
440                                 "nonMinifiedMyCustomRelease",
441                             )
442                         )
443                         .isTrue()
444                 }
445             }
446 }
447