11package com.telefonica.androidsnaptesting
22
3- import com.android.build.gradle.internal.tasks.AndroidVariantTask
3+ import com.android.build.gradle.TestedExtension
44import com.android.build.gradle.internal.tasks.DeviceProviderInstrumentTestTask
55import org.gradle.api.Plugin
66import org.gradle.api.Project
77import org.gradle.api.Task
8- import org.gradle.internal.build.event.BuildEventListenerRegistryInternal
9- import org.gradle.tooling.events.OperationCompletionListener
8+ import org.gradle.api.provider.ProviderFactory
109import java.io.File
11- import javax.inject.Inject
1210
13- class AndroidSnaptestingPlugin @Inject constructor(
14- private val buildEventListenerRegistry : BuildEventListenerRegistryInternal
15- ) : Plugin<Project> {
11+ class AndroidSnaptestingPlugin : Plugin <Project > {
1612
1713 override fun apply (project : Project ) {
1814 project.afterEvaluate {
@@ -24,32 +20,76 @@ class AndroidSnaptestingPlugin @Inject constructor(
2420 throw AndroidSnaptestingNoDeviceProviderInstrumentTestTasksException ()
2521 }
2622
27- deviceProviderInstrumentTestTasks
28- .forEach { deviceProviderTask ->
29- val capitalizedVariant = deviceProviderTask.variantName.capitalizeFirstLetter()
30- val beforeTaskName = " androidSnaptestingBefore$capitalizedVariant "
31- project.tasks.register(beforeTaskName, Task ::class .java) { task ->
32- task.doFirst {
33- deviceProviderTask.deviceFileManager().clearAllSnapshots()
34- }
35- }
36- deviceProviderTask.dependsOn(beforeTaskName)
23+ val extension = project.extensions.findByType(TestedExtension ::class .java)
24+ ? : throw RuntimeException (" TestedExtension not found" )
3725
38- val afterTaskName = " androidSnaptestingAfter$capitalizedVariant "
39- project.tasks.register(afterTaskName, Task ::class .java) { task ->
40- task.doLast {
41- deviceProviderTask.afterExecution()
42- }
43- }
44- deviceProviderTask.onTaskCompleted {
45- deviceProviderTask.afterExecution()
46- }
26+ val isRecordMode = project.properties[" android.testInstrumentationRunnerArguments.record" ] == " true"
27+ val projectDir = project.projectDir
28+ val providerFactory: ProviderFactory = project.providers
29+
30+ deviceProviderInstrumentTestTasks.names.forEach { taskName ->
31+ val deviceProviderTask = project.tasks.named(
32+ taskName,
33+ DeviceProviderInstrumentTestTask ::class .java,
34+ ).get()
35+ val capitalizedVariant = deviceProviderTask.variantName.capitalizeFirstLetter()
36+
37+ @Suppress(" DEPRECATION" )
38+ val testedVariant = extension.testVariants
39+ .firstOrNull { it.name == deviceProviderTask.variantName }
40+ ? : throw RuntimeException (" TestVariant not found for ${deviceProviderTask.variantName} " )
41+ val applicationIdProvider = providerFactory.provider { testedVariant.applicationId }
42+ val adbExecutablePath = extension.adbExecutable.absolutePath
43+
44+ val goldenSnapshotsSourcePath = run {
45+ val variantSourceFolder = deviceProviderTask
46+ .variantName
47+ .replace(" AndroidTest" , " " )
48+ .capitalizeFirstLetter()
49+ .let { " androidTest$it " }
50+ " $projectDir /src/$variantSourceFolder /assets/android-snaptesting-golden-files"
51+ }
52+
53+ // Attach work directly on the deviceProviderTask (config-cache safe).
54+ // Note: in Kotlin, doFirst/doLast lambdas receive the task as 'it', not 'this'.
55+ deviceProviderTask.doFirst {
56+ (it as DeviceProviderInstrumentTestTask )
57+ .deviceFileManager(applicationIdProvider.get(), adbExecutablePath, providerFactory)
58+ .clearAllSnapshots()
59+ }
60+
61+ deviceProviderTask.doLast {
62+ (it as DeviceProviderInstrumentTestTask )
63+ .afterExecution(
64+ applicationId = applicationIdProvider.get(),
65+ adbExecutablePath = adbExecutablePath,
66+ providerFactory = providerFactory,
67+ isRecordMode = isRecordMode,
68+ goldenSnapshotsSourcePath = goldenSnapshotsSourcePath,
69+ )
4770 }
71+
72+ // Keep empty before/after tasks as dependency anchors for CI scripts
73+ // (e.g. ci.gradle.kts references these task names).
74+ val beforeTaskName = " androidSnaptestingBefore$capitalizedVariant "
75+ project.tasks.register(beforeTaskName, Task ::class .java)
76+ deviceProviderTask.dependsOn(beforeTaskName)
77+
78+ val afterTaskName = " androidSnaptestingAfter$capitalizedVariant "
79+ project.tasks.register(afterTaskName, Task ::class .java)
80+ deviceProviderTask.finalizedBy(afterTaskName)
81+ }
4882 }
4983 }
5084
51- private fun DeviceProviderInstrumentTestTask.afterExecution () {
52- val deviceFileManager = deviceFileManager()
85+ private fun DeviceProviderInstrumentTestTask.afterExecution (
86+ applicationId : String ,
87+ adbExecutablePath : String ,
88+ providerFactory : ProviderFactory ,
89+ isRecordMode : Boolean ,
90+ goldenSnapshotsSourcePath : String ,
91+ ) {
92+ val deviceFileManager = deviceFileManager(applicationId, adbExecutablePath, providerFactory)
5393
5494 val reportsFolder = reportsDir.get().dir(" androidSnaptesting" )
5595 val recordedFolderFile = reportsFolder.dir(" recorded" ).asFile.apply {
@@ -64,7 +104,7 @@ class AndroidSnaptestingPlugin @Inject constructor(
64104 val goldenForFailuresReportFolderFile = reportsFolder.dir(" golden" ).asFile.apply {
65105 mkdirs()
66106 }
67- val goldenFolderFile = File (getAbsoluteGoldenSnapshotsSourcePath() )
107+ val goldenFolderFile = File (goldenSnapshotsSourcePath )
68108
69109 File (" ${reportsFolder.asFile.absolutePath} /recorded.html" ).apply {
70110 createNewFile()
@@ -76,7 +116,7 @@ class AndroidSnaptestingPlugin @Inject constructor(
76116 writeText(report)
77117 }
78118
79- if (project.properties[ " android.testInstrumentationRunnerArguments.record " ] != " true " ) {
119+ if (! isRecordMode ) {
80120 File (" ${reportsFolder.asFile.absolutePath} /failures.html" ).apply {
81121 createNewFile()
82122 val failuresFiles = failuresFolderFile.listFiles()?.asList() ? : emptyList()
@@ -99,35 +139,13 @@ class AndroidSnaptestingPlugin @Inject constructor(
99139 writeText(report)
100140 }
101141 } else {
102- File (getAbsoluteGoldenSnapshotsSourcePath() ).apply {
142+ File (goldenSnapshotsSourcePath ).apply {
103143 mkdirs()
104144 recordedFolderFile.copyRecursively(this , true )
105145 }
106146 }
107147 }
108148
109- private fun Task.onTaskCompleted (onCompleted : () -> Unit ) {
110- buildEventListenerRegistry.onTaskCompletion(
111- project.provider {
112- OperationCompletionListener {
113- if (it.descriptor.name != path) {
114- return @OperationCompletionListener
115- }
116- onCompleted()
117- }
118- }
119- )
120- }
121-
122- private fun AndroidVariantTask.getAbsoluteGoldenSnapshotsSourcePath (): String {
123- val variantSourceFolder = this
124- .variantName
125- .replace(" AndroidTest" , " " )
126- .capitalizeFirstLetter()
127- .let { " androidTest$it " }
128- return " ${project.projectDir} /src/$variantSourceFolder /assets/android-snaptesting-golden-files"
129- }
130-
131149 private fun String.capitalizeFirstLetter (): String {
132150 return replaceFirstChar { if (it.isLowerCase()) it.titlecase() else it.toString() }
133151 }
0 commit comments