diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 88cc4ae..a9eb4f1 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -12,6 +12,7 @@ compose-bom = "2025.12.01" dokka = "2.1.0" junit = "4.13.2" kotlin = "2.2.21" +kotlin-coroutines = "1.10.2" mockk = "1.14.7" okhttp = "5.3.2" @@ -34,6 +35,7 @@ compose-ui-tooling = { module = "androidx.compose.ui:ui-tooling" } compose-ui-toolingPreview = { module = "androidx.compose.ui:ui-tooling-preview" } conscrypt = { module = "org.conscrypt:conscrypt-android", version.ref = "conscrypt" } junit = { module = "junit:junit", version.ref = "junit" } +kotlin-coroutines-test = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-test", version.ref = "kotlin-coroutines" } kotlin-stdlib = { module = "org.jetbrains.kotlin:kotlin-stdlib", version.ref = "kotlin" } mockk-android = { module = "io.mockk:mockk-android", version.ref = "mockk" } okhttp = { module = "com.squareup.okhttp3:okhttp", version.ref = "okhttp" } diff --git a/lib/build.gradle.kts b/lib/build.gradle.kts index 294fd53..e9747ec 100644 --- a/lib/build.gradle.kts +++ b/lib/build.gradle.kts @@ -1,3 +1,13 @@ +/* + * Copyright © All Contributors. See LICENSE and AUTHORS in the root directory for details. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * SPDX-License-Identifier: MPL-2.0 + */ + plugins { alias(libs.plugins.android.library) alias(libs.plugins.compose.compiler) @@ -113,6 +123,7 @@ dependencies { androidTestImplementation(libs.androidx.test.runner) androidTestImplementation(libs.androidx.test.rules) androidTestImplementation(libs.conscrypt) + androidTestImplementation(libs.kotlin.coroutines.test) androidTestImplementation(libs.okhttp3.mockwebserver) androidTestImplementation(libs.mockk.android) diff --git a/lib/src/androidTest/java/at/bitfire/cert4android/UserDecisionRegistryTest.kt b/lib/src/androidTest/java/at/bitfire/cert4android/UserDecisionRegistryTest.kt index fd9d045..fe53491 100644 --- a/lib/src/androidTest/java/at/bitfire/cert4android/UserDecisionRegistryTest.kt +++ b/lib/src/androidTest/java/at/bitfire/cert4android/UserDecisionRegistryTest.kt @@ -23,6 +23,7 @@ import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.delay import kotlinx.coroutines.launch import kotlinx.coroutines.runBlocking +import kotlinx.coroutines.test.runTest import org.junit.After import org.junit.Assert.assertEquals import org.junit.Assert.assertFalse @@ -57,27 +58,24 @@ class UserDecisionRegistryTest { @Test - fun testCheck_FirstDecision_Negative() { + fun testCheck_FirstDecision_Negative() = runTest { every { registry.requestDecision(testCert, any(), any()) } answers { registry.onUserDecision(testCert, false) } - assertFalse(runBlocking { - registry.check(testCert, true) - }) + assertFalse(registry.check(testCert, true)) } @Test - fun testCheck_FirstDecision_Positive() { + fun testCheck_FirstDecision_Positive() = runTest { every { registry.requestDecision(testCert, any(), any()) } answers { registry.onUserDecision(testCert, true) } - assertTrue(runBlocking { - registry.check(testCert, true) - }) + assertTrue(registry.check(testCert, true)) } @Test fun testCheck_MultipleDecisionsForSameCert_Negative() { + // Keep runBlocking for complex concurrency test with Semaphore and threads val canSendFeedback = Semaphore(0) every { registry.requestDecision(testCert, any(), any()) } answers { thread { @@ -104,6 +102,7 @@ class UserDecisionRegistryTest { @Test fun testCheck_MultipleDecisionsForSameCert_Positive() { + // Keep runBlocking for complex concurrency test with Semaphore and threads val canSendFeedback = Semaphore(0) every { registry.requestDecision(testCert, any(), any()) } answers { thread { @@ -130,6 +129,7 @@ class UserDecisionRegistryTest { @Test fun testCheck_MultipleDecisionsForSameCert_cancel() { + // Keep runBlocking for complex concurrency test with Semaphore, threads, and job cancellation val canSendFeedback = Semaphore(0) val nm = mockk() every { nm.cancel(any(), any()) } just runs @@ -160,12 +160,10 @@ class UserDecisionRegistryTest { } @Test - fun testCheck_UserDecisionImpossible() { + fun testCheck_UserDecisionImpossible() = runTest { every { NotificationUtils.notificationsPermitted(any()) } returns false - assertFalse(runBlocking { - // should return instantly - registry.check(testCert, false) - }) + // should return instantly + assertFalse(registry.check(testCert, false)) verify(inverse = true) { registry.requestDecision(any(), any(), any()) }