apple_kit

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

RadrootsAppleLocationServicesTests.swift (7604B)


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