Skip to content

Commit 84ad2f7

Browse files
runningcodeclaude
andcommitted
fix(snapshot): Fix compile errors in generated sidecar metadata code
- Remove SentrySnapshotHandler that used java.awt.image.BufferedImage and javax.imageio.ImageIO which are unavailable in Android test classpath - Use SnapshotVerifier pointed at sentry output dir instead, which writes images with predictable names (not content hashes) - Fix methodName access: use preview.methodName (ComposablePreview) instead of info.methodName (AndroidPreviewInfo doesn't have it) - Fix declaringClass: it's a non-nullable String on ComposablePreview - Write sidecar filenames matching SnapshotVerifier's naming pattern (Paparazzi_Preview_Test_{screenshotId_lowercased}) - Clean sentry output dir before each test run to ensure fresh writes Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent f6399fb commit 84ad2f7

2 files changed

Lines changed: 26 additions & 50 deletions

File tree

plugin-build/src/main/kotlin/io/sentry/android/gradle/snapshot/GenerateSnapshotTestsTask.kt

Lines changed: 17 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,6 @@ import androidx.compose.ui.Modifier
9999
import androidx.compose.ui.graphics.Color
100100
import androidx.compose.ui.unit.dp
101101
import app.cash.paparazzi.DeviceConfig
102-
import app.cash.paparazzi.HtmlReportWriter
103102
import app.cash.paparazzi.Paparazzi
104103
import app.cash.paparazzi.Snapshot
105104
import app.cash.paparazzi.SnapshotHandler
@@ -108,9 +107,8 @@ import app.cash.paparazzi.TestName
108107
import app.cash.paparazzi.detectEnvironment
109108
import com.android.ide.common.rendering.api.SessionParams
110109
import com.android.resources.*
111-
import java.awt.image.BufferedImage
112110
import java.io.File
113-
import javax.imageio.ImageIO
111+
import java.util.Locale
114112
import kotlin.math.ceil
115113
import org.junit.Rule
116114
import org.junit.Test
@@ -208,29 +206,6 @@ private class TestNameOverrideHandler(
208206
}
209207
}
210208
211-
private class SentrySnapshotHandler(
212-
private val outputDir: File,
213-
private val delegate: SnapshotHandler,
214-
) : SnapshotHandler {
215-
override fun newFrameHandler(
216-
snapshot: Snapshot,
217-
frameCount: Int,
218-
fps: Int,
219-
): SnapshotHandler.FrameHandler {
220-
val delegateHandler = delegate.newFrameHandler(snapshot, frameCount, fps)
221-
return object : SnapshotHandler.FrameHandler {
222-
override fun handle(image: BufferedImage) {
223-
delegateHandler.handle(image)
224-
val name = snapshot.name ?: return
225-
outputDir.mkdirs()
226-
ImageIO.write(image, "png", File(outputDir, "${'$'}{name}.png"))
227-
}
228-
override fun close() = delegateHandler.close()
229-
}
230-
}
231-
override fun close() = delegate.close()
232-
}
233-
234209
private object PaparazziPreviewRule {
235210
const val UNDEFINED_API_LEVEL = -1
236211
const val MAX_API_LEVEL = 36
@@ -243,7 +218,7 @@ private object PaparazziPreviewRule {
243218
}
244219
val tolerance = 0.0
245220
val sentryOutputDir = File(
246-
System.getProperty("sentry.snapshot.output", "build/sentry-snapshots/images")
221+
System.getProperty("sentry.snapshot.output", "build/sentry-snapshots")
247222
)
248223
return Paparazzi(
249224
environment = detectEnvironment().copy(compileSdkVersion = previewApiLevel),
@@ -255,14 +230,11 @@ private object PaparazziPreviewRule {
255230
previewInfo.widthDp > 0 && previewInfo.heightDp > 0 -> SessionParams.RenderingMode.FULL_EXPAND
256231
else -> SessionParams.RenderingMode.SHRINK
257232
},
258-
snapshotHandler = SentrySnapshotHandler(
259-
outputDir = sentryOutputDir,
260-
delegate = TestNameOverrideHandler(
261-
when (System.getProperty("paparazzi.test.verify")?.toBoolean() == true) {
262-
true -> SnapshotVerifier(maxPercentDifference = tolerance)
263-
false -> HtmlReportWriter(maxPercentDifference = tolerance)
264-
}
265-
),
233+
snapshotHandler = TestNameOverrideHandler(
234+
SnapshotVerifier(
235+
maxPercentDifference = tolerance,
236+
rootDirectory = sentryOutputDir,
237+
)
266238
),
267239
maxPercentDifference = tolerance,
268240
)
@@ -368,29 +340,26 @@ class $CLASS_NAME(
368340
screenshotId: String,
369341
preview: ComposablePreview<AndroidPreviewInfo>,
370342
) {
371-
val outputDir = File(
372-
System.getProperty("sentry.snapshot.output", "build/sentry-snapshots/images")
343+
val sentryRoot = File(
344+
System.getProperty("sentry.snapshot.output", "build/sentry-snapshots")
373345
)
374-
outputDir.mkdirs()
346+
val imagesDir = File(sentryRoot, "images")
347+
imagesDir.mkdirs()
375348
val info = preview.previewInfo
376349
val q = '"'
377350
val parts = mutableListOf<String>()
378351
parts.add(q + "display_name" + q + ": " + q + escapeJson(screenshotId) + q)
379352
parts.add(q + "image_file_name" + q + ": " + q + escapeJson(screenshotId) + q)
380353
val group = info.group
381-
if (!group.isNullOrBlank()) {
354+
if (group.isNotBlank()) {
382355
parts.add(q + "group" + q + ": " + q + escapeJson(group) + q)
383356
}
384-
val declaringClass = preview.declaringClass
385-
if (declaringClass != null) {
386-
parts.add(q + "className" + q + ": " + q + escapeJson(declaringClass) + q)
387-
}
388-
val methodName = info.methodName
389-
if (methodName != null) {
390-
parts.add(q + "methodName" + q + ": " + q + escapeJson(methodName) + q)
391-
}
357+
parts.add(q + "className" + q + ": " + q + escapeJson(preview.declaringClass) + q)
358+
parts.add(q + "methodName" + q + ": " + q + escapeJson(preview.methodName) + q)
392359
val json = parts.joinToString(",\n ", prefix = "{\n ", postfix = "\n}")
393-
File(outputDir, "${'$'}{screenshotId}.json").writeText(json)
360+
val sidecarName = "Paparazzi_Preview_Test_" +
361+
screenshotId.lowercase(Locale.US).replace("\\s".toRegex(), "_")
362+
File(imagesDir, "${'$'}{sidecarName}.json").writeText(json)
394363
}
395364
396365
private fun escapeJson(s: String): String =

plugin-build/src/main/kotlin/io/sentry/android/gradle/snapshot/SentrySnapshotPlugin.kt

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import com.android.build.api.variant.ApplicationAndroidComponentsExtension
44
import com.android.build.api.variant.HostTestBuilder
55
import com.android.build.gradle.BaseExtension
66
import io.sentry.android.gradle.util.AgpVersions
7+
import java.io.File
78
import kotlin.jvm.java
89
import org.gradle.api.Plugin
910
import org.gradle.api.Project
@@ -30,12 +31,18 @@ class SentrySnapshotPlugin : Plugin<Project> {
3031
val androidComponents =
3132
project.extensions.getByType(ApplicationAndroidComponentsExtension::class.java)
3233

33-
val sentrySnapshotOutputDir = project.layout.buildDirectory.dir("sentry-snapshots/images")
34+
val sentrySnapshotRootDir = project.layout.buildDirectory.dir("sentry-snapshots")
3435
project.tasks.withType(Test::class.java).configureEach { testTask ->
3536
testTask.systemProperty(
3637
"sentry.snapshot.output",
37-
sentrySnapshotOutputDir.get().asFile.absolutePath,
38+
sentrySnapshotRootDir.get().asFile.absolutePath,
3839
)
40+
testTask.doFirst {
41+
val imagesDir = File(sentrySnapshotRootDir.get().asFile, "images")
42+
if (imagesDir.exists()) {
43+
imagesDir.deleteRecursively()
44+
}
45+
}
3946
}
4047

4148
androidComponents.onVariants { variant ->

0 commit comments

Comments
 (0)