Files
ios-mail/Modules/InboxCoreUI/Tests/Lock/LockScreenStoreTests.swift
T

120 lines
4.0 KiB
Swift

// Copyright (c) 2025 Proton Technologies AG
//
// This file is part of Proton Mail.
//
// Proton Mail is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Proton Mail is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Proton Mail. If not, see https://www.gnu.org/licenses/.
import InboxTesting
import Testing
import proton_app_uniffi
@testable import InboxCoreUI
@MainActor
final class LockScreenStoreTests {
private let mailSession = MailSessionSpy()
private let biometricAuthorizationNotifierSpy = BiometricAuthorizationNotifierSpy()
private let pinVerifierSpy: PINVerifierSpy = .init()
private var dismissLockInvokeCount = 0
lazy var sut: LockScreenStore = .init(
state: .init(type: .pin, pinAuthenticationError: nil),
pinVerifier: pinVerifierSpy,
biometricAuthorizationNotifier: biometricAuthorizationNotifierSpy,
signOutService: mailSession,
dismissLock: { [unowned self] in
dismissLockInvokeCount += 1
}
)
@Test
func handleBiometricAuthenticatedOutput_ItEmitsLockAuthenticatedOutput() async {
await sut.handle(action: .biometric(.authenticated))
#expect(dismissLockInvokeCount == 1)
#expect(biometricAuthorizationNotifierSpy.biometricsCheckPassedInvokeCount == 1)
}
@Test
func userEntersValidPin_ItEmitsLockAuthenticatedOutput() async {
pinVerifierSpy.verifyPinCodeStub = .ok
await sut.handle(action: .pin(.pin(.init(digits: [1, 2, 3, 4, 5]))))
#expect(sut.state.pinAuthenticationError == nil)
#expect(dismissLockInvokeCount == 1)
}
@Test
func userEntersInvalidPinForFirstTime_ItDisplaysError() async {
pinVerifierSpy.verifyPinCodeStub = .error(.reason(.incorrectPin))
await sut.handle(action: .pin(.pin(.init(digits: [1, 2, 3, 4, 5]))))
#expect(sut.state.pinAuthenticationError == .custom(L10n.PINLock.invalidPIN.string))
#expect(dismissLockInvokeCount == 0)
}
@Test
func userEntersInvalidPinForAndThreeAttemntsRemainig_ItDisplaysError() async {
pinVerifierSpy.remainingPinAttemptsStub = .ok(3)
pinVerifierSpy.verifyPinCodeStub = .error(.reason(.incorrectPin))
await sut.handle(action: .pin(.pin(.init(digits: [1, 2, 3, 4, 5]))))
#expect(sut.state.pinAuthenticationError == .attemptsRemaining(3))
#expect(dismissLockInvokeCount == 0)
}
@Test
func pinScreenIsLoadedAndNumberOfAttemptsIsZero_ItVerifiesNumberOfAttemptsAndSendsOutput() async {
pinVerifierSpy.remainingPinAttemptsStub = .ok(0)
await sut.handle(action: .pinScreenLoaded)
#expect(pinVerifierSpy.remainingPinAttemptsCallCount == 1)
#expect(dismissLockInvokeCount == 1)
}
@Test
func signOutButtonIsTappedOnPINLockScreen_ItSignOutsFromAllAccounts() async {
await sut.handle(action: .pin(.logOut))
#expect(mailSession.signOutAllCallCount == 1)
}
@Test
func signOutButtonIsTappedOnBioemtryScreen_ItSignOutsFromAllAccounts() async {
await sut.handle(action: .biometric(.logOut))
#expect(mailSession.signOutAllCallCount == 1)
}
}
private class BiometricAuthorizationNotifierSpy: BiometricAuthorizationNotifier, @unchecked Sendable {
private(set) var biometricsCheckPassedInvokeCount = 0
// MARK: - BiometricAuthorizationNotifier
func biometricsCheckPassed() {
biometricsCheckPassedInvokeCount += 1
}
}
extension MailSessionSpy: SignOutService {
public func signOutAllAccounts() async throws {
try await signOutAll().get()
}
}