1 val runningGradle5 = gradle.gradleVersion.startsWith("5.")
2
3 val guavaVersionJre =
4 "<version>(.*)</version>".toRegex().find(file("../../pom.xml").readText())?.groups?.get(1)?.value
5 ?: error("version not found in pom")
6
7 val expectedReducedRuntimeClasspathAndroidVersion =
8 setOf(
9 "guava-${guavaVersionJre.replace("jre", "android")}.jar",
10 "failureaccess-1.0.2.jar",
11 "j2objc-annotations-3.0.0.jar",
12 "jsr305-3.0.2.jar",
13 "checker-qual-3.43.0.jar",
14 "error_prone_annotations-2.28.0.jar",
15 "listenablefuture-9999.0-empty-to-avoid-conflict-with-guava.jar"
16 )
17 val expectedReducedRuntimeClasspathJreVersion =
18 setOf(
19 "guava-$guavaVersionJre.jar",
20 "failureaccess-1.0.2.jar",
21 "j2objc-annotations-3.0.0.jar",
22 "jsr305-3.0.2.jar",
23 "checker-qual-3.43.0.jar",
24 "error_prone_annotations-2.28.0.jar",
25 "listenablefuture-9999.0-empty-to-avoid-conflict-with-guava.jar"
26 )
27 val expectedCompileClasspathAndroidVersion = expectedReducedRuntimeClasspathAndroidVersion
28 val expectedCompileClasspathJreVersion = expectedReducedRuntimeClasspathJreVersion
29
30 val extraLegacyDependencies = setOf("google-collections-1.0.jar")
31
<lambda>null32 buildscript {
33 val agpVersion = if (gradle.gradleVersion.startsWith("5.")) "3.6.4" else "7.0.4"
34 repositories {
35 google()
36 mavenCentral()
37 }
38 dependencies {
39 classpath("com.android.tools.build:gradle:$agpVersion") {
40 exclude(
41 group = "org.jetbrains.trove4j"
42 ) // Might not be available on Maven Central and not needed for this test
43 }
44 }
45 }
46
<lambda>null47 subprojects {
48 if (name.endsWith("Java")) {
49 apply(plugin = "java-library")
50 } else {
51 apply(plugin = "com.android.application")
52 the<com.android.build.gradle.AppExtension>().compileSdkVersion(30)
53 }
54
55 var expectedClasspath =
56 if (runningGradle5) {
57 // without Gradle Module Metadata (only the POM is used)
58 // - variant decision is made based on version suffix (android/jre) and not on the actual
59 // environment
60 // - runtime classpath equals the compile classpath
61 // - dependency conflict with Google Collections is not detected
62 if (name.startsWith("android")) {
63 expectedCompileClasspathAndroidVersion + extraLegacyDependencies
64 } else {
65 expectedCompileClasspathJreVersion + extraLegacyDependencies
66 }
67 } else {
68 // with Gradle Module Metadata
69 // - variant is chosen based on the actual environment, independent of version suffix
70 // - reduced runtime classpath is used (w/o annotation libraries)
71 // - capability conflicts are detected with Google Collections
72 if (name.contains("Android") && !name.contains("JreConstraint")) {
73 when {
74 name.contains("RuntimeClasspath") -> {
75 expectedReducedRuntimeClasspathAndroidVersion
76 }
77 name.contains("CompileClasspath") -> {
78 expectedCompileClasspathAndroidVersion
79 }
80 else -> {
81 error("unexpected classpath type: $name")
82 }
83 }
84 } else {
85 when {
86 name.contains("RuntimeClasspath") -> {
87 expectedReducedRuntimeClasspathJreVersion
88 }
89 name.contains("CompileClasspath") -> {
90 expectedCompileClasspathJreVersion
91 }
92 else -> {
93 error("unexpected classpath type: $name")
94 }
95 }
96 }
97 }
98 val guavaVersion =
99 if (name.startsWith("android")) {
100 guavaVersionJre.replace("jre", "android")
101 } else {
102 guavaVersionJre
103 }
104 val javaVersion = JavaVersion.VERSION_1_8
105
106 repositories {
107 mavenCentral()
108 mavenLocal()
109 }
110 val java = the<JavaPluginExtension>()
111 java.targetCompatibility = javaVersion
112 java.sourceCompatibility = javaVersion
113
114 if (!runningGradle5) {
115 configurations.all {
116 resolutionStrategy.capabilitiesResolution {
117 withCapability("com.google.collections:google-collections") {
118 candidates
119 .find {
120 val idField =
121 it.javaClass.getDeclaredMethod(
122 "getId"
123 ) // reflective access to make this compile with Gradle 5
124 (idField.invoke(it) as ModuleComponentIdentifier).module == "guava"
125 }
126 ?.apply { select(this) }
127 }
128 }
129 }
130
131 if (name.contains("AndroidConstraint")) {
132 dependencies {
133 constraints {
134 "api"("com.google.guava:guava") {
135 attributes {
136 // if the Gradle version is 7+, you can use
137 // TargetJvmEnvironment.TARGET_JVM_ENVIRONMENT_ATTRIBUTE
138 attribute(Attribute.of("org.gradle.jvm.environment", String::class.java), "android")
139 }
140 }
141 }
142 }
143 configurations.all {
144 resolutionStrategy.capabilitiesResolution {
145 withCapability("com.google.guava:guava") {
146 candidates
147 .find {
148 val variantName = it.javaClass.getDeclaredMethod("getVariantName")
149 (variantName.invoke(it) as String).contains("android")
150 }
151 ?.apply { select(this) }
152 }
153 }
154 }
155 }
156
157 if (name.contains("JreConstraint")) {
158 dependencies {
159 constraints {
160 "api"("com.google.guava:guava") {
161 attributes {
162 // if the Gradle version is 7+, you can use
163 // TargetJvmEnvironment.TARGET_JVM_ENVIRONMENT_ATTRIBUTE
164 attribute(
165 Attribute.of("org.gradle.jvm.environment", String::class.java),
166 "standard-jvm"
167 )
168 }
169 }
170 }
171 }
172 configurations.all {
173 resolutionStrategy.capabilitiesResolution {
174 withCapability("com.google.guava:guava") {
175 candidates
176 .find {
177 val variantName = it.javaClass.getDeclaredMethod("getVariantName")
178 (variantName.invoke(it) as String).contains("jre")
179 }
180 ?.apply { select(this) }
181 }
182 }
183 }
184 }
185 }
186
187 dependencies {
188 "api"("com.google.collections:google-collections:1.0")
189 "api"("com.google.guava:listenablefuture:1.0")
190 "api"("com.google.guava:guava:$guavaVersion")
191 }
192
193 tasks.register("testClasspath") {
194 doLast {
195 val classpathConfiguration =
196 if (project.name.contains("RuntimeClasspath")) {
197 if (project.name.endsWith("Java")) configurations["runtimeClasspath"]
198 else configurations["debugRuntimeClasspath"]
199 } else if (project.name.contains("CompileClasspath")) {
200 if (project.name.endsWith("Java")) configurations["compileClasspath"]
201 else configurations["debugCompileClasspath"]
202 } else {
203 error("unexpected classpath type: " + project.name)
204 }
205
206 val actualClasspath = classpathConfiguration.files.map { it.name }.toSet()
207 if (actualClasspath != expectedClasspath) {
208 throw RuntimeException(
209 """
210 Expected: ${expectedClasspath.sorted()}
211 Actual: ${actualClasspath.sorted()}
212 """
213 .trimIndent()
214 )
215 }
216 }
217 }
218 }
219