226 lines
7.0 KiB
Swift
226 lines
7.0 KiB
Swift
//
|
|
// LocationServiceTests.swift
|
|
// AutoCatCoreTests
|
|
//
|
|
// Created by Selim Mustafaev on 01.08.2024.
|
|
// Copyright © 2024 Selim Mustafaev. All rights reserved.
|
|
//
|
|
|
|
import Testing
|
|
import CoreLocation
|
|
import Mockable
|
|
import Intents
|
|
import Contacts
|
|
@testable import AutoCatCore
|
|
|
|
@MainActor
|
|
struct LocationServiceTests {
|
|
|
|
let latitude: CLLocationDegrees = 10
|
|
let longitude: CLLocationDegrees = 10
|
|
let address = "Test Address"
|
|
|
|
let location: CLLocation
|
|
|
|
let geocoderMock = MockGeocoderProtocol()
|
|
let locationManagerMock = MockSwiftLocationProtocol()
|
|
let settingsServiceMock = MockSettingsServiceProtocol()
|
|
let locationService: LocationService
|
|
|
|
init() {
|
|
|
|
self.location = CLLocation(latitude: latitude, longitude: longitude)
|
|
|
|
self.locationService = LocationService(geocoder: geocoderMock,
|
|
locationManager: locationManagerMock,
|
|
settingsService: settingsServiceMock)
|
|
|
|
given(settingsServiceMock)
|
|
.user.willReturn(User())
|
|
}
|
|
|
|
@Test
|
|
func getValidAddress() async throws {
|
|
|
|
let placemark = CLPlacemark(location: location, name: address, postalAddress: nil)
|
|
|
|
given(geocoderMock)
|
|
.reverseGeocodeLocation(.any)
|
|
.willReturn([placemark])
|
|
|
|
let result = try await locationService.getAddressForLocation(latitude: latitude,
|
|
longitude: longitude)
|
|
|
|
verify(geocoderMock)
|
|
.reverseGeocodeLocation(.any)
|
|
.called(.once)
|
|
|
|
#expect(result == address)
|
|
}
|
|
|
|
@Test
|
|
func getNilAddress() async throws {
|
|
|
|
let placemark = CLPlacemark(location: location, name: nil, postalAddress: nil)
|
|
|
|
given(geocoderMock)
|
|
.reverseGeocodeLocation(.any)
|
|
.willReturn([placemark])
|
|
|
|
await #expect(throws: LocationError.reverseGeocode) {
|
|
_ = try await locationService.getAddressForLocation(latitude: latitude,
|
|
longitude: longitude)
|
|
}
|
|
|
|
verify(geocoderMock)
|
|
.reverseGeocodeLocation(.any)
|
|
.called(.once)
|
|
}
|
|
|
|
@Test
|
|
func addressNotFound() async throws {
|
|
|
|
given(geocoderMock)
|
|
.reverseGeocodeLocation(.any)
|
|
.willReturn([])
|
|
|
|
await #expect(throws: LocationError.reverseGeocode) {
|
|
_ = try await locationService.getAddressForLocation(latitude: latitude,
|
|
longitude: longitude)
|
|
}
|
|
|
|
verify(geocoderMock)
|
|
.reverseGeocodeLocation(.any)
|
|
.called(.once)
|
|
}
|
|
|
|
@Test("Get location: denied")
|
|
func getLocationDenied() async throws {
|
|
|
|
given(locationManagerMock)
|
|
.authorizationStatus
|
|
.willReturn(.denied)
|
|
|
|
await #expect(throws: CLError(.denied)) {
|
|
_ = try await locationService.requestCurrentLocation()
|
|
}
|
|
}
|
|
|
|
@Test("Get location: not determined -> denied")
|
|
func getLocationNotDeterminedDenied() async throws {
|
|
|
|
given(locationManagerMock)
|
|
.authorizationStatus
|
|
.willReturn(.notDetermined)
|
|
|
|
given(locationManagerMock)
|
|
.requestPermission(.value(.always))
|
|
.willReturn(.denied)
|
|
|
|
when(locationManagerMock)
|
|
.requestPermission(.value(.always))
|
|
.perform {
|
|
given(locationManagerMock)
|
|
.authorizationStatus
|
|
.willReturn(.denied)
|
|
}
|
|
|
|
await #expect(throws: CLError(.denied)) {
|
|
_ = try await locationService.requestCurrentLocation()
|
|
}
|
|
}
|
|
|
|
@Test("Get location: not determined -> allow")
|
|
func getLocationNotDeterminedAllow() async throws {
|
|
|
|
given(locationManagerMock)
|
|
.authorizationStatus
|
|
.willReturn(.notDetermined)
|
|
|
|
given(locationManagerMock)
|
|
.requestPermission(.value(.always))
|
|
.willReturn(.authorizedWhenInUse)
|
|
|
|
when(locationManagerMock)
|
|
.requestPermission(.value(.always))
|
|
.perform {
|
|
given(locationManagerMock)
|
|
.authorizationStatus
|
|
.willReturn(.authorizedWhenInUse)
|
|
}
|
|
|
|
given(locationManagerMock)
|
|
.requestLocation(accuracy: .any, timeout: .any)
|
|
.willReturn(.didUpdateLocations([location]))
|
|
|
|
let event = try await locationService.requestCurrentLocation()
|
|
|
|
#expect(event.latitude == latitude)
|
|
#expect(event.longitude == longitude)
|
|
}
|
|
|
|
@Test("Get location: normal")
|
|
func getLocationNormal() async throws {
|
|
|
|
given(locationManagerMock)
|
|
.authorizationStatus
|
|
.willReturn(.authorizedWhenInUse)
|
|
|
|
given(locationManagerMock)
|
|
.requestLocation(accuracy: .any, timeout: .any)
|
|
.willReturn(.didUpdateLocations([location]))
|
|
|
|
let event = try await locationService.requestCurrentLocation()
|
|
|
|
#expect(event.latitude == latitude)
|
|
#expect(event.longitude == longitude)
|
|
}
|
|
|
|
@Test("Get location: no location")
|
|
func getLocationNone() async throws {
|
|
|
|
given(locationManagerMock)
|
|
.authorizationStatus
|
|
.willReturn(.authorizedWhenInUse)
|
|
|
|
given(locationManagerMock)
|
|
.requestLocation(accuracy: .any, timeout: .any)
|
|
.willReturn(.didUpdateLocations([]))
|
|
|
|
await #expect(throws: LocationError.generic) {
|
|
_ = try await locationService.requestCurrentLocation()
|
|
}
|
|
}
|
|
|
|
@Test("Get location: parallel requests")
|
|
func getLocationParallel() async throws {
|
|
|
|
given(locationManagerMock)
|
|
.authorizationStatus
|
|
.willReturn(.authorizedWhenInUse)
|
|
|
|
given(locationManagerMock)
|
|
.requestLocation(accuracy: .any, timeout: .any)
|
|
.willReturn(.didUpdateLocations([location]))
|
|
|
|
async let task1 = locationService.requestCurrentLocation()
|
|
async let task2 = locationService.requestCurrentLocation()
|
|
|
|
try await Task.sleep(nanoseconds: 500_000_000)
|
|
async let task3 = locationService.requestCurrentLocation()
|
|
|
|
let (event1, event2, event3) = try await (task1, task2, task3)
|
|
|
|
verify(locationManagerMock)
|
|
.requestLocation(accuracy: .any, timeout: .any)
|
|
.called(.exactly(2))
|
|
|
|
#expect(event1.latitude == latitude)
|
|
#expect(event1.longitude == longitude)
|
|
#expect(event2.latitude == latitude)
|
|
#expect(event2.longitude == longitude)
|
|
#expect(event3.latitude == latitude)
|
|
#expect(event3.longitude == longitude)
|
|
}
|
|
}
|