Skip to content
Merged
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// MARK: - BiometricsStateService

/// A protocol for a service that provides state management functionality around biometrics.
///
public protocol BiometricsStateService: ActiveAccountStateProvider {
/// Get the active user's Biometric Authentication Preference.
///
/// - Returns: A `Bool` indicating the user's preference for using biometric authentication.
/// If `true`, the device should attempt biometric authentication for authorization events.
/// If `false`, the device should not attempt biometric authentication for authorization events.
///
func getBiometricAuthenticationEnabled() async throws -> Bool

/// Sets the user's Biometric Authentication Preference.
///
/// - Parameter isEnabled: A `Bool` indicating the user's preference for using biometric authentication.
/// If `true`, the device should attempt biometric authentication for authorization events.
/// If `false`, the device should not attempt biometric authentication for authorization events.
///
func setBiometricAuthenticationEnabled(_ isEnabled: Bool?) async throws
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import BitwardenKit
import TestHelpers

public class MockBiometricsStateService: BiometricsStateService {
public var activeAccountIdError: Error?
public var activeAccountIdResult = Result<String, Error>.failure(BitwardenTestError.mock("Mock error not set"))
public var biometricAuthenticationEnabledResult: Result<Bool, Error> = .success(false)
public var setBiometricAuthenticationEnabledError: Error?

public init() {}

public func getActiveAccountId() async throws -> String {
if let activeAccountIdError {
throw activeAccountIdError
}
return try activeAccountIdResult.get()
}

public func getBiometricAuthenticationEnabled() async throws -> Bool {
try biometricAuthenticationEnabledResult.get()
}

public func setBiometricAuthenticationEnabled(_ isEnabled: Bool?) async throws {
if let setBiometricAuthenticationEnabledError {
throw setBiometricAuthenticationEnabledError
}
biometricAuthenticationEnabledResult = .success(isEnabled ?? false)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

๐Ÿ“ Observation: The mock implementation stores the result of setBiometricAuthenticationEnabled in biometricAuthenticationEnabledResult, which creates bidirectional coupling between the setter and getter.

While this works for simple test scenarios, it means that setting isEnabled = nil will be stored as false, which may not accurately reflect the behavior of the real implementation. Consider whether tests need to verify the actual value passed vs. the stored state separately.

This is fine for current test needs, but worth noting for future test scenarios.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We do this elsewhere in our mocks, I believe, so I'm comfortable with this for now. In the PR where I bring the BiometricsRepository into BitwardenKit, I might do a re-look through all the tests and decide to change this then.

}
}
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import BitwardenKit
import BitwardenSdk
import LocalAuthentication

Expand Down Expand Up @@ -66,7 +67,7 @@ class DefaultBiometricsRepository: BiometricsRepository {
var keychainRepository: KeychainRepository

/// A service used to update user preferences.
var stateService: StateService
var stateService: BiometricsStateService

// MARK: Initialization

Expand All @@ -80,7 +81,7 @@ class DefaultBiometricsRepository: BiometricsRepository {
init(
biometricsService: BiometricsService,
keychainService: KeychainRepository,
stateService: StateService,
stateService: BiometricsStateService,
) {
self.biometricsService = biometricsService
keychainRepository = keychainService
Expand Down
Loading