apple_kit

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

RadrootsAppleLocationServicesTests.swift (7517B)


      1 import Foundation
      2 import Testing
      3 
      4 @testable import RadrootsKit
      5 
      6 #if canImport(CoreLocation)
      7     import CoreLocation
      8 #endif
      9 
     10 @Test func appleLocationServicesReportsCurrentAvailability() async {
     11     let service = RadrootsAppleLocationServices(
     12         adapters: RadrootsAppleLocationServicesAdapters(
     13             locationServicesEnabled: { true },
     14             authorizationStatus: { .authorizedWhenInUse },
     15             requestWhenInUseAuthorization: { _ in .authorizedWhenInUse },
     16             requestCurrentLocation: { _ in
     17                 throw RadrootsLocationServicesError.permanentFailure
     18             }
     19         )
     20     )
     21 
     22     let availability = await service.currentAvailability()
     23 
     24     #expect(availability.locationServicesEnabled)
     25     #expect(availability.authorization == .authorizedWhenInUse)
     26     #expect(availability.canRequestCurrentLocation)
     27 }
     28 
     29 @Test func appleLocationServicesShortCircuitsAuthorizationRequests() async throws {
     30     let authorized = RadrootsAppleLocationServices(
     31         adapters: RadrootsAppleLocationServicesAdapters(
     32             locationServicesEnabled: { true },
     33             authorizationStatus: { .authorizedWhenInUse },
     34             requestWhenInUseAuthorization: { _ in
     35                 throw RadrootsLocationServicesError.permanentFailure
     36             },
     37             requestCurrentLocation: { _ in
     38                 throw RadrootsLocationServicesError.permanentFailure
     39             }
     40         )
     41     )
     42 
     43     #expect(try await authorized.requestWhenInUseAuthorization() == .authorizedWhenInUse)
     44 
     45     let denied = RadrootsAppleLocationServices(
     46         adapters: RadrootsAppleLocationServicesAdapters(
     47             locationServicesEnabled: { true },
     48             authorizationStatus: { .denied },
     49             requestWhenInUseAuthorization: { _ in
     50                 throw RadrootsLocationServicesError.permanentFailure
     51             },
     52             requestCurrentLocation: { _ in
     53                 throw RadrootsLocationServicesError.permanentFailure
     54             }
     55         )
     56     )
     57 
     58     await #expect(throws: RadrootsLocationServicesError.permissionDenied) {
     59         _ = try await denied.requestWhenInUseAuthorization()
     60     }
     61 }
     62 
     63 @Test func appleLocationServicesRequestsAuthorizationWhenUndetermined() async throws {
     64     let service = RadrootsAppleLocationServices(
     65         adapters: RadrootsAppleLocationServicesAdapters(
     66             locationServicesEnabled: { true },
     67             authorizationStatus: { .notDetermined },
     68             requestWhenInUseAuthorization: { timeoutSeconds in
     69                 #expect(timeoutSeconds == 12)
     70                 return .authorizedWhenInUse
     71             },
     72             requestCurrentLocation: { _ in
     73                 throw RadrootsLocationServicesError.permanentFailure
     74             }
     75         )
     76     )
     77 
     78     #expect(try await service.requestWhenInUseAuthorization() == .authorizedWhenInUse)
     79 }
     80 
     81 @Test func appleLocationServicesReturnsCurrentLocationForAuthorizedState() async throws {
     82     let capturedAt = Date(timeIntervalSince1970: 100)
     83     let reading = try RadrootsLocationReading(
     84         coordinate: RadrootsLocationCoordinate(latitude: 49.2827, longitude: -123.1207),
     85         horizontalAccuracyMeters: 4,
     86         capturedAt: capturedAt
     87     )
     88     let service = RadrootsAppleLocationServices(
     89         adapters: RadrootsAppleLocationServicesAdapters(
     90             now: { Date(timeIntervalSince1970: 102) },
     91             locationServicesEnabled: { true },
     92             authorizationStatus: { .authorizedWhenInUse },
     93             requestWhenInUseAuthorization: { _ in .authorizedWhenInUse },
     94             requestCurrentLocation: { request in
     95                 #expect(request.timeoutSeconds == 3)
     96                 return reading
     97             }
     98         )
     99     )
    100 
    101     let result = try await service.currentLocation(
    102         RadrootsCurrentLocationRequest(
    103         timeoutSeconds: 3,
    104         maximumCachedReadingAgeSeconds: 5
    105     ))
    106 
    107     #expect(result.reading == reading)
    108     #expect(result.authorization == .authorizedWhenInUse)
    109 }
    110 
    111 @Test func appleLocationServicesRejectsCurrentLocationForUnauthorizedState() async {
    112     let service = RadrootsAppleLocationServices(
    113         adapters: RadrootsAppleLocationServicesAdapters(
    114             locationServicesEnabled: { true },
    115             authorizationStatus: { .notDetermined },
    116             requestWhenInUseAuthorization: { _ in .authorizedWhenInUse },
    117             requestCurrentLocation: { _ in
    118                 throw RadrootsLocationServicesError.permanentFailure
    119             }
    120         )
    121     )
    122 
    123     await #expect(throws: RadrootsLocationServicesError.permissionDenied) {
    124         _ = try await service.currentLocation(RadrootsCurrentLocationRequest(timeoutSeconds: 1))
    125     }
    126 }
    127 
    128 @Test func appleLocationServicesRejectsStaleCurrentLocationReadings() async throws {
    129     let reading = try RadrootsLocationReading(
    130         coordinate: RadrootsLocationCoordinate(latitude: 49.2827, longitude: -123.1207),
    131         horizontalAccuracyMeters: 4,
    132         capturedAt: Date(timeIntervalSince1970: 100)
    133     )
    134     let service = RadrootsAppleLocationServices(
    135         adapters: RadrootsAppleLocationServicesAdapters(
    136             now: { Date(timeIntervalSince1970: 200) },
    137             locationServicesEnabled: { true },
    138             authorizationStatus: { .authorizedWhenInUse },
    139             requestWhenInUseAuthorization: { _ in .authorizedWhenInUse },
    140             requestCurrentLocation: { _ in reading }
    141         )
    142     )
    143 
    144     await #expect(throws: RadrootsLocationServicesError.transientFailure) {
    145         _ = try await service.currentLocation(
    146             RadrootsCurrentLocationRequest(
    147             timeoutSeconds: 1,
    148             maximumCachedReadingAgeSeconds: 5
    149         ))
    150     }
    151 }
    152 
    153 @Test func appleLocationServicesPropagatesTypedLocationFailures() async {
    154     let service = RadrootsAppleLocationServices(
    155         adapters: RadrootsAppleLocationServicesAdapters(
    156             locationServicesEnabled: { true },
    157             authorizationStatus: { .authorizedWhenInUse },
    158             requestWhenInUseAuthorization: { _ in .authorizedWhenInUse },
    159             requestCurrentLocation: { _ in
    160                 throw RadrootsLocationServicesError.timeout
    161             }
    162         )
    163     )
    164 
    165     await #expect(throws: RadrootsLocationServicesError.timeout) {
    166         _ = try await service.currentLocation(RadrootsCurrentLocationRequest(timeoutSeconds: 1))
    167     }
    168 }
    169 
    170 #if canImport(CoreLocation)
    171     @Test func appleLocationServicesMapsCoreLocationAuthorization() {
    172         #expect(
    173             RadrootsAppleLocationServicesAdapters.authorization(
    174             for: CLAuthorizationStatus.notDetermined,
    175             locationServicesEnabled: true
    176         ) == .notDetermined)
    177         #expect(
    178             RadrootsAppleLocationServicesAdapters.authorization(
    179             for: CLAuthorizationStatus.denied,
    180             locationServicesEnabled: true
    181         ) == .denied)
    182         #expect(
    183             RadrootsAppleLocationServicesAdapters.authorization(
    184             for: CLAuthorizationStatus.authorizedAlways,
    185             locationServicesEnabled: true
    186         ) == .authorizedAlways)
    187         #expect(
    188             RadrootsAppleLocationServicesAdapters.authorization(
    189             for: CLAuthorizationStatus.authorizedAlways,
    190             locationServicesEnabled: false
    191         ) == .unavailable)
    192         #if os(iOS)
    193             #expect(
    194                 RadrootsAppleLocationServicesAdapters.authorization(
    195                 for: CLAuthorizationStatus.authorizedWhenInUse,
    196                 locationServicesEnabled: true
    197             ) == .authorizedWhenInUse)
    198         #endif
    199     }
    200 #endif