Skip to content

Commit

Permalink
Merge pull request #4239 from element-hq/feature/bma/fixNightlyReports2
Browse files Browse the repository at this point in the history
Fix nightly reports - next step
  • Loading branch information
bmarty authored Feb 6, 2025
2 parents 5456f0e + 54af229 commit de673c9
Show file tree
Hide file tree
Showing 4 changed files with 149 additions and 7 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -23,17 +23,19 @@ open class PinUnlockStateProvider : PreviewParameterProvider<PinUnlockState> {
aPinUnlockState(showWrongPinTitle = true),
aPinUnlockState(showSignOutPrompt = true),
aPinUnlockState(showBiometricUnlock = false),
aPinUnlockState(showSignOutPrompt = true, remainingAttempts = 0),
aPinUnlockState(showSignOutPrompt = true, remainingAttempts = AsyncData.Success(0)),
aPinUnlockState(signOutAction = AsyncAction.Loading),
aPinUnlockState(biometricUnlockResult = BiometricAuthenticator.AuthenticationResult.Failure(
BiometricUnlockError(BiometricPrompt.ERROR_LOCKOUT, "Biometric auth disabled")
)),
aPinUnlockState(
biometricUnlockResult = BiometricAuthenticator.AuthenticationResult.Failure(
BiometricUnlockError(BiometricPrompt.ERROR_LOCKOUT, "Biometric auth disabled")
)
),
)
}

fun aPinUnlockState(
pinEntry: PinEntry = PinEntry.createEmpty(4),
remainingAttempts: Int = 3,
remainingAttempts: AsyncData<Int> = AsyncData.Success(3),
showWrongPinTitle: Boolean = false,
showSignOutPrompt: Boolean = false,
showBiometricUnlock: Boolean = true,
Expand All @@ -43,7 +45,7 @@ fun aPinUnlockState(
) = PinUnlockState(
pinEntry = AsyncData.Success(pinEntry),
showWrongPinTitle = showWrongPinTitle,
remainingAttempts = AsyncData.Success(remainingAttempts),
remainingAttempts = remainingAttempts,
showSignOutPrompt = showSignOutPrompt,
showBiometricUnlock = showBiometricUnlock,
signOutAction = signOutAction,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
/*
* Copyright 2025 New Vector Ltd.
*
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
* Please see LICENSE files in the repository root for full details.
*/

package io.element.android.features.lockscreen.impl.unlock

import androidx.biometric.BiometricPrompt
import com.google.common.truth.Truth.assertThat
import io.element.android.features.lockscreen.impl.biometric.BiometricAuthenticator
import io.element.android.features.lockscreen.impl.biometric.BiometricUnlockError
import io.element.android.libraries.architecture.AsyncData
import org.junit.Test

class PinUnlockStateTest {
@Test
fun `isSignOutPromptCancellable should have expected values`() {
assertThat(aPinUnlockState(remainingAttempts = AsyncData.Uninitialized).isSignOutPromptCancellable).isTrue()
assertThat(aPinUnlockState(remainingAttempts = AsyncData.Success(1)).isSignOutPromptCancellable).isTrue()
assertThat(aPinUnlockState(remainingAttempts = AsyncData.Success(0)).isSignOutPromptCancellable).isFalse()
}

@Test
fun `biometricUnlockErrorMessage and showBiometricUnlockError should have expected values`() {
listOf(
null,
BiometricAuthenticator.AuthenticationResult.Failure(),
BiometricAuthenticator.AuthenticationResult.Success,
).forEach { biometricUnlockResult ->
aPinUnlockState(
biometricUnlockResult = biometricUnlockResult,
).let {
assertThat(it.biometricUnlockErrorMessage).isNull()
assertThat(it.showBiometricUnlockError).isFalse()
}
}
listOf(
BiometricPrompt.ERROR_HW_UNAVAILABLE,
BiometricPrompt.ERROR_UNABLE_TO_PROCESS,
BiometricPrompt.ERROR_TIMEOUT,
BiometricPrompt.ERROR_NO_SPACE,
BiometricPrompt.ERROR_CANCELED,
BiometricPrompt.ERROR_VENDOR,
BiometricPrompt.ERROR_USER_CANCELED,
BiometricPrompt.ERROR_NO_BIOMETRICS,
BiometricPrompt.ERROR_HW_NOT_PRESENT,
BiometricPrompt.ERROR_NEGATIVE_BUTTON,
BiometricPrompt.ERROR_NO_DEVICE_CREDENTIAL,
BiometricPrompt.ERROR_SECURITY_UPDATE_REQUIRED,
).forEach { code ->
aPinUnlockState(
biometricUnlockResult = BiometricAuthenticator.AuthenticationResult.Failure(
error = BiometricUnlockError(code, "Error message")
),
).let {
assertThat(it.biometricUnlockErrorMessage).isNull()
assertThat(it.showBiometricUnlockError).isFalse()
}
}
listOf(
BiometricPrompt.ERROR_LOCKOUT,
BiometricPrompt.ERROR_LOCKOUT_PERMANENT,
).forEach { code ->
aPinUnlockState(
biometricUnlockResult = BiometricAuthenticator.AuthenticationResult.Failure(
error = BiometricUnlockError(code, "Error message")
),
).let {
assertThat(it.biometricUnlockErrorMessage).isEqualTo("Error message")
assertThat(it.showBiometricUnlockError).isTrue()
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
/*
* Copyright 2025 New Vector Ltd.
*
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
* Please see LICENSE files in the repository root for full details.
*/

package io.element.android.features.securebackup.impl.root

import com.google.common.truth.Truth.assertThat
import io.element.android.libraries.architecture.AsyncData
import io.element.android.libraries.matrix.api.encryption.BackupState
import io.element.android.libraries.matrix.test.AN_EXCEPTION
import org.junit.Test

class SecureBackupRootStateTest {
@Test
fun `isKeyStorageEnabled should be true for all these backup states`() {
listOf(
BackupState.CREATING,
BackupState.ENABLING,
BackupState.RESUMING,
BackupState.DOWNLOADING,
BackupState.ENABLED,
).forEach { backupState ->
assertThat(aSecureBackupRootState(backupState = backupState).isKeyStorageEnabled).isTrue()
}
}

@Test
fun `isKeyStorageEnabled should be false for all these backup states`() {
listOf(
BackupState.WAITING_FOR_SYNC,
BackupState.DISABLING,
).forEach { backupState ->
assertThat(aSecureBackupRootState(backupState = backupState).isKeyStorageEnabled).isFalse()
}
}

@Test
fun `isKeyStorageEnabled should have value depending on doesBackupExistOnServer when state is UNKNOWN`() {
assertThat(
aSecureBackupRootState(
backupState = BackupState.UNKNOWN,
doesBackupExistOnServer = AsyncData.Success(true),
).isKeyStorageEnabled
).isTrue()

listOf(
AsyncData.Uninitialized,
AsyncData.Loading(),
AsyncData.Failure(AN_EXCEPTION),
AsyncData.Success(false),
).forEach { doesBackupExistOnServer ->
assertThat(
aSecureBackupRootState(
backupState = BackupState.UNKNOWN,
doesBackupExistOnServer = doesBackupExistOnServer,
).isKeyStorageEnabled
).isFalse()
}
}
}
3 changes: 2 additions & 1 deletion plugins/src/main/kotlin/extension/KoverExtension.kt
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,6 @@ fun Project.setupKover() {
description = "Verifies the code coverage of all subprojects."
val dependencies = listOf(":app:koverVerifyGplayDebug") + koverVariants.map { ":app:koverVerify${it.replaceFirstChar(Char::titlecase)}" }
dependsOn(dependencies)

}
// https://kotlin.github.io/kotlinx-kover/
// Run `./gradlew :app:koverHtmlReport` to get report at ./app/build/reports/kover
Expand Down Expand Up @@ -180,7 +179,9 @@ fun Project.setupKover() {
"io.element.android.libraries.matrix.api.timeline.item.event.OtherState$*",
"io.element.android.libraries.matrix.api.timeline.item.event.LocalEventSendState*",
"io.element.android.libraries.mediaviewer.impl.local.pdf.PdfViewerState",
"io.element.android.libraries.mediaviewer.impl.local.player.MediaPlayerControllerState",
"io.element.android.libraries.textcomposer.model.TextEditorState",
"io.element.android.libraries.textcomposer.components.FormattingOptionState",
)
includes.classes("*State")
}
Expand Down

0 comments on commit de673c9

Please sign in to comment.