Skip to content

Commit be1167a

Browse files
committed
Add bom related tests
1 parent 28ff233 commit be1167a

File tree

6 files changed

+1210
-0
lines changed

6 files changed

+1210
-0
lines changed

plugins/src/test/kotlin/com/google/firebase/gradle/TestUtil.kt

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,12 @@
1616

1717
package com.google.firebase.gradle
1818

19+
import io.kotest.assertions.throwables.shouldThrowAny
20+
import io.kotest.matchers.equals.shouldBeEqual
21+
import io.kotest.matchers.string.shouldContain
1922
import io.mockk.MockKMatcherScope
2023
import java.io.File
24+
import kotlin.test.assertEquals
2125
import org.gradle.testkit.runner.BuildResult
2226
import org.gradle.testkit.runner.GradleRunner
2327

@@ -51,3 +55,35 @@ fun createGradleRunner(directory: File, vararg arguments: String): GradleRunner
5155

5256
/** Match arguments that end with the specified [str]. */
5357
fun MockKMatcherScope.endsWith(str: String) = match<String> { it.endsWith(str) }
58+
59+
/**
60+
* Asserts that an exception is thrown with a message that contains the provided [substrings].
61+
*
62+
* ```
63+
* shouldThrowSubstring("fetching", "firebase-common") {
64+
* throw RuntimeException("We ran into a problem while fetching the firebase-common artifact")
65+
* }
66+
* ```
67+
*
68+
* @param substrings A variable amount of strings that the exception message should contain.
69+
* @param block The callback that should throw the exception.
70+
*/
71+
inline fun shouldThrowSubstring(vararg substrings: String, block: () -> Unit) {
72+
val exception = shouldThrowAny { block() }
73+
74+
for (str in substrings) {
75+
exception.message.shouldContain(str)
76+
}
77+
}
78+
79+
/**
80+
* Asserts that this string is equal to the [expected] string.
81+
*
82+
* Should be used in place of [shouldBeEqual] when working with multi-line strings, as this method
83+
* will provide a proper diff in the console _and_ IDE of which parts of the string were different.
84+
*
85+
* Works around [kotest/issues/1084](https://github.com/kotest/kotest/issues/1084).
86+
*
87+
* @param expected The string that this string should have the same contents of.
88+
*/
89+
infix fun String.shouldBeText(expected: String) = assertEquals(expected, this)
Lines changed: 224 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,224 @@
1+
/*
2+
* Copyright 2025 Google LLC
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 com.google.firebase.gradle.plugins
18+
19+
import com.google.firebase.gradle.bomgenerator.GenerateBomReleaseNotesTask
20+
import com.google.firebase.gradle.plugins.datamodels.ArtifactDependency
21+
import com.google.firebase.gradle.plugins.datamodels.DependencyManagementElement
22+
import com.google.firebase.gradle.plugins.datamodels.PomElement
23+
import com.google.firebase.gradle.shouldBeText
24+
import io.kotest.core.spec.style.FunSpec
25+
import io.kotest.matchers.file.shouldExist
26+
import java.io.File
27+
import org.gradle.api.tasks.TaskProvider
28+
import org.gradle.kotlin.dsl.register
29+
import org.gradle.testfixtures.ProjectBuilder
30+
import org.junit.Rule
31+
import org.junit.Test
32+
import org.junit.rules.TemporaryFolder
33+
34+
class GenerateBomReleaseNotesTests : FunSpec() {
35+
@Rule @JvmField val testProjectDir = TemporaryFolder()
36+
37+
@Test
38+
fun `generates the release notes`() {
39+
val dependencies =
40+
listOf(
41+
ArtifactDependency(
42+
groupId = "com.google.firebase",
43+
artifactId = "firebase-auth",
44+
version = "10.0.0",
45+
),
46+
ArtifactDependency(
47+
groupId = "com.google.firebase",
48+
artifactId = "firebase-firestore",
49+
version = "10.0.0",
50+
),
51+
)
52+
val bom = makeBom("1.0.0", dependencies)
53+
val file = makeReleaseNotes(bom, bom)
54+
55+
file.readText().trim() shouldBeText
56+
"""
57+
### {{firebase_bom_long}} ({{bill_of_materials}}) version 1.0.0 {: #bom_v1-0-0}
58+
{% comment %}
59+
These library versions must be flat-typed, do not use variables.
60+
The release note for this BoM version is a library-version snapshot.
61+
{% endcomment %}
62+
63+
<section class="expandable">
64+
<p class="showalways">
65+
Firebase Android SDKs mapped to this {{bom}} version
66+
</p>
67+
<p>
68+
Libraries that were versioned with this release are in highlighted rows.<br>
69+
Refer to a library's release notes (on this page) for details about its changes.
70+
</p>
71+
<table>
72+
<thead>
73+
<th>Artifact name</th>
74+
<th>Version mapped<br>to previous {{bom}} v1.0.0</th>
75+
<th>Version mapped<br>to this {{bom}} v1.0.0</th>
76+
</thead>
77+
<tbody>
78+
<tr>
79+
<td>com.google.firebase:firebase-auth</td>
80+
<td>10.0.0</td>
81+
<td>10.0.0</td>
82+
</tr>
83+
<tr>
84+
<td>com.google.firebase:firebase-firestore</td>
85+
<td>10.0.0</td>
86+
<td>10.0.0</td>
87+
</tr>
88+
</tbody>
89+
</table>
90+
</section>
91+
"""
92+
.trimIndent()
93+
}
94+
95+
@Test
96+
fun `correctly formats changed dependencies`() {
97+
val oldDependencies =
98+
listOf(
99+
ArtifactDependency(
100+
groupId = "com.google.firebase",
101+
artifactId = "firebase-auth",
102+
version = "10.0.0",
103+
),
104+
ArtifactDependency(
105+
groupId = "com.google.firebase",
106+
artifactId = "firebase-analytics",
107+
version = "10.0.0",
108+
),
109+
ArtifactDependency(
110+
groupId = "com.google.firebase",
111+
artifactId = "firebase-vertexai",
112+
version = "10.0.0",
113+
),
114+
)
115+
val newDependencies =
116+
listOf(
117+
ArtifactDependency(
118+
groupId = "com.google.firebase",
119+
artifactId = "firebase-auth",
120+
version = "10.0.0",
121+
),
122+
ArtifactDependency(
123+
groupId = "com.google.firebase",
124+
artifactId = "firebase-firestore",
125+
version = "10.0.0",
126+
),
127+
ArtifactDependency(
128+
groupId = "com.google.firebase",
129+
artifactId = "firebase-vertexai",
130+
version = "11.0.0",
131+
),
132+
)
133+
val oldBom = makeBom("1.0.0", oldDependencies)
134+
val newBom = makeBom("2.0.0", newDependencies)
135+
val file = makeReleaseNotes(oldBom, newBom)
136+
137+
file.readText().trim() shouldBeText
138+
"""
139+
### {{firebase_bom_long}} ({{bill_of_materials}}) version 2.0.0 {: #bom_v2-0-0}
140+
{% comment %}
141+
These library versions must be flat-typed, do not use variables.
142+
The release note for this BoM version is a library-version snapshot.
143+
{% endcomment %}
144+
145+
<section class="expandable">
146+
<p class="showalways">
147+
Firebase Android SDKs mapped to this {{bom}} version
148+
</p>
149+
<p>
150+
Libraries that were versioned with this release are in highlighted rows.<br>
151+
Refer to a library's release notes (on this page) for details about its changes.
152+
</p>
153+
<table>
154+
<thead>
155+
<th>Artifact name</th>
156+
<th>Version mapped<br>to previous {{bom}} v1.0.0</th>
157+
<th>Version mapped<br>to this {{bom}} v2.0.0</th>
158+
</thead>
159+
<tbody>
160+
<tr>
161+
<td>com.google.firebase:firebase-auth</td>
162+
<td>10.0.0</td>
163+
<td>10.0.0</td>
164+
</tr>
165+
<tr class="alt">
166+
<td><b>com.google.firebase:firebase-firestore</b></td>
167+
<td><b>N/A</b></td>
168+
<td><b>10.0.0</b></td>
169+
</tr>
170+
<tr class="alt">
171+
<td><b>com.google.firebase:firebase-vertexai</b></td>
172+
<td><b>10.0.0</b></td>
173+
<td><b>11.0.0</b></td>
174+
</tr>
175+
</tbody>
176+
</table>
177+
</section>
178+
"""
179+
.trimIndent()
180+
}
181+
182+
private fun makeTask(
183+
configure: GenerateBomReleaseNotesTask.() -> Unit
184+
): TaskProvider<GenerateBomReleaseNotesTask> {
185+
val project = ProjectBuilder.builder().withProjectDir(testProjectDir.root).build()
186+
187+
return project.tasks.register<GenerateBomReleaseNotesTask>("generateBomReleaseNotes") {
188+
releaseNotesFile.set(project.layout.buildDirectory.file("bomReleaseNotes.md"))
189+
190+
configure()
191+
}
192+
}
193+
194+
private fun makeReleaseNotes(previousBom: PomElement, currentBom: PomElement): File {
195+
val currentBomFile = testProjectDir.newFile("current.bom")
196+
currentBom.toFile(currentBomFile)
197+
198+
val task = makeTask {
199+
this.currentBom.set(currentBomFile)
200+
this.previousBom.set(previousBom)
201+
}
202+
203+
val file =
204+
task.get().let {
205+
it.generate()
206+
it.releaseNotesFile.asFile.get()
207+
}
208+
209+
file.shouldExist()
210+
211+
return file
212+
}
213+
214+
private fun makeBom(version: String, dependencies: List<ArtifactDependency>): PomElement {
215+
return PomElement.fromFile(emptyBom)
216+
.copy(version = version, dependencyManagement = DependencyManagementElement(dependencies))
217+
}
218+
219+
companion object {
220+
private val resourcesDirectory = File("src/test/resources")
221+
private val testResources = resourcesDirectory.childFile("Bom")
222+
private val emptyBom = testResources.childFile("empty-bom.pom")
223+
}
224+
}

0 commit comments

Comments
 (0)