Swift Testing for Unit Tests PART 1 (#5119)

* migrated a lot of unit tests to Swift Testing and added a new implementation for deferred fulfillment

more tests migration

Cleaned the code manually to establish some good patterns

more code improvements

some more code improvements

removed empty tests

update project

* more pr suggestions and cleanups

* removed the TestSetup pattern

* fixing claude not reusing tests

* pr suggestion + added indent rule to swiftformat so that we can prevent AIs to change that
This commit is contained in:
Mauro
2026-02-19 16:20:47 +01:00
committed by GitHub
parent fc03e05697
commit 7982aef855
118 changed files with 4630 additions and 4129 deletions
@@ -7,15 +7,17 @@
//
@testable import ElementX
import XCTest
import Foundation
import Testing
@MainActor
class AppLockServiceTests: XCTestCase {
var keychainController: KeychainController!
var appSettings: AppSettings!
var service: AppLockService!
@Suite
final class AppLockServiceTests {
private var keychainController: KeychainController
private var appSettings: AppSettings
private var service: AppLockService
override func setUp() {
init() {
AppSettings.resetAllSettings()
appSettings = AppSettings()
@@ -26,34 +28,36 @@ class AppLockServiceTests: XCTestCase {
service.disable()
}
override func tearDown() {
deinit {
AppSettings.resetAllSettings()
}
// MARK: - PIN Code
func testValidPINCode() {
@Test
func validPINCode() {
// Given a service that hasn't been enabled.
XCTAssertFalse(service.isEnabled, "The service shouldn't be enabled to begin with.")
#expect(!service.isEnabled, "The service shouldn't be enabled to begin with.")
// When setting a PIN code.
let pinCode = "2023" // Highly secure PIN that is rotated every 12 months.
guard case .success = service.setupPINCode(pinCode) else {
XCTFail("The PIN should be valid.")
Issue.record("The PIN should be valid.")
return
}
// Then service should be enabled and only the provided PIN should work to unlock the app.
XCTAssertTrue(service.isEnabled, "The service should become enabled when setting a PIN.")
XCTAssertTrue(service.unlock(with: pinCode), "The provided PIN code should work.")
XCTAssertFalse(service.unlock(with: "2024"), "No other PIN code should work.")
XCTAssertFalse(service.unlock(with: "1234"), "No other PIN code should work.")
XCTAssertFalse(service.unlock(with: "9999"), "No other PIN code should work.")
#expect(service.isEnabled, "The service should become enabled when setting a PIN.")
#expect(service.unlock(with: pinCode), "The provided PIN code should work.")
#expect(!service.unlock(with: "2024"), "No other PIN code should work.")
#expect(!service.unlock(with: "1234"), "No other PIN code should work.")
#expect(!service.unlock(with: "9999"), "No other PIN code should work.")
}
func testWeakPINCode() {
@Test
func weakPINCode() {
// Given a service that hasn't been enabled.
XCTAssertFalse(service.isEnabled, "The service shouldn't be enabled to begin with.")
#expect(!service.isEnabled, "The service shouldn't be enabled to begin with.")
// When setting a PIN code that is in the block list.
let pinCode = appSettings.appLockPINCodeBlockList[0]
@@ -61,16 +65,17 @@ class AppLockServiceTests: XCTestCase {
// Then the setup should fail and the service be left as disabled.
guard case let .failure(error) = result else {
XCTFail("The call should have failed.")
Issue.record("The call should have failed.")
return
}
XCTAssertEqual(error, .weakPIN, "The PIN should be rejected as weak.")
XCTAssertFalse(service.isEnabled, "The service should remain disabled.")
#expect(error == .weakPIN, "The PIN should be rejected as weak.")
#expect(!service.isEnabled, "The service should remain disabled.")
}
func testShortPINCode() {
@Test
func shortPINCode() {
// Given a service that hasn't been enabled.
XCTAssertFalse(service.isEnabled, "The service shouldn't be enabled to begin with.")
#expect(!service.isEnabled, "The service shouldn't be enabled to begin with.")
// When setting a PIN code that is too short
let pinCode = "123"
@@ -78,16 +83,17 @@ class AppLockServiceTests: XCTestCase {
// Then the setup should fail and the service be left as disabled.
guard case let .failure(error) = result else {
XCTFail("The call should have failed.")
Issue.record("The call should have failed.")
return
}
XCTAssertEqual(error, .invalidPIN, "The PIN should be rejected as invalid.")
XCTAssertFalse(service.isEnabled, "The service should remain disabled.")
#expect(error == .invalidPIN, "The PIN should be rejected as invalid.")
#expect(!service.isEnabled, "The service should remain disabled.")
}
func testNonNumericPINCode() {
@Test
func nonNumericPINCode() {
// Given a service that hasn't been enabled.
XCTAssertFalse(service.isEnabled, "The service shouldn't be enabled to begin with.")
#expect(!service.isEnabled, "The service shouldn't be enabled to begin with.")
// When setting a PIN code that is too short
let pinCode = "abcd"
@@ -95,116 +101,121 @@ class AppLockServiceTests: XCTestCase {
// Then the setup should fail and the service be left as disabled.
guard case let .failure(error) = result else {
XCTFail("The call should have failed.")
Issue.record("The call should have failed.")
return
}
XCTAssertEqual(error, .invalidPIN, "The PIN should be rejected as invalid.")
XCTAssertFalse(service.isEnabled, "The service should remain disabled.")
#expect(error == .invalidPIN, "The PIN should be rejected as invalid.")
#expect(!service.isEnabled, "The service should remain disabled.")
}
func testChangePINCode() {
@Test
func changePINCode() {
// Given a service that is already enabled with a PIN.
let pinCode = "2023"
let newPINCode = "2024"
guard case .success = service.setupPINCode(pinCode) else {
XCTFail("The PIN should be valid.")
Issue.record("The PIN should be valid.")
return
}
XCTAssertTrue(service.isEnabled, "The service should be enabled.")
XCTAssertTrue(service.unlock(with: pinCode), "The initial PIN should work.")
XCTAssertFalse(service.unlock(with: newPINCode), "The PIN we're about to set should not work.")
#expect(service.isEnabled, "The service should be enabled.")
#expect(service.unlock(with: pinCode), "The initial PIN should work.")
#expect(!service.unlock(with: newPINCode), "The PIN we're about to set should not work.")
// When updating the PIN code.
guard case .success = service.setupPINCode(newPINCode) else {
XCTFail("The PIN should be valid.")
Issue.record("The PIN should be valid.")
return
}
// Then the old code should not be accepted.
XCTAssertTrue(service.isEnabled, "The service should remain enabled.")
XCTAssertTrue(service.unlock(with: newPINCode), "The new PIN should work.")
XCTAssertFalse(service.unlock(with: pinCode), "The original PIN should be rejected.")
#expect(service.isEnabled, "The service should remain enabled.")
#expect(service.unlock(with: newPINCode), "The new PIN should work.")
#expect(!service.unlock(with: pinCode), "The original PIN should be rejected.")
}
func testInvalidChangePINCode() {
@Test
func invalidChangePINCode() {
// Given a service that is already enabled with a PIN.
let pinCode = "2023"
let invalidPIN = appSettings.appLockPINCodeBlockList[0]
guard case .success = service.setupPINCode(pinCode) else {
XCTFail("The PIN should be valid.")
Issue.record("The PIN should be valid.")
return
}
XCTAssertTrue(service.isEnabled, "The service should be enabled.")
XCTAssertTrue(service.unlock(with: pinCode), "The initial PIN should work.")
XCTAssertFalse(service.unlock(with: invalidPIN), "The PIN we're about to set should not work.")
#expect(service.isEnabled, "The service should be enabled.")
#expect(service.unlock(with: pinCode), "The initial PIN should work.")
#expect(!service.unlock(with: invalidPIN), "The PIN we're about to set should not work.")
// When updating the PIN code that is in the block list.
let result = service.setupPINCode(invalidPIN)
// Then it should fail and nothing should change.
guard case let .failure(error) = result else {
XCTFail("The call should have failed.")
Issue.record("The call should have failed.")
return
}
XCTAssertEqual(error, .weakPIN, "The PIN should be rejected as weak.")
XCTAssertTrue(service.isEnabled, "The service should remain enabled.")
XCTAssertFalse(service.unlock(with: invalidPIN), "The rejected PIN shouldn't work.")
XCTAssertTrue(service.unlock(with: pinCode), "The original PIN should continue to work.")
#expect(error == .weakPIN, "The PIN should be rejected as weak.")
#expect(service.isEnabled, "The service should remain enabled.")
#expect(!service.unlock(with: invalidPIN), "The rejected PIN shouldn't work.")
#expect(service.unlock(with: pinCode), "The original PIN should continue to work.")
}
func testDisablePINCode() {
@Test
func disablePINCode() {
// Given a service that is already enabled with a PIN.
let pinCode = "2023"
guard case .success = service.setupPINCode(pinCode) else {
XCTFail("The PIN should be valid.")
Issue.record("The PIN should be valid.")
return
}
XCTAssertTrue(service.isEnabled, "The service should be enabled.")
XCTAssertTrue(service.unlock(with: pinCode), "The initial PIN should work.")
#expect(service.isEnabled, "The service should be enabled.")
#expect(service.unlock(with: pinCode), "The initial PIN should work.")
// When disabling the PIN code.
service.disable()
// Then the PIN code should be removed.
XCTAssertFalse(service.isEnabled, "The service should no longer be enabled.")
XCTAssertFalse(service.unlock(with: pinCode), "The initial PIN shouldn't work any more.")
#expect(!service.isEnabled, "The service should no longer be enabled.")
#expect(!service.unlock(with: pinCode), "The initial PIN shouldn't work any more.")
}
// MARK: - Biometric Unlock
func testEnableBiometricUnlock() async {
@Test
func enableBiometricUnlock() async {
// Given a service with the PIN code already set.
let context = LAContextMock()
context.biometryTypeValue = .touchID
context.evaluatedPolicyDomainStateValue = Data("👆".utf8)
service = AppLockService(keychainController: keychainController, appSettings: appSettings, context: context)
guard case .success = service.setupPINCode("2023") else {
XCTFail("The PIN should be valid.")
Issue.record("The PIN should be valid.")
return
}
XCTAssertTrue(service.isEnabled, "The service should be enabled.")
XCTAssertEqual(service.biometryType, .touchID, "The biometry type should be in sync with the mock.")
XCTAssertFalse(service.biometricUnlockEnabled, "Biometric unlock should not be enabled.")
XCTAssertFalse(service.biometricUnlockTrusted, "Biometric unlock should not be trusted.")
#expect(service.isEnabled, "The service should be enabled.")
#expect(service.biometryType == .touchID, "The biometry type should be in sync with the mock.")
#expect(!service.biometricUnlockEnabled, "Biometric unlock should not be enabled.")
#expect(!service.biometricUnlockTrusted, "Biometric unlock should not be trusted.")
// When enabling biometric unlock.
guard case .success = service.enableBiometricUnlock() else {
XCTFail("The biometric lock should enable.")
Issue.record("The biometric lock should enable.")
return
}
context.evaluatePolicyReturnValue = true
// Then the service should be unlockable with biometrics.
XCTAssertEqual(service.biometryType, .touchID, "The biometry type should not change.")
XCTAssertTrue(service.biometricUnlockEnabled, "Biometric unlock should now be enabled.")
XCTAssertTrue(service.biometricUnlockTrusted, "Biometric unlock should now be trusted.")
#expect(service.biometryType == .touchID, "The biometry type should not change.")
#expect(service.biometricUnlockEnabled, "Biometric unlock should now be enabled.")
#expect(service.biometricUnlockTrusted, "Biometric unlock should now be trusted.")
guard await service.unlockWithBiometrics() == .unlocked else {
XCTFail("The biometric unlock should work.")
Issue.record("The biometric unlock should work.")
return
}
}
func testBiometricUnlockTrust() {
@Test
func biometricUnlockTrust() {
// Given a service with the PIN code already set.
let context = LAContextMock()
context.biometryTypeValue = .touchID
@@ -212,129 +223,133 @@ class AppLockServiceTests: XCTestCase {
service = AppLockService(keychainController: keychainController, appSettings: appSettings, context: context)
let pinCode = "2023"
guard case .success = service.setupPINCode(pinCode) else {
XCTFail("The PIN should be valid.")
Issue.record("The PIN should be valid.")
return
}
guard case .success = service.enableBiometricUnlock() else {
XCTFail("The biometric lock should enable.")
Issue.record("The biometric lock should enable.")
return
}
XCTAssertTrue(service.isEnabled, "The service should be enabled.")
XCTAssertEqual(service.biometryType, .touchID, "The biometry type should be in sync with the mock.")
XCTAssertTrue(service.biometricUnlockEnabled, "Biometric unlock should be enabled.")
XCTAssertTrue(service.biometricUnlockTrusted, "Biometric unlock should be trusted.")
#expect(service.isEnabled, "The service should be enabled.")
#expect(service.biometryType == .touchID, "The biometry type should be in sync with the mock.")
#expect(service.biometricUnlockEnabled, "Biometric unlock should be enabled.")
#expect(service.biometricUnlockTrusted, "Biometric unlock should be trusted.")
// When the user changes biometric data.
context.evaluatedPolicyDomainStateValue = Data("👈".utf8)
// Then biometric lock should remain enabled but untrusted.
XCTAssertTrue(service.isEnabled, "The service should remain enabled.")
XCTAssertEqual(service.biometryType, .touchID, "The biometry type should not change.")
XCTAssertTrue(service.biometricUnlockEnabled, "Biometric unlock should remain enabled.")
XCTAssertFalse(service.biometricUnlockTrusted, "Biometric unlock should no longer be trusted.")
#expect(service.isEnabled, "The service should remain enabled.")
#expect(service.biometryType == .touchID, "The biometry type should not change.")
#expect(service.biometricUnlockEnabled, "Biometric unlock should remain enabled.")
#expect(!service.biometricUnlockTrusted, "Biometric unlock should no longer be trusted.")
// When the user confirms their PIN code.
XCTAssertTrue(service.unlock(with: pinCode), "The PIN code should be accepted")
#expect(service.unlock(with: pinCode), "The PIN code should be accepted")
// Then the biometric lock should once again be trusted.
XCTAssertTrue(service.isEnabled, "The service should remain enabled.")
XCTAssertEqual(service.biometryType, .touchID, "The biometry type should not change.")
XCTAssertTrue(service.biometricUnlockEnabled, "Biometric unlock should remain enabled.")
XCTAssertTrue(service.biometricUnlockTrusted, "Biometric unlock should once again be trusted.")
#expect(service.isEnabled, "The service should remain enabled.")
#expect(service.biometryType == .touchID, "The biometry type should not change.")
#expect(service.biometricUnlockEnabled, "Biometric unlock should remain enabled.")
#expect(service.biometricUnlockTrusted, "Biometric unlock should once again be trusted.")
}
func testDisableBiometricUnlock() {
@Test
func disableBiometricUnlock() {
// Given a service with the PIN code already set.
let context = LAContextMock()
context.biometryTypeValue = .touchID
context.evaluatedPolicyDomainStateValue = Data("👆".utf8)
service = AppLockService(keychainController: keychainController, appSettings: appSettings, context: context)
guard case .success = service.setupPINCode("2023") else {
XCTFail("The PIN should be valid.")
Issue.record("The PIN should be valid.")
return
}
guard case .success = service.enableBiometricUnlock() else {
XCTFail("The biometric lock should enable.")
Issue.record("The biometric lock should enable.")
return
}
XCTAssertTrue(service.isEnabled, "The service should be enabled.")
XCTAssertEqual(service.biometryType, .touchID, "The biometry type should be in sync with the mock.")
XCTAssertTrue(service.biometricUnlockEnabled, "Biometric unlock should be enabled.")
XCTAssertTrue(service.biometricUnlockTrusted, "Biometric unlock should be trusted.")
#expect(service.isEnabled, "The service should be enabled.")
#expect(service.biometryType == .touchID, "The biometry type should be in sync with the mock.")
#expect(service.biometricUnlockEnabled, "Biometric unlock should be enabled.")
#expect(service.biometricUnlockTrusted, "Biometric unlock should be trusted.")
// When disabling biometric unlock.
service.disableBiometricUnlock()
// Then only PIN unlock should remain enabled.
XCTAssertTrue(service.isEnabled, "The service should remain enabled.")
XCTAssertEqual(service.biometryType, .touchID, "The biometry type should not change.")
XCTAssertFalse(service.biometricUnlockEnabled, "Biometric unlock should become disabled.")
XCTAssertFalse(service.biometricUnlockTrusted, "Biometric unlock should no longer be trusted.")
#expect(service.isEnabled, "The service should remain enabled.")
#expect(service.biometryType == .touchID, "The biometry type should not change.")
#expect(!service.biometricUnlockEnabled, "Biometric unlock should become disabled.")
#expect(!service.biometricUnlockTrusted, "Biometric unlock should no longer be trusted.")
}
func testDisablePINWithBiometricUnlock() {
@Test
func disablePINWithBiometricUnlock() {
// Given a service with the PIN code already set.
let context = LAContextMock()
context.biometryTypeValue = .touchID
context.evaluatedPolicyDomainStateValue = Data("👆".utf8)
service = AppLockService(keychainController: keychainController, appSettings: appSettings, context: context)
guard case .success = service.setupPINCode("2023") else {
XCTFail("The PIN should be valid.")
Issue.record("The PIN should be valid.")
return
}
guard case .success = service.enableBiometricUnlock() else {
XCTFail("The biometric lock should enable.")
Issue.record("The biometric lock should enable.")
return
}
XCTAssertTrue(service.isEnabled, "The service should be enabled.")
XCTAssertTrue(service.biometricUnlockEnabled, "Biometric unlock should be enabled.")
XCTAssertTrue(service.biometricUnlockTrusted, "Biometric unlock should be trusted.")
#expect(service.isEnabled, "The service should be enabled.")
#expect(service.biometricUnlockEnabled, "Biometric unlock should be enabled.")
#expect(service.biometricUnlockTrusted, "Biometric unlock should be trusted.")
// When disabling the PIN lock.
service.disable()
// Then both PIN and biometric unlock should be disabled.
XCTAssertFalse(service.isEnabled, "The service should remain enabled.")
XCTAssertFalse(service.biometricUnlockEnabled, "Biometric unlock should become disabled.")
XCTAssertFalse(service.biometricUnlockTrusted, "Biometric unlock should no longer be trusted.")
#expect(!service.isEnabled, "The service should remain enabled.")
#expect(!service.biometricUnlockEnabled, "Biometric unlock should become disabled.")
#expect(!service.biometricUnlockTrusted, "Biometric unlock should no longer be trusted.")
}
// MARK: - Attempt failures
func testResetAttemptsOnUnlock() {
@Test
func resetAttemptsOnUnlock() {
// Given a service that is enabled and has failed unlock attempts.
let pinCode = "2023"
guard case .success = service.setupPINCode(pinCode) else {
XCTFail("The PIN should be valid.")
Issue.record("The PIN should be valid.")
return
}
appSettings.appLockNumberOfPINAttempts = 2
XCTAssertEqual(appSettings.appLockNumberOfPINAttempts, 2, "The initial conditions should be stored.")
XCTAssertTrue(service.isEnabled, "The service should be enabled.")
#expect(appSettings.appLockNumberOfPINAttempts == 2, "The initial conditions should be stored.")
#expect(service.isEnabled, "The service should be enabled.")
// When unlocking the service
XCTAssertTrue(service.unlock(with: pinCode), "The PIN should work.")
#expect(service.unlock(with: pinCode), "The PIN should work.")
// Then the attempts counts should both be reset.
XCTAssertEqual(appSettings.appLockNumberOfPINAttempts, 0, "The PIN attempts should be reset.")
#expect(appSettings.appLockNumberOfPINAttempts == 0, "The PIN attempts should be reset.")
}
func testResetAttemptsOnDisable() {
@Test
func resetAttemptsOnDisable() {
// Given a service that is enabled and has failed unlock attempts.
let pinCode = "2023"
guard case .success = service.setupPINCode(pinCode) else {
XCTFail("The PIN should be valid.")
Issue.record("The PIN should be valid.")
return
}
appSettings.appLockNumberOfPINAttempts = 2
XCTAssertEqual(appSettings.appLockNumberOfPINAttempts, 2, "The initial conditions should be stored.")
XCTAssertTrue(service.isEnabled, "The service should be enabled.")
#expect(appSettings.appLockNumberOfPINAttempts == 2, "The initial conditions should be stored.")
#expect(service.isEnabled, "The service should be enabled.")
// When disabling the service
service.disable()
XCTAssertFalse(service.isEnabled, "The service should be disabled.")
#expect(!service.isEnabled, "The service should be disabled.")
// Then the attempts counts should both be reset.
XCTAssertEqual(appSettings.appLockNumberOfPINAttempts, 0, "The PIN attempts should be reset.")
#expect(appSettings.appLockNumberOfPINAttempts == 0, "The PIN attempts should be reset.")
}
}