425 lines
14 KiB
Swift
425 lines
14 KiB
Swift
//
|
||
// VehicleServiceTests.swift
|
||
// AutoCatCoreTests
|
||
//
|
||
// Created by Selim Mustafaev on 24.01.2025.
|
||
// Copyright © 2025 Selim Mustafaev. All rights reserved.
|
||
//
|
||
|
||
import Testing
|
||
import Mockable
|
||
import AutoCatCore
|
||
|
||
struct VehicleServiceTests {
|
||
|
||
let apiServiceMock = MockApiServiceProtocol()
|
||
let storageServiceMock = MockStorageServiceProtocol()
|
||
let locationServiceMock: MockLocationServiceProtocol
|
||
|
||
let vehicleService: VehicleServiceProtocol
|
||
|
||
let existingVehicleNumber = "А123АА761"
|
||
let nonExistingVehicleNumber = "А999АА761"
|
||
let testVin = "1234567890"
|
||
|
||
init () async throws {
|
||
|
||
self.locationServiceMock = await .init()
|
||
|
||
self.vehicleService = VehicleService(apiService: apiServiceMock,
|
||
storageService: storageServiceMock,
|
||
locationService: locationServiceMock)
|
||
}
|
||
|
||
@Test("Check vehicle (all throws)")
|
||
func checkVehicleAllThrows() async throws {
|
||
|
||
given(storageServiceMock)
|
||
.loadVehicle(number: .any)
|
||
.willThrow(TestError.generic)
|
||
|
||
given(locationServiceMock)
|
||
.getRecentLocation()
|
||
.willThrow(TestError.generic)
|
||
|
||
given(apiServiceMock)
|
||
.checkVehicle(by: .any, notes: .any, events: .any, force: .any)
|
||
.willThrow(TestError.generic)
|
||
|
||
given(locationServiceMock)
|
||
.resetLastEvent()
|
||
.willReturn()
|
||
|
||
given(storageServiceMock)
|
||
.updateVehicle(dto: .any, policy: .any)
|
||
.willThrow(TestError.generic)
|
||
|
||
await #expect(throws: TestError.generic) {
|
||
_ = try await vehicleService.check(number: existingVehicleNumber)
|
||
}
|
||
}
|
||
|
||
@Test("Check vehicle (all but DB update throws)")
|
||
func checkVehicleDbUpdate() async throws {
|
||
|
||
given(storageServiceMock)
|
||
.loadVehicle(number: .any)
|
||
.willThrow(TestError.generic)
|
||
|
||
given(locationServiceMock)
|
||
.getRecentLocation()
|
||
.willThrow(TestError.generic)
|
||
|
||
given(apiServiceMock)
|
||
.checkVehicle(by: .any, notes: .any, events: .any, force: .any)
|
||
.willThrow(TestError.generic)
|
||
|
||
given(locationServiceMock)
|
||
.resetLastEvent()
|
||
.willReturn()
|
||
|
||
given(storageServiceMock)
|
||
.updateVehicle(dto: .any, policy: .any)
|
||
.willReturn(true)
|
||
|
||
let result = try await vehicleService.check(number: existingVehicleNumber)
|
||
|
||
#expect(result.vehicle.unrecognized)
|
||
#expect(result.vehicle.events.isEmpty)
|
||
#expect(result.errors.count == 2)
|
||
}
|
||
|
||
@Test("Check vehicle (existing unrecognized vehicle)")
|
||
func checkVehicleExistingVehicle() async throws {
|
||
|
||
var vehicle = VehicleDto(number: existingVehicleNumber)
|
||
vehicle.vin1 = testVin
|
||
|
||
given(storageServiceMock)
|
||
.loadVehicle(number: .any)
|
||
.willReturn(vehicle)
|
||
|
||
given(locationServiceMock)
|
||
.getRecentLocation()
|
||
.willThrow(TestError.generic)
|
||
|
||
given(apiServiceMock)
|
||
.checkVehicle(by: .any, notes: .any, events: .any, force: .any)
|
||
.willThrow(TestError.generic)
|
||
|
||
given(locationServiceMock)
|
||
.resetLastEvent()
|
||
.willReturn()
|
||
|
||
given(storageServiceMock)
|
||
.updateVehicle(dto: .any, policy: .any)
|
||
.willReturn(true)
|
||
|
||
let result = try await vehicleService.check(number: existingVehicleNumber)
|
||
|
||
#expect(result.vehicle.vin1 == testVin)
|
||
#expect(result.errors.count == 2)
|
||
}
|
||
|
||
@Test("Check vehicle (location received)")
|
||
func checkVehicleLocationReceived() async throws {
|
||
|
||
var vehicle = VehicleDto(number: existingVehicleNumber)
|
||
vehicle.vin1 = testVin
|
||
|
||
given(storageServiceMock)
|
||
.loadVehicle(number: .any)
|
||
.willReturn(vehicle)
|
||
|
||
given(locationServiceMock)
|
||
.getRecentLocation()
|
||
.willReturn(.valid)
|
||
|
||
given(apiServiceMock)
|
||
.checkVehicle(by: .any, notes: .any, events: .any, force: .any)
|
||
.willThrow(TestError.generic)
|
||
|
||
given(locationServiceMock)
|
||
.resetLastEvent()
|
||
.willReturn()
|
||
|
||
given(storageServiceMock)
|
||
.updateVehicle(dto: .any, policy: .any)
|
||
.willReturn(true)
|
||
|
||
let result = try await vehicleService.check(number: VehicleDto.validNumber)
|
||
|
||
#expect(result.vehicle.vin1 == testVin)
|
||
#expect(result.errors.count == 1)
|
||
#expect(result.vehicle.events.count == 1)
|
||
#expect(result.vehicle.events.first?.latitude == VehicleEventDto.validLatitude)
|
||
#expect(result.vehicle.events.first?.longitude == VehicleEventDto.validLongitude)
|
||
}
|
||
|
||
@Test("Check vehicle (existing normal vehicle)")
|
||
func checkVehicleExistingNormalVehicle() async throws {
|
||
|
||
given(storageServiceMock)
|
||
.loadVehicle(number: .any)
|
||
.willReturn(.normal)
|
||
|
||
given(locationServiceMock)
|
||
.getRecentLocation()
|
||
.willReturn(.valid)
|
||
|
||
given(apiServiceMock)
|
||
.checkVehicle(by: .any, notes: .any, events: .any, force: .any)
|
||
.willThrow(TestError.generic)
|
||
|
||
given(locationServiceMock)
|
||
.resetLastEvent()
|
||
.willReturn()
|
||
|
||
given(storageServiceMock)
|
||
.updateVehicle(dto: .any, policy: .any)
|
||
.willReturn(true)
|
||
|
||
given(apiServiceMock)
|
||
.add(event: .any, to: .any)
|
||
.willThrow(TestError.generic)
|
||
|
||
let result = try await vehicleService.check(number: VehicleDto.validNumber)
|
||
|
||
#expect(result.vehicle.number == VehicleDto.validNumber)
|
||
#expect(result.errors.count == 2)
|
||
#expect(result.vehicle.events.count == 1)
|
||
#expect(result.vehicle.events.first?.latitude == VehicleEventDto.validLatitude)
|
||
#expect(result.vehicle.events.first?.longitude == VehicleEventDto.validLongitude)
|
||
}
|
||
|
||
@Test("Check vehicle (existing normal vehicle, add event)")
|
||
func checkVehicleExistingNormalVehicleAddEvent() async throws {
|
||
|
||
given(storageServiceMock)
|
||
.loadVehicle(number: .any)
|
||
.willReturn(.normal)
|
||
|
||
given(locationServiceMock)
|
||
.getRecentLocation()
|
||
.willReturn(.valid)
|
||
|
||
given(apiServiceMock)
|
||
.checkVehicle(by: .any, notes: .any, events: .any, force: .any)
|
||
.willThrow(TestError.generic)
|
||
|
||
given(locationServiceMock)
|
||
.resetLastEvent()
|
||
.willReturn()
|
||
|
||
given(storageServiceMock)
|
||
.updateVehicle(dto: .any, policy: .any)
|
||
.willReturn(true)
|
||
|
||
given(apiServiceMock)
|
||
.add(event: .any, to: .any)
|
||
.willReturn(.normal.addEvent(.valid))
|
||
|
||
let result = try await vehicleService.check(number: VehicleDto.validNumber)
|
||
|
||
#expect(result.vehicle.number == VehicleDto.validNumber)
|
||
#expect(result.errors.count == 1)
|
||
#expect(result.vehicle.events.count == 1)
|
||
#expect(result.vehicle.events.first?.latitude == VehicleEventDto.validLatitude)
|
||
#expect(result.vehicle.events.first?.longitude == VehicleEventDto.validLongitude)
|
||
}
|
||
|
||
@Test("Check vehicle (with server check working)")
|
||
func checkVehicleServerCheck() async throws {
|
||
|
||
given(storageServiceMock)
|
||
.loadVehicle(number: .any)
|
||
.willReturn(.normal)
|
||
|
||
given(locationServiceMock)
|
||
.getRecentLocation()
|
||
.willReturn(.valid)
|
||
|
||
given(apiServiceMock)
|
||
.checkVehicle(by: .any, notes: .any, events: .any, force: .any)
|
||
.willReturn(.normal)
|
||
|
||
given(locationServiceMock)
|
||
.resetLastEvent()
|
||
.willReturn()
|
||
|
||
given(storageServiceMock)
|
||
.updateVehicle(dto: .any, policy: .any)
|
||
.willReturn(true)
|
||
|
||
given(apiServiceMock)
|
||
.add(event: .any, to: .any)
|
||
.willReturn(.normal.addEvent(.valid))
|
||
|
||
let result = try await vehicleService.check(number: VehicleDto.validNumber)
|
||
|
||
#expect(result.vehicle.number == VehicleDto.validNumber)
|
||
#expect(result.errors.count == 0)
|
||
#expect(result.vehicle.events.count == 1)
|
||
#expect(result.vehicle.events.first?.latitude == VehicleEventDto.validLatitude)
|
||
#expect(result.vehicle.events.first?.longitude == VehicleEventDto.validLongitude)
|
||
}
|
||
|
||
@Test("Check")
|
||
func check() async throws {
|
||
|
||
let vehicle: VehicleDto = .normal
|
||
|
||
given(storageServiceMock)
|
||
.loadVehicle(number: .any)
|
||
.willReturn(.normal)
|
||
|
||
given(locationServiceMock)
|
||
.getRecentLocation()
|
||
.willReturn(.valid)
|
||
|
||
given(apiServiceMock)
|
||
.checkVehicle(by: .any, notes: .any, events: .any, force: .any)
|
||
.willReturn(vehicle)
|
||
|
||
given(locationServiceMock)
|
||
.resetLastEvent()
|
||
.willReturn()
|
||
|
||
given(storageServiceMock)
|
||
.updateVehicle(dto: .any, policy: .any)
|
||
.willReturn(true)
|
||
|
||
given(apiServiceMock)
|
||
.add(event: .any, to: .any)
|
||
.willReturn(vehicle.addEvent(.valid))
|
||
|
||
let result = try await vehicleService.check(number: vehicle.number)
|
||
|
||
verify(apiServiceMock)
|
||
.checkVehicle(by: .any, notes: .any, events: .any, force: .value(false))
|
||
.called(.once)
|
||
|
||
verify(locationServiceMock)
|
||
.getRecentLocation()
|
||
.called(.once)
|
||
|
||
verify(apiServiceMock)
|
||
.add(event: .any, to: .any)
|
||
.called(.once)
|
||
|
||
verify(storageServiceMock)
|
||
.updateVehicle(dto: .any, policy: .value(.always))
|
||
.called(.once)
|
||
|
||
#expect(result.vehicle.number == vehicle.number)
|
||
#expect(result.errors.count == 0)
|
||
#expect(result.vehicle.events.count == 1)
|
||
#expect(result.vehicle.events.first?.latitude == VehicleEventDto.validLatitude)
|
||
#expect(result.vehicle.events.first?.longitude == VehicleEventDto.validLongitude)
|
||
}
|
||
|
||
@Test("Update (history)")
|
||
func updateHistory() async throws {
|
||
|
||
let vehicle: VehicleDto = .normal
|
||
|
||
given(storageServiceMock)
|
||
.loadVehicle(number: .any)
|
||
.willReturn(.normal)
|
||
|
||
given(locationServiceMock)
|
||
.getRecentLocation()
|
||
.willReturn(.valid)
|
||
|
||
given(apiServiceMock)
|
||
.checkVehicle(by: .any, notes: .any, events: .any, force: .any)
|
||
.willReturn(vehicle)
|
||
|
||
given(locationServiceMock)
|
||
.resetLastEvent()
|
||
.willReturn()
|
||
|
||
given(storageServiceMock)
|
||
.updateVehicle(dto: .any, policy: .any)
|
||
.willReturn(true)
|
||
|
||
given(apiServiceMock)
|
||
.add(event: .any, to: .any)
|
||
.willReturn(vehicle.addEvent(.valid))
|
||
|
||
let result = try await vehicleService.updateHistory(number: vehicle.number)
|
||
|
||
verify(apiServiceMock)
|
||
.checkVehicle(by: .any, notes: .any, events: .any, force: .value(true))
|
||
.called(.once)
|
||
|
||
verify(locationServiceMock)
|
||
.getRecentLocation()
|
||
.called(.never)
|
||
|
||
verify(apiServiceMock)
|
||
.add(event: .any, to: .any)
|
||
.called(.never)
|
||
|
||
verify(storageServiceMock)
|
||
.updateVehicle(dto: .any, policy: .value(.always))
|
||
.called(.once)
|
||
|
||
#expect(result.vehicle.number == vehicle.number)
|
||
#expect(result.errors.count == 0)
|
||
#expect(result.vehicle.events.count == 0)
|
||
}
|
||
|
||
@Test("Update (search)")
|
||
func updateSearch() async throws {
|
||
|
||
let vehicle: VehicleDto = .normal
|
||
|
||
given(storageServiceMock)
|
||
.loadVehicle(number: .any)
|
||
.willReturn(.normal)
|
||
|
||
given(locationServiceMock)
|
||
.getRecentLocation()
|
||
.willReturn(.valid)
|
||
|
||
given(apiServiceMock)
|
||
.checkVehicle(by: .any, notes: .any, events: .any, force: .any)
|
||
.willReturn(vehicle)
|
||
|
||
given(locationServiceMock)
|
||
.resetLastEvent()
|
||
.willReturn()
|
||
|
||
given(storageServiceMock)
|
||
.updateVehicle(dto: .any, policy: .any)
|
||
.willReturn(true)
|
||
|
||
given(apiServiceMock)
|
||
.add(event: .any, to: .any)
|
||
.willReturn(vehicle.addEvent(.valid))
|
||
|
||
let result = try await vehicleService.updateSearch(number: vehicle.number)
|
||
|
||
verify(apiServiceMock)
|
||
.checkVehicle(by: .any, notes: .any, events: .any, force: .value(true))
|
||
.called(.once)
|
||
|
||
verify(locationServiceMock)
|
||
.getRecentLocation()
|
||
.called(.never)
|
||
|
||
verify(apiServiceMock)
|
||
.add(event: .any, to: .any)
|
||
.called(.never)
|
||
|
||
verify(storageServiceMock)
|
||
.updateVehicle(dto: .any, policy: .value(.ifExists))
|
||
.called(.once)
|
||
|
||
#expect(result.vehicle.number == vehicle.number)
|
||
#expect(result.errors.count == 0)
|
||
#expect(result.vehicle.events.count == 0)
|
||
}
|
||
}
|