apple_kit

Apple-native services for Radroots iOS and macOS apps
git clone https://radroots.dev/git/apple_kit.git
Log | Files | Refs | README

RadrootsAppleUserPresenceTests.swift (3663B)


      1 import Foundation
      2 import Testing
      3 @testable import RadrootsKit
      4 
      5 @Test func appleUserPresenceReportsStatusThroughAdapter() async throws {
      6     let expectedStatus = RadrootsUserPresenceStatus(
      7         support: .deviceCredential,
      8         biometryKind: .none,
      9         canEvaluateDeviceCredential: true,
     10         canEvaluateBiometrics: false
     11     )
     12     let service = RadrootsAppleUserPresence(
     13         adapters: RadrootsAppleUserPresenceAdapters(
     14             currentStatus: {
     15                 expectedStatus
     16             },
     17             verify: { request in
     18                 RadrootsUserPresenceResult(policy: request.policy, verified: true)
     19             }
     20         )
     21     )
     22 
     23     let status = try await service.currentStatus()
     24 
     25     #expect(status == expectedStatus)
     26 }
     27 
     28 @Test func appleUserPresenceVerifiesThroughAdapter() async throws {
     29     let request = try RadrootsUserPresenceRequest(
     30         policy: .deviceOwnerAuthenticationWithBiometrics,
     31         reason: "Unlock local Nostr identity"
     32     )
     33     let service = RadrootsAppleUserPresence(
     34         adapters: RadrootsAppleUserPresenceAdapters(
     35             currentStatus: {
     36                 .unavailable
     37             },
     38             verify: { request in
     39                 RadrootsUserPresenceResult(policy: request.policy, verified: true)
     40             }
     41         )
     42     )
     43 
     44     let result = try await service.verify(request)
     45 
     46     #expect(result.policy == .deviceOwnerAuthenticationWithBiometrics)
     47     #expect(result.verified)
     48 }
     49 
     50 @Test func appleUserPresencePropagatesAdapterFailures() async throws {
     51     let service = RadrootsAppleUserPresence(
     52         adapters: RadrootsAppleUserPresenceAdapters(
     53             currentStatus: {
     54                 .unavailable
     55             },
     56             verify: { _ in
     57                 throw RadrootsUserPresenceError.unavailable("user presence unavailable")
     58             }
     59         )
     60     )
     61 
     62     await #expect(throws: RadrootsUserPresenceError.unavailable("user presence unavailable")) {
     63         try await service.verify(RadrootsUserPresenceRequest(reason: "Delete local Nostr identity"))
     64     }
     65 }
     66 
     67 @Test func appleUserPresenceAsyncSupportTimesOutUnresolvedCallbacks() async {
     68     await #expect(throws: RadrootsUserPresenceError.timeout("timed out")) {
     69         let _: Bool = try await RadrootsAppleUserPresenceAsyncSupport.awaitCallback(
     70             timeout: 0.001,
     71             timeoutMessage: "timed out"
     72         ) { _ in }
     73     }
     74 }
     75 
     76 #if canImport(LocalAuthentication)
     77 import LocalAuthentication
     78 
     79 @Test func appleUserPresenceMapsLocalAuthenticationPolicies() {
     80     #expect(
     81         RadrootsAppleUserPresenceAdapters.platformPolicy(.deviceOwnerAuthentication) ==
     82             LAPolicy.deviceOwnerAuthentication
     83     )
     84     #expect(
     85         RadrootsAppleUserPresenceAdapters.platformPolicy(.deviceOwnerAuthenticationWithBiometrics) ==
     86             LAPolicy.deviceOwnerAuthenticationWithBiometrics
     87     )
     88 }
     89 
     90 @Test func appleUserPresenceMapsLocalAuthenticationErrors() {
     91     assertUserPresenceError(
     92         RadrootsAppleUserPresenceAdapters.adapt(error: LAError(.userCancel)),
     93         matches: { if case .userCancelled = $0 { true } else { false } }
     94     )
     95     assertUserPresenceError(
     96         RadrootsAppleUserPresenceAdapters.adapt(error: LAError(.biometryNotAvailable)),
     97         matches: { if case .unavailable = $0 { true } else { false } }
     98     )
     99     assertUserPresenceError(
    100         RadrootsAppleUserPresenceAdapters.adapt(error: LAError(.authenticationFailed)),
    101         matches: { if case .permissionDenied = $0 { true } else { false } }
    102     )
    103 }
    104 
    105 private func assertUserPresenceError(
    106     _ error: RadrootsUserPresenceError,
    107     matches: (RadrootsUserPresenceError) -> Bool
    108 ) {
    109     #expect(matches(error))
    110 }
    111 #endif