// // AudioRecordsTests.swift // AutoCatTests // // Created by Selim Mustafaev on 05.04.2025. // Copyright © 2025 Selim Mustafaev. All rights reserved. // import Testing import Mockable import AutoCatCore @testable import AutoCat @MainActor struct AudioRecordsTests { let recordServiceMock = MockVehicleRecordServiceProtocol() let storageServiceMock = MockStorageServiceProtocol() let recordPlayerMock = MockRecordPlayerServiceProtocol() let viewModel: RecordsViewModel init() async throws { viewModel = .init( recordService: recordServiceMock, storageService: storageServiceMock, recordPlayer: recordPlayerMock ) } @Test("Initial load") func initialLoad() async throws { given(storageServiceMock) .loadRecords() .willReturn([AudioRecordDto.default]) given(recordServiceMock) .requestPermissionsIfNeeded() .willReturn() await viewModel.onAppear() verify(storageServiceMock) .loadRecords() .called(.once) verify(recordServiceMock) .requestPermissionsIfNeeded() .called(.once) #expect(viewModel.records.count == 1) #expect(viewModel.hud == nil) } @Test("Initial load error") func initialLoadError() async throws { given(storageServiceMock) .loadRecords() .willThrow(TestError.generic) given(recordServiceMock) .requestPermissionsIfNeeded() .willReturn() await viewModel.onAppear() verify(storageServiceMock) .loadRecords() .called(.once) verify(recordServiceMock) .requestPermissionsIfNeeded() .called(.once) #expect(viewModel.records.isEmpty) #expect(viewModel.hud == .error(TestError.generic)) } @Test("Start recording") func startRecording() async throws { given(recordServiceMock) .startRecording() .willReturn() await viewModel.startRecording() verify(recordServiceMock) .startRecording() .called(.once) #expect(viewModel.showRecordingAlert == true) #expect(viewModel.hud == nil) } @Test("Start recording error") func startRecordingError() async throws { given(recordServiceMock) .startRecording() .willThrow(TestError.generic) await viewModel.startRecording() verify(recordServiceMock) .startRecording() .called(.once) #expect(viewModel.showRecordingAlert == false) #expect(viewModel.hud == .error(TestError.generic)) } @Test("Stop recording") func stopRecording() async throws { given(recordServiceMock) .stopRecording() .willReturn(.default) given(storageServiceMock) .add(record: .any) .willReturn() given(storageServiceMock) .loadRecords() .willReturn([.default]) await viewModel.stopRecording() verify(recordServiceMock) .stopRecording() .called(.once) verify(storageServiceMock) .add(record: .any) .called(.once) verify(storageServiceMock) .loadRecords() .called(.once) #expect(viewModel.records.count == 1) #expect(viewModel.hud == nil) } @Test("Stop recording (recording error)") func stopRecordingError() async throws { given(recordServiceMock) .stopRecording() .willThrow(TestError.generic) await viewModel.stopRecording() verify(recordServiceMock) .stopRecording() .called(.once) verify(storageServiceMock) .add(record: .any) .called(.never) verify(storageServiceMock) .loadRecords() .called(.never) #expect(viewModel.records.isEmpty) #expect(viewModel.hud == .error(TestError.generic)) } @Test("Stop recording (add error)") func stopRecordingAddError() async throws { given(recordServiceMock) .stopRecording() .willReturn(.default) given(storageServiceMock) .add(record: .any) .willThrow(TestError.generic) await viewModel.stopRecording() verify(recordServiceMock) .stopRecording() .called(.once) verify(storageServiceMock) .add(record: .any) .called(.once) verify(storageServiceMock) .loadRecords() .called(.never) #expect(viewModel.records.isEmpty) #expect(viewModel.hud == .error(TestError.generic)) } @Test("Stop recording (load error)") func stopRecordingLoadError() async throws { given(recordServiceMock) .stopRecording() .willReturn(.default) given(storageServiceMock) .add(record: .any) .willReturn() given(storageServiceMock) .loadRecords() .willThrow(TestError.generic) await viewModel.stopRecording() verify(recordServiceMock) .stopRecording() .called(.once) verify(storageServiceMock) .add(record: .any) .called(.once) verify(storageServiceMock) .loadRecords() .called(.once) #expect(viewModel.records.isEmpty) #expect(viewModel.hud == .error(TestError.generic)) } @Test("Cancel recording") func cancelRecording() async throws { given(recordServiceMock) .cancelRecording() .willReturn() await viewModel.cancelRecording() verify(recordServiceMock) .cancelRecording() .called(.once) } @Test("Delete record") func deleteRecord() async throws { viewModel.records = [.default] given(storageServiceMock) .deleteRecord(id: .any) .willReturn() await viewModel.deleteRecord(id: AudioRecordDto.default.id) verify(storageServiceMock) .deleteRecord(id: .any) .called(.once) #expect(viewModel.records.isEmpty) #expect(viewModel.hud == nil) } @Test("Delete record (error)") func deleteRecordError() async throws { viewModel.records = [.default] given(storageServiceMock) .deleteRecord(id: .any) .willThrow(TestError.generic) await viewModel.deleteRecord(id: AudioRecordDto.default.id) verify(storageServiceMock) .deleteRecord(id: .any) .called(.once) #expect(viewModel.records.count == 1) #expect(viewModel.hud == .error(TestError.generic)) } @Test("Edit record") func editRecord() async throws { var editedRecord: AudioRecordDto = .default editedRecord.number = "123" viewModel.records = [.default] given(storageServiceMock) .updateRecord(id: .any, number: .any) .willReturn(editedRecord) await viewModel.editRecord(id: AudioRecordDto.default.id, number: "123") verify(storageServiceMock) .updateRecord(id: .any, number: .any) .called(.once) #expect(viewModel.records == [editedRecord]) #expect(viewModel.hud == nil) } @Test("Edit record (error)") func editRecordError() async throws { let record: AudioRecordDto = .default viewModel.records = [record] given(storageServiceMock) .updateRecord(id: .any, number: .any) .willThrow(TestError.generic) await viewModel.editRecord(id: AudioRecordDto.default.id, number: "123") verify(storageServiceMock) .updateRecord(id: .any, number: .any) .called(.once) #expect(viewModel.records == [record]) #expect(viewModel.hud == .error(TestError.generic)) } @Test("Show recognized text") func showRecognizedText() async throws { var record: AudioRecordDto = .default record.rawText = "Test text" viewModel.showRawRecognizedText(record) #expect(viewModel.hud == .message("Test text")) } }