1 /*
2  * Copyright 2022 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.build
18 
19 import androidx.testutils.gradle.ProjectSetupRule
20 import java.io.File
21 import org.junit.Assert
22 import org.junit.Assert.assertEquals
23 import org.junit.Rule
24 import org.junit.Test
25 
26 class ConstraintTest {
27     @get:Rule val projectSetup = ProjectSetupRule()
28 
29     /** Test for matching constraint versions in Gradle metadata. */
30     @Test
mavenMetadataRequiresVersionnull31     fun mavenMetadataRequiresVersion() {
32         val baseMavenMetadata = getPublishedFile("androidx/core/core/maven-metadata.xml")
33         val baseVersion = getLatestVersion(baseMavenMetadata)
34 
35         val baseGradleMetadata =
36             getPublishedFile("androidx/core/core/$baseVersion/core-$baseVersion.module")
37         val baseRequiresKtxVersion =
38             getConstraintVersion(baseGradleMetadata.readText(), "androidx.core", "core-ktx")!!
39 
40         val ktxMavenMetadata = getPublishedFile("androidx/core/core-ktx/maven-metadata.xml")
41         val ktxVersion = getLatestVersion(ktxMavenMetadata)
42 
43         val ktxGradleMetadata =
44             getPublishedFile("androidx/core/core-ktx/$ktxVersion/core-ktx-$ktxVersion.module")
45         val ktxRequiresBaseVersion =
46             getConstraintVersion(ktxGradleMetadata.readText(), "androidx.core", "core")!!
47 
48         // The core and core-ktx libraries should share the same version.
49         assertEquals(baseVersion, ktxVersion)
50 
51         // Their Gradle metadata files should reference each other as `required`-type constraints.
52         assertEquals(baseVersion, ktxRequiresBaseVersion)
53         assertEquals(ktxVersion, baseRequiresKtxVersion)
54     }
55 
56     /** Unit test for the constraint version extraction function. */
57     @Test
getConstraintVersionTestnull58     fun getConstraintVersionTest() {
59         val metadata =
60             """
61               "version": {
62                 "requires": "1.0.0"
63               }
64             }
65           ],
66           variants: [
67             {
68               "name": "releaseVariantReleaseApiPublication",
69               "dependencyConstraints": [
70                 {
71                    "group": "org.jetbrains.kotlin",
72                    "module": "kotlin-stdlib",
73                    "version": {
74                      "requires": "1.8.22"
75                    }
76                 }
77               ],
78              },
79              {
80               "name": "releaseVariantReleaseRuntimePublication",
81               "dependencyConstraints": [
82                 {
83                   "group": "androidx.preference",
84                   "module": "preference-ktx",
85                   "version": {
86                     "requires": "1.3.0-alpha01"
87                   }
88                 }
89               ],
90              }
91           ]
92           "files": [
93             {
94               "name": "preference-1.3.0-alpha01.aar",
95               "url": "preference-1.3.0-alpha01.aar",
96         """
97                 .trimIndent()
98 
99         val requiresVersion =
100             getConstraintVersion(metadata, "androidx.preference", "preference-ktx")
101         assertEquals("1.3.0-alpha01", requiresVersion)
102     }
103 
getConstraintVersionnull104     private fun getConstraintVersion(metadata: String, groupId: String, artifact: String): String? =
105         getDependencyConstraints(metadata).let {
106             Regex(
107                     "\"group\": \"$groupId\",\\s+\"module\": " +
108                         "\"$artifact\",\\s+\"version\": \\{\\s+\"requires\": \"(.+?)\""
109                 )
110                 .find(it)
111                 ?.groups
112                 ?.get(1)
113                 ?.value
114         }
115 
getDependencyConstraintsnull116     private fun getDependencyConstraints(moduleJson: String) =
117         Regex("(?s)\"dependencyConstraints\": \\[(.+?)]").findAll(moduleJson).joinToString("\n") {
118             it.groups.get(1)?.value.orEmpty()
119         }
120 
121     // Yes, I know https://stackoverflow.com/a/1732454/258688, but it's just a test...
getLatestVersionnull122     private fun getLatestVersion(metadataFile: File) =
123         metadataFile
124             .readLines()
125             .mapNotNull { Regex(".*<latest>(.*?)</latest>.*").find(it)?.groups?.get(1)?.value }
126             .first()
127 
getPublishedFilenull128     private fun getPublishedFile(name: String) =
129         File(projectSetup.props.tipOfTreeMavenRepoPath).resolve(name).check { it.exists() }
130 
checknull131     private fun <T> T.check(eval: (T) -> Boolean): T {
132         if (!eval(this)) {
133             Assert.fail("Failed assertion: $this")
134         }
135         return this
136     }
137 }
138