Skip to content

Commit

Permalink
Merge pull request #279 from usefulness/updates
Browse files Browse the repository at this point in the history
Expose `ScreenshotConfig`, update `tileSize` from 512 to  1536, fix verification not failing on images of different dimensions
  • Loading branch information
mateuszkwiecinski authored May 22, 2024
2 parents 7349e54 + d768c58 commit 9824dee
Show file tree
Hide file tree
Showing 15 changed files with 149 additions and 87 deletions.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
17 changes: 17 additions & 0 deletions screenshot-testing-core/api/screenshot-testing-core.api
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,25 @@ public abstract interface class io/github/usefulness/testing/screenshot/RecordBu
public final class io/github/usefulness/testing/screenshot/Screenshot {
public static final field INSTANCE Lio/github/usefulness/testing/screenshot/Screenshot;
public static final field MAX_PIXELS J
public final fun getDefaultConfig ()Lio/github/usefulness/testing/screenshot/ScreenshotConfig;
public final fun setDefaultConfig (Lio/github/usefulness/testing/screenshot/ScreenshotConfig;)V
public static final fun snap (Landroid/app/Activity;)Lio/github/usefulness/testing/screenshot/RecordBuilder;
public static final fun snap (Landroid/app/Activity;Lio/github/usefulness/testing/screenshot/ScreenshotConfig;)Lio/github/usefulness/testing/screenshot/RecordBuilder;
public static final fun snap (Landroid/view/View;)Lio/github/usefulness/testing/screenshot/RecordBuilder;
public static final fun snap (Landroid/view/View;Lio/github/usefulness/testing/screenshot/ScreenshotConfig;)Lio/github/usefulness/testing/screenshot/RecordBuilder;
public static synthetic fun snap$default (Landroid/app/Activity;Lio/github/usefulness/testing/screenshot/ScreenshotConfig;ILjava/lang/Object;)Lio/github/usefulness/testing/screenshot/RecordBuilder;
public static synthetic fun snap$default (Landroid/view/View;Lio/github/usefulness/testing/screenshot/ScreenshotConfig;ILjava/lang/Object;)Lio/github/usefulness/testing/screenshot/RecordBuilder;
}

public final class io/github/usefulness/testing/screenshot/ScreenshotConfig {
public fun <init> ()V
public fun <init> (IJ)V
public synthetic fun <init> (IJILkotlin/jvm/internal/DefaultConstructorMarker;)V
public fun equals (Ljava/lang/Object;)Z
public final fun getMaxPixels ()J
public final fun getTileSize ()I
public fun hashCode ()I
public fun toString ()Ljava/lang/String;
}

public final class io/github/usefulness/testing/screenshot/ScreenshotRunner {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ interface RecordBuilder {
* Set the maximum number of pixels this screenshot should produce. Producing any number higher
* will throw an exception.
*
* @param maxPixels Maximum number of pixels this screenshot should produce. Specify zero or a
* [maxPixels] Maximum number of pixels this screenshot should produce. Specify zero or a
* negative number for no limit.
*/
fun setMaxPixels(maxPixels: Long): RecordBuilder
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,25 +15,31 @@ import io.github.usefulness.testing.screenshot.internal.ScreenshotImpl
*/
object Screenshot {

var defaultConfig = ScreenshotConfig()

/**
* Take a snapshot of an already measured and layout-ed view. See adb-logcat for how to pull the
* screenshot.
* Take a snapshot of an already measured and layout-ed view.
*
*
* This method is thread safe.
*/
@JvmStatic
fun snap(measuredView: View): RecordBuilder = ScreenshotImpl.snap(measuredView)
@JvmOverloads
fun snap(measuredView: View, config: ScreenshotConfig = defaultConfig): RecordBuilder =
ScreenshotImpl(config = config).snap(measuredView)

/**
* Take a snapshot of the activity and store it with the the testName. See the adb-logcat for how
* to pull the screenshot.
* Take a snapshot of the activity and store it with the the testName.
*
*
* This method is thread safe.
*/
@JvmStatic
fun snap(activity: Activity): RecordBuilder = ScreenshotImpl.snapActivity(activity)
@JvmOverloads
fun snap(activity: Activity, config: ScreenshotConfig = defaultConfig): RecordBuilder =
ScreenshotImpl(config = config).snapActivity(activity)

const val MAX_PIXELS = ScreenshotImpl.MAX_PIXELS
@JvmField
@Deprecated("Scheduled for removal in next major release")
val MAX_PIXELS = ScreenshotConfig().maxPixels
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package io.github.usefulness.testing.screenshot

import androidx.annotation.Px
import io.github.usefulness.testing.screenshot.internal.Poko

@Poko
class ScreenshotConfig(
@Px val tileSize: Int = 1536,
/**
* Set the maximum number of pixels this screenshot should produce. Producing any number higher
* will throw an exception.
*
* Maximum number of pixels this screenshot should produce. Specify zero or a negative number for no limit.
*/
@Px val maxPixels: Long = 10000000L,
)
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,15 @@ package io.github.usefulness.testing.screenshot

import android.app.Instrumentation
import android.os.Bundle
import io.github.usefulness.testing.screenshot.internal.ScreenshotImpl
import io.github.usefulness.testing.screenshot.internal.MetadataRecorder

/**
* The ScreenshotRunner needs to be called from the top level Instrumentation test runner before and
* after all the tests run.
*/

object ScreenshotRunner {

/**
* Call this exactly once in your process before any screenshots are generated.
*
Expand All @@ -24,6 +25,6 @@ object ScreenshotRunner {
* Typically this can be in `AndroidJUnitRunner#finish()`
*/
fun onDestroy() {
ScreenshotImpl.flush()
MetadataRecorder.flush()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ class TestMethodInfo(
)

object TestNameDetector {

private const val JUNIT_TEST = "org.junit.Test"
private const val JUNIT4_TEST = "org.junit.Test"
private const val JUNIT5_TEST = "org.junit.jupiter.api.Test"

@JvmStatic
@Suppress("ThrowingExceptionsWithoutMessageOrCause")
Expand Down Expand Up @@ -42,6 +42,8 @@ object TestNameDetector {
}
}

private fun isTestMethod(method: Method) =
method.annotations.any { it.annotationClass.qualifiedName.equals(JUNIT_TEST, ignoreCase = true) }
private fun isTestMethod(method: Method) = method.annotations.any {
val qualifiedName = it.annotationClass.qualifiedName
qualifiedName.equals(JUNIT5_TEST, ignoreCase = true) || qualifiedName.equals(JUNIT4_TEST, ignoreCase = true)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,6 @@ internal interface Album {
*/
fun writeBitmap(name: String, tilei: Int, tilej: Int, bitmap: Bitmap): String

/**
* Call after all the screenshots are done.
*/
fun flush()

/**
* Opens a stream to dump the view hierarchy into. This should be called before addRecord() is
* called for the given name.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,12 @@ package io.github.usefulness.testing.screenshot.internal

import android.graphics.Bitmap

internal class AlbumImpl(private val screenshotDirectories: ScreenshotDirectories) : Album {
private val metadataRecorder = MetadataRecorder(screenshotDirectories)

override fun flush() {
metadataRecorder.flush()
}
internal class AlbumImpl : Album {

override fun writeBitmap(name: String, tilei: Int, tilej: Int, bitmap: Bitmap): String {
val tileName = generateTileName(name, tilei, tilej)
val filename = getScreenshotFilenameInternal(tileName)
screenshotDirectories.openOutputFile(filename).use {
ScreenshotDirectories.openOutputFile(filename).use {
bitmap.compress(Bitmap.CompressFormat.PNG, COMPRESSION_QUALITY, it)
}
return tileName
Expand All @@ -27,13 +22,13 @@ internal class AlbumImpl(private val screenshotDirectories: ScreenshotDirectorie
}

private fun writeMetadataFile(name: String, data: String) {
screenshotDirectories.openOutputFile(name)
ScreenshotDirectories.openOutputFile(name)
.use { it.write(data.toByteArray()) }
}

override fun addRecord(recordBuilder: RecordBuilderImpl) {
recordBuilder.checkState()
if (metadataRecorder.snapshot().any { it.name == recordBuilder.name }) {
if (MetadataRecorder.snapshot().any { it.name == recordBuilder.name }) {
if (recordBuilder.hasExplicitName()) {
error("Can't create multiple screenshots with the same name: ${recordBuilder.name}")
}
Expand All @@ -43,7 +38,7 @@ internal class AlbumImpl(private val screenshotDirectories: ScreenshotDirectorie

val tiling = recordBuilder.tiling

metadataRecorder.addNew(
MetadataRecorder.addNew(
screenshot = MetadataRecorder.ScreenshotMetadata(
description = recordBuilder.description,
name = recordBuilder.name,
Expand All @@ -60,10 +55,9 @@ internal class AlbumImpl(private val screenshotDirectories: ScreenshotDirectorie
)
}

internal companion object {
private const val COMPRESSION_QUALITY = 90
companion object {

fun create(): AlbumImpl = AlbumImpl(ScreenshotDirectories())
private const val COMPRESSION_QUALITY = 90

/**
* For a given screenshot, and a tile position, generates a name where we store the screenshot in
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,11 @@ import kotlinx.serialization.json.encodeToStream
import java.io.FileNotFoundException

@OptIn(ExperimentalSerializationApi::class)
internal class MetadataRecorder(private val screenshotDirectories: ScreenshotDirectories) {
private val metadataFileName = "metadata.json"
internal object MetadataRecorder {
private const val metadataFileName = "metadata.json"
private val metadata by lazy {
try {
screenshotDirectories.openInputFile(metadataFileName).use { metadataFile ->
ScreenshotDirectories.openInputFile(metadataFileName).use { metadataFile ->
Json.decodeFromStream<List<ScreenshotMetadata>>(metadataFile).toMutableList()
}
} catch (ignored: FileNotFoundException) {
Expand All @@ -23,7 +23,7 @@ internal class MetadataRecorder(private val screenshotDirectories: ScreenshotDir
fun snapshot() = metadata.asSequence()

fun flush() {
screenshotDirectories.openOutputFile(metadataFileName).use { output ->
ScreenshotDirectories.openOutputFile(metadataFileName).use { output ->
Json.encodeToStream<List<ScreenshotMetadata>>(value = metadata, stream = output)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,14 @@ package io.github.usefulness.testing.screenshot.internal
import android.graphics.Bitmap
import android.view.View
import io.github.usefulness.testing.screenshot.RecordBuilder
import io.github.usefulness.testing.screenshot.ScreenshotConfig
import java.io.File
import java.nio.charset.Charset

internal class RecordBuilderImpl(private val mScreenshotImpl: ScreenshotImpl) : RecordBuilder {
internal class RecordBuilderImpl(
private val mScreenshotImpl: ScreenshotImpl,
config: ScreenshotConfig,
) : RecordBuilder {
private val mExtras: MutableMap<String, String> = HashMap()
var description: String? = null
private set
Expand All @@ -33,7 +37,7 @@ internal class RecordBuilderImpl(private val mScreenshotImpl: ScreenshotImpl) :
/**
* @return The maximum number of pixels that is expected to be produced by this screenshot
*/
var maxPixels: Long = DEFAULT_MAX_PIXELS
var maxPixels: Long = config.maxPixels
private set

override fun setDescription(description: String): RecordBuilderImpl {
Expand Down Expand Up @@ -72,7 +76,7 @@ internal class RecordBuilderImpl(private val mScreenshotImpl: ScreenshotImpl) :
return this
}

override val bitmap: Bitmap?
override val bitmap: Bitmap
get() = mScreenshotImpl.getBitmap(this)

override fun setMaxPixels(maxPixels: Long): RecordBuilderImpl {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import java.io.InputStream
import java.io.OutputStream

@OptIn(ExperimentalTestApi::class)
internal class ScreenshotDirectories {
internal object ScreenshotDirectories {

fun openOutputFile(name: String): OutputStream = PlatformTestStorageRegistry.getInstance().openOutputFile(name)

Expand Down
Loading

0 comments on commit 9824dee

Please sign in to comment.