Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions Ext/Accessibility/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ plugins {
id 'com.android.library'
id 'kotlin-android'
id 'org.jetbrains.dokka'
id 'maven-publish'
id 'signing'
}

ext {
Expand Down
20 changes: 13 additions & 7 deletions Ext/Compose/build.gradle
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
import org.jetbrains.kotlin.gradle.dsl.JvmTarget

plugins {
id 'com.android.library'
id 'kotlin-android'
id 'org.jetbrains.dokka'
id 'maven-publish'
id 'signing'
alias(libs.plugins.compose.compiler)
}

ext {
Expand Down Expand Up @@ -66,15 +71,16 @@ android {
compose true
}

kotlinOptions {
jvmTarget = '17'
kotlin {
compilerOptions {
allWarningsAsErrors.set(true)
jvmTarget.set(JvmTarget.JVM_21)
freeCompilerArgs.addAll("-Xcontext-parameters")
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_17
targetCompatibility JavaVersion.VERSION_17
}
composeOptions {
kotlinCompilerExtensionVersion "1.5.14"
sourceCompatibility JavaVersion.VERSION_21
targetCompatibility JavaVersion.VERSION_21
}

dependencies {
Expand Down
2 changes: 2 additions & 0 deletions Ext/Fullscreen/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ plugins {
id 'com.android.library'
id 'kotlin-android'
id 'org.jetbrains.dokka'
id 'maven-publish'
id 'signing'
}

ext {
Expand Down
24 changes: 14 additions & 10 deletions Library/build.gradle
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
import org.jetbrains.kotlin.gradle.dsl.JvmTarget

plugins {
id 'com.android.library'
id 'kotlin-android'
id 'org.jetbrains.dokka'
id 'jacoco'
id 'maven-publish'
id 'signing'
}

ext {
Expand All @@ -26,23 +30,23 @@ archivesBaseName = pom.artifact
jacoco { toolVersion = "0.8.10" }

android {
kotlinOptions {
jvmTarget = '17'
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_17
targetCompatibility JavaVersion.VERSION_17
sourceCompatibility JavaVersion.VERSION_21
targetCompatibility JavaVersion.VERSION_21
}

defaultConfig {
compileSdk libs.versions.compileSdk.get().toInteger()
compileSdkVersion libs.versions.compileSdk.get().toInteger()
minSdkVersion libs.versions.minSdk.get().toInteger()
targetSdkVersion libs.versions.targetSdk.get().toInteger()
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
multiDexEnabled = true
kotlinOptions {
allWarningsAsErrors = true
freeCompilerArgs = ["-Xcontext-receivers"]
kotlin {
compilerOptions {
allWarningsAsErrors.set(true)
jvmTarget.set(JvmTarget.JVM_21)
freeCompilerArgs.addAll("-Xcontext-parameters")
}
}
}

Expand Down Expand Up @@ -156,4 +160,4 @@ project.afterEvaluate {
executionData(files("${project.buildDir}/jacoco/${testTaskName}.exec"))
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ class BitmapCompareTest {

@Test
fun fuzzy() {
val similarBitmap = baselineBitmap.copy(baselineBitmap.config, true)!!
val similarBitmap = baselineBitmap.copy(baselineBitmap.config!!, true)!!
similarBitmap.setPixel(0, 0, similarBitmap.getPixel(0, 0) + 1)

assertFalse(FuzzyCompare(TestifyConfiguration(exactness = 1.0f)).compareBitmaps(similarBitmap, baselineBitmap))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ class FuzzyCompareBitmapTest {
fun fuzzy() {
val baselineBitmap = loadBitmap("test")

val similarBitmap = baselineBitmap.copy(baselineBitmap.config, true)!!
val similarBitmap = baselineBitmap.copy(baselineBitmap.config!!, true)!!
similarBitmap.setPixel(0, 0, similarBitmap.getPixel(0, 0) + 1)

assertFalse(FuzzyCompare(TestifyConfiguration(exactness = 1.0f)).compareBitmaps(similarBitmap, baselineBitmap))
Expand Down
2 changes: 1 addition & 1 deletion Library/src/main/java/dev/testify/ScreenshotRule.kt
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ import org.junit.runners.model.Statement
@Suppress("unused", "MemberVisibilityCanBePrivate")
open class ScreenshotRule<T : Activity> @JvmOverloads constructor(
protected val activityClass: Class<T>,
@IdRes override var rootViewId: Int = android.R.id.content,
@field:IdRes override var rootViewId: Int = android.R.id.content,
initialTouchMode: Boolean = false,
enableReporter: Boolean = false,
override val configuration: TestifyConfiguration = TestifyConfiguration()
Expand Down
4 changes: 1 addition & 3 deletions Library/src/main/java/dev/testify/ScreenshotUtility.kt
Original file line number Diff line number Diff line change
Expand Up @@ -33,16 +33,15 @@ import android.graphics.BitmapFactory
import android.os.Debug
import android.util.Log
import android.view.View
import androidx.test.annotation.ExperimentalTestApi
import dev.testify.core.getDeviceDescription
import dev.testify.internal.helpers.loadAsset
import dev.testify.output.Destination
import dev.testify.output.PNG_EXTENSION
import dev.testify.output.getDestination
import dev.testify.output.getFileRelativeToRoot
import java.io.File
import java.util.concurrent.CountDownLatch
import java.util.concurrent.TimeUnit
import java.io.File

/**
* The default, preferred [BitmapFactory.Options] to use when decoding a [Bitmap].
Expand Down Expand Up @@ -138,7 +137,6 @@ fun loadBaselineBitmapForComparison(
* @return A [Bitmap] representing the captured [screenshotView] in [activity]
* Will return [null] if there is an error capturing the bitmap.
*/
@ExperimentalTestApi
fun createBitmapFromActivity(
activity: Activity,
fileName: String,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ data class TestifyConfiguration(
* Set the exactness of the bitmap comparison. The exactness is a value between 0.0 and 1.0, where 0.0 is the least
* exact and 1.0 is the most exact. The default value is 0.0.
*/
@FloatRange(from = 0.0, to = 1.0) var exactness: Float? = null,
@field:FloatRange(from = 0.0, to = 1.0) var exactness: Float? = null,

/**
* Install an activity monitor and set the requested orientation. Blocks and waits for the orientation change to
Expand Down Expand Up @@ -140,7 +140,7 @@ data class TestifyConfiguration(
* Set the @IdRes of the view that should be focused before the bitmap is captured.
* Allows Testify to deliberately set the keyboard focus to the specified view ID.
*/
@IdRes var focusTargetId: Int = View.NO_ID,
@field:IdRes var focusTargetId: Int = View.NO_ID,

/**
* Pause the test execution after the bitmap is captured.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ import java.util.concurrent.TimeUnit
*
* @param focusTargetId the id of the view to request focus on. If [View.NO_ID] is provided, the root view will be used.
*/
class FocusModification(@IdRes var focusTargetId: Int) : ViewModification() {
class FocusModification(@field:IdRes var focusTargetId: Int) : ViewModification() {

/**
* Returns the view to request focus on.
Expand Down
9 changes: 8 additions & 1 deletion Library/src/main/java/dev/testify/report/ReportSession.kt
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
package dev.testify.report

import android.app.Instrumentation
import android.os.Build
import androidx.annotation.VisibleForTesting
import dev.testify.internal.annotation.ExcludeFromJacocoGeneratedReport
import java.io.BufferedReader
Expand Down Expand Up @@ -214,7 +215,13 @@ internal open class ReportSession {
*/
@VisibleForTesting
internal fun getSessionId(instrumentation: Instrumentation, thread: Thread): String {
return "${instrumentation.context.hashCode().toString(16).padStart(8, '0')}-${thread.id}"
val id = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.BAKLAVA) {
thread.threadId()
} else {
@Suppress("DEPRECATION")
thread.id
}
return "${instrumentation.context.hashCode().toString(16).padStart(8, '0')}-$id"
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -108,9 +108,9 @@ import kotlin.contracts.contract
* @param configuration The [TestifyConfiguration] for the current test
*/
open class ScreenshotScenarioRule @JvmOverloads constructor(
@IdRes override var rootViewId: Int = android.R.id.content,
@field:IdRes override var rootViewId: Int = android.R.id.content,
enableReporter: Boolean = false,
@LayoutRes override var targetLayoutId: Int = View.NO_ID,
@field:LayoutRes override var targetLayoutId: Int = View.NO_ID,
override val configuration: TestifyConfiguration = TestifyConfiguration()
) :
TestWatcher(),
Expand Down Expand Up @@ -501,10 +501,10 @@ open class ScreenshotScenarioRule @JvmOverloads constructor(
} ?: throw ScenarioRequiredException()
}

context (ActivityScenario<*>)
context (scenario: ActivityScenario<*>)
@JvmName("assertSameContext")
fun assertSame() {
assertSame(this@ActivityScenario)
assertSame(scenario)
}

private fun assertSame(scenario: ActivityScenario<*>) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ class ResourceWrapperTest {
}

overrideResourceConfiguration<Activity>(
locale = Locale("fr_CA")
locale = Locale.of("fr_CA")
)
verify(exactly = 1) { ResourceWrapper.addOverride(any()) }
verify { wrappedResource.beforeActivityLaunched() }
Expand Down Expand Up @@ -171,7 +171,7 @@ class ResourceWrapperTest {
}

overrideResourceConfiguration<Activity>(
locale = Locale("fr_CA"),
locale = Locale.of("fr_CA"),
fontScale = 1.5f
)
verify(exactly = 2) { ResourceWrapper.addOverride(any()) }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,10 @@ class ReportSessionTest {
val context: Context = mockk()

every { instrumentation.context } returns context
every { thread.id } returns 123L
every {
@Suppress("DEPRECATION")
thread.id
} returns 123L

val id = ReportSession.getSessionId(instrumentation, thread)
assertTrue("^[0-9a-fA-F]{8}-123".toRegex().containsMatchIn(id))
Expand Down
2 changes: 2 additions & 0 deletions Plugins/Gradle/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ plugins {
id 'org.jetbrains.kotlin.jvm'
id 'org.jetbrains.dokka'
id 'jacoco'
id 'maven-publish'
id 'signing'
}

def gradleProperties = new Properties()
Expand Down
46 changes: 26 additions & 20 deletions Samples/Flix/FlixLibrary/build.gradle
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import org.jetbrains.kotlin.gradle.dsl.JvmTarget

buildscript {
ext {
versions = [
Expand All @@ -17,15 +19,16 @@ plugins {
id 'kotlin-kapt'
id 'com.google.dagger.hilt.android'
id 'dev.testify'
alias(libs.plugins.compose.compiler)
}

android {
namespace 'dev.testify.samples.flix.library'
compileSdk 34
compileSdk 36

defaultConfig {
minSdk 24
targetSdk 33
minSdkVersion 26
targetSdkVersion 36

testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"

Expand All @@ -40,11 +43,13 @@ android {
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_17
targetCompatibility JavaVersion.VERSION_17
sourceCompatibility JavaVersion.VERSION_21
targetCompatibility JavaVersion.VERSION_21
}
kotlinOptions {
jvmTarget = '17'
kotlin {
compilerOptions {
jvmTarget.set(JvmTarget.JVM_21)
}
}
buildFeatures {
compose true
Expand All @@ -70,26 +75,27 @@ testify {
}

dependencies {
kapt "com.google.dagger:dagger-compiler:2.46.1"
kapt "com.google.dagger:hilt-compiler:2.48"
kapt "com.google.dagger:dagger-compiler:2.57.1"
kapt "com.google.dagger:hilt-compiler:2.57.1"

def composeBom = platform('androidx.compose:compose-bom:2024.05.00')
def composeBom = platform('androidx.compose:compose-bom:2025.08.01')
implementation composeBom
//noinspection UseTomlInstead
implementation "androidx.hilt:hilt-navigation-compose:1.2.0"
implementation "androidx.lifecycle:lifecycle-runtime-compose:2.8.1"
implementation "androidx.test.espresso.idling:idling-concurrent:3.6.0-rc01"
implementation "com.google.dagger:hilt-android:2.48"
implementation 'androidx.compose.material3:material3:1.2.1'
implementation 'androidx.core:core-ktx:1.13.1'
implementation 'io.ktor:ktor-client-android:1.5.0'
implementation 'org.jetbrains.kotlinx:kotlinx-serialization-json:1.1.0'
implementation("io.coil-kt:coil-compose:2.2.2")
implementation "androidx.lifecycle:lifecycle-runtime-compose:2.9.3"
implementation "androidx.test.espresso.idling:idling-concurrent:3.7.0"
implementation "com.google.dagger:hilt-android:2.57.1"
implementation 'androidx.compose.material3:material3:1.3.2'
implementation 'androidx.core:core-ktx:1.17.0'
implementation 'io.ktor:ktor-client-android:3.2.3'
implementation 'org.jetbrains.kotlinx:kotlinx-serialization-json:1.9.0'
implementation("io.coil-kt:coil-compose:2.7.0")

androidTestImplementation composeBom
androidTestImplementation "androidx.compose.ui:ui-test-junit4:${versions.compose.ui}"
androidTestImplementation "androidx.test:rules:1.5.0"
androidTestImplementation "androidx.test:rules:1.7.0"

androidTestImplementation project(":Library")
androidTestImplementation project(":ComposeExtensions")
androidTestImplementation 'androidx.test.ext:junit:1.1.5'
androidTestImplementation 'androidx.test.ext:junit:1.3.0'
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,9 @@ import dev.testify.samples.flix.data.remote.tmdb.TheMovieDbUrlResolver
import dev.testify.samples.flix.data.remote.tmdb.entity.Person
import dev.testify.samples.flix.data.translator.toFlixPerson
import io.ktor.client.HttpClient
import io.ktor.client.call.body
import io.ktor.client.request.get
import io.ktor.http.pathComponents
import io.ktor.http.appendPathSegments
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.async
import kotlinx.coroutines.flow.Flow
Expand All @@ -53,20 +54,23 @@ class CastMemberRepository @Inject constructor(
val apiConfigurationDeferred = async { configurationApi.getApiConfiguration() }

val personApiSpec = GetApiSpec("person", id.toString())

val person: Person = client.get {
url {
val allUrlComponents: List<String> = buildList {
add(personApiSpec.apiVersion.toString())
addAll(personApiSpec.pathSegments)
}
pathComponents(allUrlComponents)
appendPathSegments(allUrlComponents)
}
}
}.body()

val apiConfiguration = apiConfigurationDeferred.await()
val urlResolver = TheMovieDbUrlResolver(apiConfiguration.baseUrl, apiConfiguration.headlineImageSizeKey)

person.toFlixPerson(urlResolver)

null // TODO?
}
.onFailure {
when (it) {
Expand Down
Loading