From 62076a0cd876a71192749272fb1cf419f4f32c8b Mon Sep 17 00:00:00 2001 From: Gianni Carlo Date: Sat, 3 Jun 2023 23:27:00 -0500 Subject: [PATCH] Add sourcery config and mocks --- .sourcery.yml | 10 + .swiftlint.yml | 2 +- BookPlayer.xcodeproj/project.pbxproj | 28 +- .../Generated/AutoMockable.generated.swift | 1591 +++++++++++++++++ .../PlayerControlsViewModel.swift | 2 +- BookPlayer/Player/PlayerManager.swift | 12 +- BookPlayer/Player/SpeedService.swift | 1 + BookPlayer/Services/ActionParserService.swift | 2 +- .../PlayerSettingsViewController.swift | 2 +- .../ItemListCoordinatorTests.swift | 21 +- .../Coordinators/PlayerCoordinatorTests.swift | 12 +- .../ProfileCoordinatorTests.swift | 11 +- BookPlayerTests/ItemListViewModelTests.swift | 10 +- .../MiniPlayerViewModelTests.swift | 10 +- .../Mocks/EmptyLibraryServiceMock.swift | 239 --- .../Mocks/EmptyPlaybackServiceMock.swift | 40 - .../Mocks/EmptySpeedServiceMock.swift | 21 - .../Mocks/KeychainServiceMock.swift | 26 - BookPlayerTests/Mocks/PlayerManagerMock.swift | 77 - BookPlayerTests/Mocks/SyncServiceMock.swift | 70 - BookPlayerTests/PlayerManagerTests.swift | 8 +- .../Services/AccountServiceTests.swift | 6 +- .../Services/LibraryServiceTests.swift | 2 +- Shared/Services/KeychainService.swift | 1 + Shared/Services/LibraryService.swift | 1 + Shared/Services/PlaybackService.swift | 1 + Shared/Services/Sync/SyncService.swift | 1 + Templates/AutoMockable.stencil | 118 ++ 28 files changed, 1798 insertions(+), 527 deletions(-) create mode 100644 .sourcery.yml create mode 100644 BookPlayer/Generated/AutoMockable.generated.swift delete mode 100644 BookPlayerTests/Mocks/EmptyLibraryServiceMock.swift delete mode 100644 BookPlayerTests/Mocks/EmptyPlaybackServiceMock.swift delete mode 100644 BookPlayerTests/Mocks/EmptySpeedServiceMock.swift delete mode 100644 BookPlayerTests/Mocks/KeychainServiceMock.swift delete mode 100644 BookPlayerTests/Mocks/PlayerManagerMock.swift delete mode 100644 BookPlayerTests/Mocks/SyncServiceMock.swift create mode 100644 Templates/AutoMockable.stencil diff --git a/.sourcery.yml b/.sourcery.yml new file mode 100644 index 000000000..88ea4a86c --- /dev/null +++ b/.sourcery.yml @@ -0,0 +1,10 @@ +sources: + - ./Shared + - ./BookPlayerKit + - ./BookPlayer +templates: + - Templates +output: BookPlayer/Generated +args: + autoMockableImports: ["Combine", "BookPlayerKit"] + autoMockableTestableImports: ["BookPlayer"] diff --git a/.swiftlint.yml b/.swiftlint.yml index e73429383..5022c867b 100644 --- a/.swiftlint.yml +++ b/.swiftlint.yml @@ -1,5 +1,5 @@ excluded: - - Carthage + - BookPlayer/Generated/AutoMockable.generated.swift cyclomatic_complexity: ignores_case_statements: true # line_length: 120 diff --git a/BookPlayer.xcodeproj/project.pbxproj b/BookPlayer.xcodeproj/project.pbxproj index 7b0f50cd9..64e2b89e5 100644 --- a/BookPlayer.xcodeproj/project.pbxproj +++ b/BookPlayer.xcodeproj/project.pbxproj @@ -304,7 +304,6 @@ 62793611272CBE910097837D /* ImportFileItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4163E3102148606600072AA2 /* ImportFileItem.swift */; }; 6279361F272D0D110097837D /* MainCoordinatorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6279361E272D0D110097837D /* MainCoordinatorTests.swift */; }; 62AAE2252749283F001EB9FF /* MiniPlayerViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62AAE2242749283F001EB9FF /* MiniPlayerViewModelTests.swift */; }; - 62AAE22727492896001EB9FF /* PlayerManagerMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62AAE22627492896001EB9FF /* PlayerManagerMock.swift */; }; 62AAE22D274AA6DE001EB9FF /* LibraryService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62AAE22B274AA3EB001EB9FF /* LibraryService.swift */; }; 62AAE22E274AA6DE001EB9FF /* LibraryService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62AAE22B274AA3EB001EB9FF /* LibraryService.swift */; }; 62AAE231274ABB5D001EB9FF /* LibraryServiceTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62AAE230274ABB5D001EB9FF /* LibraryServiceTests.swift */; }; @@ -401,6 +400,7 @@ 9F7B647A2804773D00895ECC /* ThemesViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F7B64792804773D00895ECC /* ThemesViewModel.swift */; }; 9F7B647C2804798800895ECC /* IconsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F7B647B2804798800895ECC /* IconsViewModel.swift */; }; 9F7B647E2804916900895ECC /* PlusViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F7B647D2804916900895ECC /* PlusViewModel.swift */; }; + 9F7C47532A2C15D300F9A500 /* AutoMockable.generated.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F7C47522A2C15D300F9A500 /* AutoMockable.generated.swift */; }; 9F82DF6927DE93A2001B0EA8 /* SkipIntervalView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F82DF6827DE93A2001B0EA8 /* SkipIntervalView.swift */; }; 9F82DF6B27DE9792001B0EA8 /* NowPlayingMediaControlsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F82DF6A27DE9792001B0EA8 /* NowPlayingMediaControlsView.swift */; }; 9F82DF6D27DE985A001B0EA8 /* NowPlayingPlaybackControlsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F82DF6C27DE985A001B0EA8 /* NowPlayingPlaybackControlsView.swift */; }; @@ -437,9 +437,6 @@ 9FB20EB729A423410021663B /* InterfaceUpdater.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FB20EB629A423410021663B /* InterfaceUpdater.swift */; }; 9FB20EB929A479FB0021663B /* BPAlertContent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FB20EB829A479FB0021663B /* BPAlertContent.swift */; }; 9FB7C48D2835A2C1003B917E /* PlayerManagerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FB7C48C2835A2C1003B917E /* PlayerManagerTests.swift */; }; - 9FB7C48F2835A4C9003B917E /* EmptyLibraryServiceMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FB7C48E2835A4C9003B917E /* EmptyLibraryServiceMock.swift */; }; - 9FB7C4912835A5A3003B917E /* EmptyPlaybackServiceMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FB7C4902835A5A3003B917E /* EmptyPlaybackServiceMock.swift */; }; - 9FB7C4932835A617003B917E /* EmptySpeedServiceMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FB7C4922835A617003B917E /* EmptySpeedServiceMock.swift */; }; 9FBDBC792879409600D315A2 /* SyncableItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FBDBC782879409600D315A2 /* SyncableItem.swift */; }; 9FBDBC7D287940D900D315A2 /* ContentsResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FBDBC7C287940D900D315A2 /* ContentsResponse.swift */; }; 9FBDBC7E287940D900D315A2 /* ContentsResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FBDBC7C287940D900D315A2 /* ContentsResponse.swift */; }; @@ -465,7 +462,6 @@ 9FC1E45F2814F66F00522FA8 /* AccountAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FC1E45E2814F66F00522FA8 /* AccountAPI.swift */; }; 9FC1E4602814F66F00522FA8 /* AccountAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FC1E45E2814F66F00522FA8 /* AccountAPI.swift */; }; 9FC1E4632814F80000522FA8 /* AccountServiceMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FC1E4622814F80000522FA8 /* AccountServiceMock.swift */; }; - 9FC1E465281507BD00522FA8 /* SyncServiceMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FC1E464281507BD00522FA8 /* SyncServiceMock.swift */; }; 9FC1E4672815091A00522FA8 /* AccountServiceTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FC1E4662815091A00522FA8 /* AccountServiceTests.swift */; }; 9FC1E46928150ECC00522FA8 /* NetworkClientMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FC1E46828150ECC00522FA8 /* NetworkClientMock.swift */; }; 9FC1E46C2815A8CA00522FA8 /* LibraryAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FC1E46A2815A8A800522FA8 /* LibraryAPI.swift */; }; @@ -473,7 +469,6 @@ 9FC1E4772815F97E00522FA8 /* KeychainServiceTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FC1E4762815F97E00522FA8 /* KeychainServiceTests.swift */; }; 9FC1E4782816001400522FA8 /* KeychainService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FC1E4742815C6A300522FA8 /* KeychainService.swift */; }; 9FC1E4792816001400522FA8 /* KeychainService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FC1E4742815C6A300522FA8 /* KeychainService.swift */; }; - 9FC1E47B281600D500522FA8 /* KeychainServiceMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FC1E47A281600D500522FA8 /* KeychainServiceMock.swift */; }; 9FCC228C2A172669003DD895 /* MappingModel_v8_to_v9.xcmappingmodel in Sources */ = {isa = PBXBuildFile; fileRef = 9FCC228B2A172669003DD895 /* MappingModel_v8_to_v9.xcmappingmodel */; }; 9FCC228D2A172669003DD895 /* MappingModel_v8_to_v9.xcmappingmodel in Sources */ = {isa = PBXBuildFile; fileRef = 9FCC228B2A172669003DD895 /* MappingModel_v8_to_v9.xcmappingmodel */; }; 9FCC228E2A172669003DD895 /* MappingModel_v8_to_v9.xcmappingmodel in Sources */ = {isa = PBXBuildFile; fileRef = 9FCC228B2A172669003DD895 /* MappingModel_v8_to_v9.xcmappingmodel */; }; @@ -967,7 +962,6 @@ 624EB9832755D8E700D462A8 /* Audiobook Player 8.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "Audiobook Player 8.xcdatamodel"; sourceTree = ""; }; 6279361E272D0D110097837D /* MainCoordinatorTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainCoordinatorTests.swift; sourceTree = ""; }; 62AAE2242749283F001EB9FF /* MiniPlayerViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MiniPlayerViewModelTests.swift; sourceTree = ""; }; - 62AAE22627492896001EB9FF /* PlayerManagerMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlayerManagerMock.swift; sourceTree = ""; }; 62AAE22B274AA3EB001EB9FF /* LibraryService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LibraryService.swift; sourceTree = ""; }; 62AAE230274ABB5D001EB9FF /* LibraryServiceTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LibraryServiceTests.swift; sourceTree = ""; }; 62CADB8D2724E41800A4A98F /* Audiobook Player 7.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "Audiobook Player 7.xcdatamodel"; sourceTree = ""; }; @@ -1054,6 +1048,7 @@ 9F7B64792804773D00895ECC /* ThemesViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThemesViewModel.swift; sourceTree = ""; }; 9F7B647B2804798800895ECC /* IconsViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IconsViewModel.swift; sourceTree = ""; }; 9F7B647D2804916900895ECC /* PlusViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlusViewModel.swift; sourceTree = ""; }; + 9F7C47522A2C15D300F9A500 /* AutoMockable.generated.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = AutoMockable.generated.swift; path = BookPlayer/Generated/AutoMockable.generated.swift; sourceTree = SOURCE_ROOT; }; 9F82DF6827DE93A2001B0EA8 /* SkipIntervalView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SkipIntervalView.swift; sourceTree = ""; }; 9F82DF6A27DE9792001B0EA8 /* NowPlayingMediaControlsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NowPlayingMediaControlsView.swift; sourceTree = ""; }; 9F82DF6C27DE985A001B0EA8 /* NowPlayingPlaybackControlsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NowPlayingPlaybackControlsView.swift; sourceTree = ""; }; @@ -1082,9 +1077,6 @@ 9FB20EB629A423410021663B /* InterfaceUpdater.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InterfaceUpdater.swift; sourceTree = ""; }; 9FB20EB829A479FB0021663B /* BPAlertContent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BPAlertContent.swift; sourceTree = ""; }; 9FB7C48C2835A2C1003B917E /* PlayerManagerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlayerManagerTests.swift; sourceTree = ""; }; - 9FB7C48E2835A4C9003B917E /* EmptyLibraryServiceMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmptyLibraryServiceMock.swift; sourceTree = ""; }; - 9FB7C4902835A5A3003B917E /* EmptyPlaybackServiceMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmptyPlaybackServiceMock.swift; sourceTree = ""; }; - 9FB7C4922835A617003B917E /* EmptySpeedServiceMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmptySpeedServiceMock.swift; sourceTree = ""; }; 9FBDBC782879409600D315A2 /* SyncableItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SyncableItem.swift; sourceTree = ""; }; 9FBDBC7C287940D900D315A2 /* ContentsResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentsResponse.swift; sourceTree = ""; }; 9FBDBC7F2879C6C900D315A2 /* UploadItemResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UploadItemResponse.swift; sourceTree = ""; }; @@ -1102,13 +1094,11 @@ 9FC1E45B2814E6A500522FA8 /* NetworkProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkProvider.swift; sourceTree = ""; }; 9FC1E45E2814F66F00522FA8 /* AccountAPI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountAPI.swift; sourceTree = ""; }; 9FC1E4622814F80000522FA8 /* AccountServiceMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountServiceMock.swift; sourceTree = ""; }; - 9FC1E464281507BD00522FA8 /* SyncServiceMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SyncServiceMock.swift; sourceTree = ""; }; 9FC1E4662815091A00522FA8 /* AccountServiceTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountServiceTests.swift; sourceTree = ""; }; 9FC1E46828150ECC00522FA8 /* NetworkClientMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkClientMock.swift; sourceTree = ""; }; 9FC1E46A2815A8A800522FA8 /* LibraryAPI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LibraryAPI.swift; sourceTree = ""; }; 9FC1E4742815C6A300522FA8 /* KeychainService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeychainService.swift; sourceTree = ""; }; 9FC1E4762815F97E00522FA8 /* KeychainServiceTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeychainServiceTests.swift; sourceTree = ""; }; - 9FC1E47A281600D500522FA8 /* KeychainServiceMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeychainServiceMock.swift; sourceTree = ""; }; 9FCC228B2A172669003DD895 /* MappingModel_v8_to_v9.xcmappingmodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcmappingmodel; path = MappingModel_v8_to_v9.xcmappingmodel; sourceTree = ""; }; 9FD8D95729DC53750074C2D8 /* CoreServices.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CoreServices.swift; sourceTree = ""; }; 9FDDD2D7289B64440020C428 /* SyncStatus.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SyncStatus.swift; sourceTree = ""; }; @@ -1832,14 +1822,9 @@ 62AAE22827492D6E001EB9FF /* Mocks */ = { isa = PBXGroup; children = ( - 62AAE22627492896001EB9FF /* PlayerManagerMock.swift */, + 9F7C47522A2C15D300F9A500 /* AutoMockable.generated.swift */, 9FC1E4622814F80000522FA8 /* AccountServiceMock.swift */, - 9FC1E464281507BD00522FA8 /* SyncServiceMock.swift */, 9FC1E46828150ECC00522FA8 /* NetworkClientMock.swift */, - 9FC1E47A281600D500522FA8 /* KeychainServiceMock.swift */, - 9FB7C48E2835A4C9003B917E /* EmptyLibraryServiceMock.swift */, - 9FB7C4902835A5A3003B917E /* EmptyPlaybackServiceMock.swift */, - 9FB7C4922835A617003B917E /* EmptySpeedServiceMock.swift */, ); path = Mocks; sourceTree = ""; @@ -3178,17 +3163,15 @@ 69343D36213A07B4000C425E /* VoiceOverServiceTest.swift in Sources */, 9F646006283AD6B700710D3C /* PlayerSettingsViewModelTests.swift in Sources */, 62AAE2252749283F001EB9FF /* MiniPlayerViewModelTests.swift in Sources */, - 9FB7C48F2835A4C9003B917E /* EmptyLibraryServiceMock.swift in Sources */, 41C2340C27324AB7006BC7B8 /* ItemListViewModelTests.swift in Sources */, 41A1B13F226FEF9300EA0400 /* DataManagerTests.swift in Sources */, 9FB7C48D2835A2C1003B917E /* PlayerManagerTests.swift in Sources */, 4137BBD4272DF540009ED9FE /* PlayerCoordinatorTests.swift in Sources */, 416A9D4B2743D51E00463621 /* StorageViewModelTests.swift in Sources */, 4137BBD2272DED79009ED9FE /* ItemListCoordinatorTests.swift in Sources */, - 9FC1E47B281600D500522FA8 /* KeychainServiceMock.swift in Sources */, + 9F7C47532A2C15D300F9A500 /* AutoMockable.generated.swift in Sources */, 62AAE231274ABB5D001EB9FF /* LibraryServiceTests.swift in Sources */, 6906A553217211C600A9E0B2 /* StubFactory.swift in Sources */, - 62AAE22727492896001EB9FF /* PlayerManagerMock.swift in Sources */, 6906A55021720FDF00A9E0B2 /* BookSortServiceTest.swift in Sources */, 6279361F272D0D110097837D /* MainCoordinatorTests.swift in Sources */, 9FBDDBA427DD1A00005FB447 /* ProfileCoordinatorTests.swift in Sources */, @@ -3196,9 +3179,6 @@ 9FC1E4672815091A00522FA8 /* AccountServiceTests.swift in Sources */, 9FC1E4772815F97E00522FA8 /* KeychainServiceTests.swift in Sources */, 4137BBD0272DEBEC009ED9FE /* LoadingCoordinatorTests.swift in Sources */, - 9FC1E465281507BD00522FA8 /* SyncServiceMock.swift in Sources */, - 9FB7C4912835A5A3003B917E /* EmptyPlaybackServiceMock.swift in Sources */, - 9FB7C4932835A617003B917E /* EmptySpeedServiceMock.swift in Sources */, 41A1B13E226FEF8000EA0400 /* DataTestUtils.swift in Sources */, 9FC1E46928150ECC00522FA8 /* NetworkClientMock.swift in Sources */, 9F8A9A5E27AC3F8C0093AA1C /* PlayableItemTests.swift in Sources */, diff --git a/BookPlayer/Generated/AutoMockable.generated.swift b/BookPlayer/Generated/AutoMockable.generated.swift new file mode 100644 index 000000000..96c3c7383 --- /dev/null +++ b/BookPlayer/Generated/AutoMockable.generated.swift @@ -0,0 +1,1591 @@ +// Generated using Sourcery 2.0.2 — https://github.com/krzysztofzablocki/Sourcery +// DO NOT EDIT + +import Foundation +#if os(iOS) || os(tvOS) || os(watchOS) +import UIKit +import AVFoundation +#elseif os(OSX) +import AppKit +#endif + +import Combine +import BookPlayerKit +@testable import BookPlayer +class KeychainServiceProtocolMock: KeychainServiceProtocol { + //MARK: - setAccessToken + + var setAccessTokenThrowableError: Error? + var setAccessTokenCallsCount = 0 + var setAccessTokenCalled: Bool { + return setAccessTokenCallsCount > 0 + } + var setAccessTokenReceivedToken: String? + var setAccessTokenReceivedInvocations: [String] = [] + var setAccessTokenClosure: ((String) throws -> Void)? + func setAccessToken(_ token: String) throws { + if let error = setAccessTokenThrowableError { + throw error + } + setAccessTokenCallsCount += 1 + setAccessTokenReceivedToken = token + setAccessTokenReceivedInvocations.append(token) + try setAccessTokenClosure?(token) + } + //MARK: - getAccessToken + + var getAccessTokenThrowableError: Error? + var getAccessTokenCallsCount = 0 + var getAccessTokenCalled: Bool { + return getAccessTokenCallsCount > 0 + } + var getAccessTokenReturnValue: String? + var getAccessTokenClosure: (() throws -> String?)? + func getAccessToken() throws -> String? { + if let error = getAccessTokenThrowableError { + throw error + } + getAccessTokenCallsCount += 1 + if let getAccessTokenClosure = getAccessTokenClosure { + return try getAccessTokenClosure() + } else { + return getAccessTokenReturnValue + } + } + //MARK: - removeAccessToken + + var removeAccessTokenThrowableError: Error? + var removeAccessTokenCallsCount = 0 + var removeAccessTokenCalled: Bool { + return removeAccessTokenCallsCount > 0 + } + var removeAccessTokenClosure: (() throws -> Void)? + func removeAccessToken() throws { + if let error = removeAccessTokenThrowableError { + throw error + } + removeAccessTokenCallsCount += 1 + try removeAccessTokenClosure?() + } +} +class LibraryServiceProtocolMock: LibraryServiceProtocol { + var metadataUpdatePublisher: AnyPublisher<[String: Any], Never> { + get { return underlyingMetadataUpdatePublisher } + set(value) { underlyingMetadataUpdatePublisher = value } + } + var underlyingMetadataUpdatePublisher: AnyPublisher<[String: Any], Never>! + //MARK: - getLibrary + + var getLibraryCallsCount = 0 + var getLibraryCalled: Bool { + return getLibraryCallsCount > 0 + } + var getLibraryReturnValue: Library! + var getLibraryClosure: (() -> Library)? + func getLibrary() -> Library { + getLibraryCallsCount += 1 + if let getLibraryClosure = getLibraryClosure { + return getLibraryClosure() + } else { + return getLibraryReturnValue + } + } + //MARK: - getLibraryReference + + var getLibraryReferenceCallsCount = 0 + var getLibraryReferenceCalled: Bool { + return getLibraryReferenceCallsCount > 0 + } + var getLibraryReferenceReturnValue: Library! + var getLibraryReferenceClosure: (() -> Library)? + func getLibraryReference() -> Library { + getLibraryReferenceCallsCount += 1 + if let getLibraryReferenceClosure = getLibraryReferenceClosure { + return getLibraryReferenceClosure() + } else { + return getLibraryReferenceReturnValue + } + } + //MARK: - getLibraryLastItem + + var getLibraryLastItemCallsCount = 0 + var getLibraryLastItemCalled: Bool { + return getLibraryLastItemCallsCount > 0 + } + var getLibraryLastItemReturnValue: SimpleLibraryItem? + var getLibraryLastItemClosure: (() -> SimpleLibraryItem?)? + func getLibraryLastItem() -> SimpleLibraryItem? { + getLibraryLastItemCallsCount += 1 + if let getLibraryLastItemClosure = getLibraryLastItemClosure { + return getLibraryLastItemClosure() + } else { + return getLibraryLastItemReturnValue + } + } + //MARK: - getLibraryCurrentTheme + + var getLibraryCurrentThemeCallsCount = 0 + var getLibraryCurrentThemeCalled: Bool { + return getLibraryCurrentThemeCallsCount > 0 + } + var getLibraryCurrentThemeReturnValue: SimpleTheme? + var getLibraryCurrentThemeClosure: (() -> SimpleTheme?)? + func getLibraryCurrentTheme() -> SimpleTheme? { + getLibraryCurrentThemeCallsCount += 1 + if let getLibraryCurrentThemeClosure = getLibraryCurrentThemeClosure { + return getLibraryCurrentThemeClosure() + } else { + return getLibraryCurrentThemeReturnValue + } + } + //MARK: - setLibraryTheme + + var setLibraryThemeWithCallsCount = 0 + var setLibraryThemeWithCalled: Bool { + return setLibraryThemeWithCallsCount > 0 + } + var setLibraryThemeWithReceivedSimpleTheme: SimpleTheme? + var setLibraryThemeWithReceivedInvocations: [SimpleTheme] = [] + var setLibraryThemeWithClosure: ((SimpleTheme) -> Void)? + func setLibraryTheme(with simpleTheme: SimpleTheme) { + setLibraryThemeWithCallsCount += 1 + setLibraryThemeWithReceivedSimpleTheme = simpleTheme + setLibraryThemeWithReceivedInvocations.append(simpleTheme) + setLibraryThemeWithClosure?(simpleTheme) + } + //MARK: - setLibraryLastBook + + var setLibraryLastBookWithCallsCount = 0 + var setLibraryLastBookWithCalled: Bool { + return setLibraryLastBookWithCallsCount > 0 + } + var setLibraryLastBookWithReceivedRelativePath: String? + var setLibraryLastBookWithReceivedInvocations: [String?] = [] + var setLibraryLastBookWithClosure: ((String?) -> Void)? + func setLibraryLastBook(with relativePath: String?) { + setLibraryLastBookWithCallsCount += 1 + setLibraryLastBookWithReceivedRelativePath = relativePath + setLibraryLastBookWithReceivedInvocations.append(relativePath) + setLibraryLastBookWithClosure?(relativePath) + } + //MARK: - insertItems + + var insertItemsFromCallsCount = 0 + var insertItemsFromCalled: Bool { + return insertItemsFromCallsCount > 0 + } + var insertItemsFromReceivedFiles: [URL]? + var insertItemsFromReceivedInvocations: [[URL]] = [] + var insertItemsFromReturnValue: [SimpleLibraryItem]! + var insertItemsFromClosure: (([URL]) -> [SimpleLibraryItem])? + func insertItems(from files: [URL]) -> [SimpleLibraryItem] { + insertItemsFromCallsCount += 1 + insertItemsFromReceivedFiles = files + insertItemsFromReceivedInvocations.append(files) + if let insertItemsFromClosure = insertItemsFromClosure { + return insertItemsFromClosure(files) + } else { + return insertItemsFromReturnValue + } + } + //MARK: - moveItems + + var moveItemsInsideThrowableError: Error? + var moveItemsInsideCallsCount = 0 + var moveItemsInsideCalled: Bool { + return moveItemsInsideCallsCount > 0 + } + var moveItemsInsideReceivedArguments: (items: [String], relativePath: String?)? + var moveItemsInsideReceivedInvocations: [(items: [String], relativePath: String?)] = [] + var moveItemsInsideClosure: (([String], String?) throws -> Void)? + func moveItems(_ items: [String], inside relativePath: String?) throws { + if let error = moveItemsInsideThrowableError { + throw error + } + moveItemsInsideCallsCount += 1 + moveItemsInsideReceivedArguments = (items: items, relativePath: relativePath) + moveItemsInsideReceivedInvocations.append((items: items, relativePath: relativePath)) + try moveItemsInsideClosure?(items, relativePath) + } + //MARK: - delete + + var deleteModeThrowableError: Error? + var deleteModeCallsCount = 0 + var deleteModeCalled: Bool { + return deleteModeCallsCount > 0 + } + var deleteModeReceivedArguments: (items: [SimpleLibraryItem], mode: DeleteMode)? + var deleteModeReceivedInvocations: [(items: [SimpleLibraryItem], mode: DeleteMode)] = [] + var deleteModeClosure: (([SimpleLibraryItem], DeleteMode) throws -> Void)? + func delete(_ items: [SimpleLibraryItem], mode: DeleteMode) throws { + if let error = deleteModeThrowableError { + throw error + } + deleteModeCallsCount += 1 + deleteModeReceivedArguments = (items: items, mode: mode) + deleteModeReceivedInvocations.append((items: items, mode: mode)) + try deleteModeClosure?(items, mode) + } + //MARK: - fetchContents + + var fetchContentsAtLimitOffsetCallsCount = 0 + var fetchContentsAtLimitOffsetCalled: Bool { + return fetchContentsAtLimitOffsetCallsCount > 0 + } + var fetchContentsAtLimitOffsetReceivedArguments: (relativePath: String?, limit: Int?, offset: Int?)? + var fetchContentsAtLimitOffsetReceivedInvocations: [(relativePath: String?, limit: Int?, offset: Int?)] = [] + var fetchContentsAtLimitOffsetReturnValue: [SimpleLibraryItem]? + var fetchContentsAtLimitOffsetClosure: ((String?, Int?, Int?) -> [SimpleLibraryItem]?)? + func fetchContents(at relativePath: String?, limit: Int?, offset: Int?) -> [SimpleLibraryItem]? { + fetchContentsAtLimitOffsetCallsCount += 1 + fetchContentsAtLimitOffsetReceivedArguments = (relativePath: relativePath, limit: limit, offset: offset) + fetchContentsAtLimitOffsetReceivedInvocations.append((relativePath: relativePath, limit: limit, offset: offset)) + if let fetchContentsAtLimitOffsetClosure = fetchContentsAtLimitOffsetClosure { + return fetchContentsAtLimitOffsetClosure(relativePath, limit, offset) + } else { + return fetchContentsAtLimitOffsetReturnValue + } + } + //MARK: - getMaxItemsCount + + var getMaxItemsCountAtCallsCount = 0 + var getMaxItemsCountAtCalled: Bool { + return getMaxItemsCountAtCallsCount > 0 + } + var getMaxItemsCountAtReceivedRelativePath: String? + var getMaxItemsCountAtReceivedInvocations: [String?] = [] + var getMaxItemsCountAtReturnValue: Int! + var getMaxItemsCountAtClosure: ((String?) -> Int)? + func getMaxItemsCount(at relativePath: String?) -> Int { + getMaxItemsCountAtCallsCount += 1 + getMaxItemsCountAtReceivedRelativePath = relativePath + getMaxItemsCountAtReceivedInvocations.append(relativePath) + if let getMaxItemsCountAtClosure = getMaxItemsCountAtClosure { + return getMaxItemsCountAtClosure(relativePath) + } else { + return getMaxItemsCountAtReturnValue + } + } + //MARK: - getLastPlayedItems + + var getLastPlayedItemsLimitCallsCount = 0 + var getLastPlayedItemsLimitCalled: Bool { + return getLastPlayedItemsLimitCallsCount > 0 + } + var getLastPlayedItemsLimitReceivedLimit: Int? + var getLastPlayedItemsLimitReceivedInvocations: [Int?] = [] + var getLastPlayedItemsLimitReturnValue: [SimpleLibraryItem]? + var getLastPlayedItemsLimitClosure: ((Int?) -> [SimpleLibraryItem]?)? + func getLastPlayedItems(limit: Int?) -> [SimpleLibraryItem]? { + getLastPlayedItemsLimitCallsCount += 1 + getLastPlayedItemsLimitReceivedLimit = limit + getLastPlayedItemsLimitReceivedInvocations.append(limit) + if let getLastPlayedItemsLimitClosure = getLastPlayedItemsLimitClosure { + return getLastPlayedItemsLimitClosure(limit) + } else { + return getLastPlayedItemsLimitReturnValue + } + } + //MARK: - findBooks + + var findBooksContainingCallsCount = 0 + var findBooksContainingCalled: Bool { + return findBooksContainingCallsCount > 0 + } + var findBooksContainingReceivedFileURL: URL? + var findBooksContainingReceivedInvocations: [URL] = [] + var findBooksContainingReturnValue: [Book]? + var findBooksContainingClosure: ((URL) -> [Book]?)? + func findBooks(containing fileURL: URL) -> [Book]? { + findBooksContainingCallsCount += 1 + findBooksContainingReceivedFileURL = fileURL + findBooksContainingReceivedInvocations.append(fileURL) + if let findBooksContainingClosure = findBooksContainingClosure { + return findBooksContainingClosure(fileURL) + } else { + return findBooksContainingReturnValue + } + } + //MARK: - getSimpleItem + + var getSimpleItemWithCallsCount = 0 + var getSimpleItemWithCalled: Bool { + return getSimpleItemWithCallsCount > 0 + } + var getSimpleItemWithReceivedRelativePath: String? + var getSimpleItemWithReceivedInvocations: [String] = [] + var getSimpleItemWithReturnValue: SimpleLibraryItem? + var getSimpleItemWithClosure: ((String) -> SimpleLibraryItem?)? + func getSimpleItem(with relativePath: String) -> SimpleLibraryItem? { + getSimpleItemWithCallsCount += 1 + getSimpleItemWithReceivedRelativePath = relativePath + getSimpleItemWithReceivedInvocations.append(relativePath) + if let getSimpleItemWithClosure = getSimpleItemWithClosure { + return getSimpleItemWithClosure(relativePath) + } else { + return getSimpleItemWithReturnValue + } + } + //MARK: - getItems + + var getItemsNotInParentFolderCallsCount = 0 + var getItemsNotInParentFolderCalled: Bool { + return getItemsNotInParentFolderCallsCount > 0 + } + var getItemsNotInParentFolderReceivedArguments: (relativePaths: [String], parentFolder: String?)? + var getItemsNotInParentFolderReceivedInvocations: [(relativePaths: [String], parentFolder: String?)] = [] + var getItemsNotInParentFolderReturnValue: [SimpleLibraryItem]? + var getItemsNotInParentFolderClosure: (([String], String?) -> [SimpleLibraryItem]?)? + func getItems(notIn relativePaths: [String], parentFolder: String?) -> [SimpleLibraryItem]? { + getItemsNotInParentFolderCallsCount += 1 + getItemsNotInParentFolderReceivedArguments = (relativePaths: relativePaths, parentFolder: parentFolder) + getItemsNotInParentFolderReceivedInvocations.append((relativePaths: relativePaths, parentFolder: parentFolder)) + if let getItemsNotInParentFolderClosure = getItemsNotInParentFolderClosure { + return getItemsNotInParentFolderClosure(relativePaths, parentFolder) + } else { + return getItemsNotInParentFolderReturnValue + } + } + //MARK: - getItemProperty + + var getItemPropertyRelativePathCallsCount = 0 + var getItemPropertyRelativePathCalled: Bool { + return getItemPropertyRelativePathCallsCount > 0 + } + var getItemPropertyRelativePathReceivedArguments: (property: String, relativePath: String)? + var getItemPropertyRelativePathReceivedInvocations: [(property: String, relativePath: String)] = [] + var getItemPropertyRelativePathReturnValue: Any? + var getItemPropertyRelativePathClosure: ((String, String) -> Any?)? + func getItemProperty(_ property: String, relativePath: String) -> Any? { + getItemPropertyRelativePathCallsCount += 1 + getItemPropertyRelativePathReceivedArguments = (property: property, relativePath: relativePath) + getItemPropertyRelativePathReceivedInvocations.append((property: property, relativePath: relativePath)) + if let getItemPropertyRelativePathClosure = getItemPropertyRelativePathClosure { + return getItemPropertyRelativePathClosure(property, relativePath) + } else { + return getItemPropertyRelativePathReturnValue + } + } + //MARK: - filterContents + + var filterContentsAtQueryScopeLimitOffsetCallsCount = 0 + var filterContentsAtQueryScopeLimitOffsetCalled: Bool { + return filterContentsAtQueryScopeLimitOffsetCallsCount > 0 + } + var filterContentsAtQueryScopeLimitOffsetReceivedArguments: (relativePath: String?, query: String?, scope: SimpleItemType, limit: Int?, offset: Int?)? + var filterContentsAtQueryScopeLimitOffsetReceivedInvocations: [(relativePath: String?, query: String?, scope: SimpleItemType, limit: Int?, offset: Int?)] = [] + var filterContentsAtQueryScopeLimitOffsetReturnValue: [SimpleLibraryItem]? + var filterContentsAtQueryScopeLimitOffsetClosure: ((String?, String?, SimpleItemType, Int?, Int?) -> [SimpleLibraryItem]?)? + func filterContents(at relativePath: String?, query: String?, scope: SimpleItemType, limit: Int?, offset: Int?) -> [SimpleLibraryItem]? { + filterContentsAtQueryScopeLimitOffsetCallsCount += 1 + filterContentsAtQueryScopeLimitOffsetReceivedArguments = (relativePath: relativePath, query: query, scope: scope, limit: limit, offset: offset) + filterContentsAtQueryScopeLimitOffsetReceivedInvocations.append((relativePath: relativePath, query: query, scope: scope, limit: limit, offset: offset)) + if let filterContentsAtQueryScopeLimitOffsetClosure = filterContentsAtQueryScopeLimitOffsetClosure { + return filterContentsAtQueryScopeLimitOffsetClosure(relativePath, query, scope, limit, offset) + } else { + return filterContentsAtQueryScopeLimitOffsetReturnValue + } + } + //MARK: - findFirstItem + + var findFirstItemInIsUnfinishedCallsCount = 0 + var findFirstItemInIsUnfinishedCalled: Bool { + return findFirstItemInIsUnfinishedCallsCount > 0 + } + var findFirstItemInIsUnfinishedReceivedArguments: (parentFolder: String?, isUnfinished: Bool?)? + var findFirstItemInIsUnfinishedReceivedInvocations: [(parentFolder: String?, isUnfinished: Bool?)] = [] + var findFirstItemInIsUnfinishedReturnValue: SimpleLibraryItem? + var findFirstItemInIsUnfinishedClosure: ((String?, Bool?) -> SimpleLibraryItem?)? + func findFirstItem(in parentFolder: String?, isUnfinished: Bool?) -> SimpleLibraryItem? { + findFirstItemInIsUnfinishedCallsCount += 1 + findFirstItemInIsUnfinishedReceivedArguments = (parentFolder: parentFolder, isUnfinished: isUnfinished) + findFirstItemInIsUnfinishedReceivedInvocations.append((parentFolder: parentFolder, isUnfinished: isUnfinished)) + if let findFirstItemInIsUnfinishedClosure = findFirstItemInIsUnfinishedClosure { + return findFirstItemInIsUnfinishedClosure(parentFolder, isUnfinished) + } else { + return findFirstItemInIsUnfinishedReturnValue + } + } + //MARK: - findFirstItem + + var findFirstItemInBeforeRankCallsCount = 0 + var findFirstItemInBeforeRankCalled: Bool { + return findFirstItemInBeforeRankCallsCount > 0 + } + var findFirstItemInBeforeRankReceivedArguments: (parentFolder: String?, beforeRank: Int16?)? + var findFirstItemInBeforeRankReceivedInvocations: [(parentFolder: String?, beforeRank: Int16?)] = [] + var findFirstItemInBeforeRankReturnValue: SimpleLibraryItem? + var findFirstItemInBeforeRankClosure: ((String?, Int16?) -> SimpleLibraryItem?)? + func findFirstItem(in parentFolder: String?, beforeRank: Int16?) -> SimpleLibraryItem? { + findFirstItemInBeforeRankCallsCount += 1 + findFirstItemInBeforeRankReceivedArguments = (parentFolder: parentFolder, beforeRank: beforeRank) + findFirstItemInBeforeRankReceivedInvocations.append((parentFolder: parentFolder, beforeRank: beforeRank)) + if let findFirstItemInBeforeRankClosure = findFirstItemInBeforeRankClosure { + return findFirstItemInBeforeRankClosure(parentFolder, beforeRank) + } else { + return findFirstItemInBeforeRankReturnValue + } + } + //MARK: - findFirstItem + + var findFirstItemInAfterRankIsUnfinishedCallsCount = 0 + var findFirstItemInAfterRankIsUnfinishedCalled: Bool { + return findFirstItemInAfterRankIsUnfinishedCallsCount > 0 + } + var findFirstItemInAfterRankIsUnfinishedReceivedArguments: (parentFolder: String?, afterRank: Int16?, isUnfinished: Bool?)? + var findFirstItemInAfterRankIsUnfinishedReceivedInvocations: [(parentFolder: String?, afterRank: Int16?, isUnfinished: Bool?)] = [] + var findFirstItemInAfterRankIsUnfinishedReturnValue: SimpleLibraryItem? + var findFirstItemInAfterRankIsUnfinishedClosure: ((String?, Int16?, Bool?) -> SimpleLibraryItem?)? + func findFirstItem(in parentFolder: String?, afterRank: Int16?, isUnfinished: Bool?) -> SimpleLibraryItem? { + findFirstItemInAfterRankIsUnfinishedCallsCount += 1 + findFirstItemInAfterRankIsUnfinishedReceivedArguments = (parentFolder: parentFolder, afterRank: afterRank, isUnfinished: isUnfinished) + findFirstItemInAfterRankIsUnfinishedReceivedInvocations.append((parentFolder: parentFolder, afterRank: afterRank, isUnfinished: isUnfinished)) + if let findFirstItemInAfterRankIsUnfinishedClosure = findFirstItemInAfterRankIsUnfinishedClosure { + return findFirstItemInAfterRankIsUnfinishedClosure(parentFolder, afterRank, isUnfinished) + } else { + return findFirstItemInAfterRankIsUnfinishedReturnValue + } + } + //MARK: - getChapters + + var getChaptersFromCallsCount = 0 + var getChaptersFromCalled: Bool { + return getChaptersFromCallsCount > 0 + } + var getChaptersFromReceivedRelativePath: String? + var getChaptersFromReceivedInvocations: [String] = [] + var getChaptersFromReturnValue: [SimpleChapter]? + var getChaptersFromClosure: ((String) -> [SimpleChapter]?)? + func getChapters(from relativePath: String) -> [SimpleChapter]? { + getChaptersFromCallsCount += 1 + getChaptersFromReceivedRelativePath = relativePath + getChaptersFromReceivedInvocations.append(relativePath) + if let getChaptersFromClosure = getChaptersFromClosure { + return getChaptersFromClosure(relativePath) + } else { + return getChaptersFromReturnValue + } + } + //MARK: - createBook + + var createBookFromCallsCount = 0 + var createBookFromCalled: Bool { + return createBookFromCallsCount > 0 + } + var createBookFromReceivedUrl: URL? + var createBookFromReceivedInvocations: [URL] = [] + var createBookFromReturnValue: Book! + var createBookFromClosure: ((URL) -> Book)? + func createBook(from url: URL) -> Book { + createBookFromCallsCount += 1 + createBookFromReceivedUrl = url + createBookFromReceivedInvocations.append(url) + if let createBookFromClosure = createBookFromClosure { + return createBookFromClosure(url) + } else { + return createBookFromReturnValue + } + } + //MARK: - loadChaptersIfNeeded + + var loadChaptersIfNeededRelativePathAssetCallsCount = 0 + var loadChaptersIfNeededRelativePathAssetCalled: Bool { + return loadChaptersIfNeededRelativePathAssetCallsCount > 0 + } + var loadChaptersIfNeededRelativePathAssetReceivedArguments: (relativePath: String, asset: AVAsset)? + var loadChaptersIfNeededRelativePathAssetReceivedInvocations: [(relativePath: String, asset: AVAsset)] = [] + var loadChaptersIfNeededRelativePathAssetClosure: ((String, AVAsset) -> Void)? + func loadChaptersIfNeeded(relativePath: String, asset: AVAsset) { + loadChaptersIfNeededRelativePathAssetCallsCount += 1 + loadChaptersIfNeededRelativePathAssetReceivedArguments = (relativePath: relativePath, asset: asset) + loadChaptersIfNeededRelativePathAssetReceivedInvocations.append((relativePath: relativePath, asset: asset)) + loadChaptersIfNeededRelativePathAssetClosure?(relativePath, asset) + } + //MARK: - createFolder + + var createFolderWithInsideThrowableError: Error? + var createFolderWithInsideCallsCount = 0 + var createFolderWithInsideCalled: Bool { + return createFolderWithInsideCallsCount > 0 + } + var createFolderWithInsideReceivedArguments: (title: String, relativePath: String?)? + var createFolderWithInsideReceivedInvocations: [(title: String, relativePath: String?)] = [] + var createFolderWithInsideReturnValue: SimpleLibraryItem! + var createFolderWithInsideClosure: ((String, String?) throws -> SimpleLibraryItem)? + func createFolder(with title: String, inside relativePath: String?) throws -> SimpleLibraryItem { + if let error = createFolderWithInsideThrowableError { + throw error + } + createFolderWithInsideCallsCount += 1 + createFolderWithInsideReceivedArguments = (title: title, relativePath: relativePath) + createFolderWithInsideReceivedInvocations.append((title: title, relativePath: relativePath)) + if let createFolderWithInsideClosure = createFolderWithInsideClosure { + return try createFolderWithInsideClosure(title, relativePath) + } else { + return createFolderWithInsideReturnValue + } + } + //MARK: - updateFolder + + var updateFolderAtTypeThrowableError: Error? + var updateFolderAtTypeCallsCount = 0 + var updateFolderAtTypeCalled: Bool { + return updateFolderAtTypeCallsCount > 0 + } + var updateFolderAtTypeReceivedArguments: (relativePath: String, type: SimpleItemType)? + var updateFolderAtTypeReceivedInvocations: [(relativePath: String, type: SimpleItemType)] = [] + var updateFolderAtTypeClosure: ((String, SimpleItemType) throws -> Void)? + func updateFolder(at relativePath: String, type: SimpleItemType) throws { + if let error = updateFolderAtTypeThrowableError { + throw error + } + updateFolderAtTypeCallsCount += 1 + updateFolderAtTypeReceivedArguments = (relativePath: relativePath, type: type) + updateFolderAtTypeReceivedInvocations.append((relativePath: relativePath, type: type)) + try updateFolderAtTypeClosure?(relativePath, type) + } + //MARK: - rebuildFolderDetails + + var rebuildFolderDetailsCallsCount = 0 + var rebuildFolderDetailsCalled: Bool { + return rebuildFolderDetailsCallsCount > 0 + } + var rebuildFolderDetailsReceivedRelativePath: String? + var rebuildFolderDetailsReceivedInvocations: [String] = [] + var rebuildFolderDetailsClosure: ((String) -> Void)? + func rebuildFolderDetails(_ relativePath: String) { + rebuildFolderDetailsCallsCount += 1 + rebuildFolderDetailsReceivedRelativePath = relativePath + rebuildFolderDetailsReceivedInvocations.append(relativePath) + rebuildFolderDetailsClosure?(relativePath) + } + //MARK: - recursiveFolderProgressUpdate + + var recursiveFolderProgressUpdateFromCallsCount = 0 + var recursiveFolderProgressUpdateFromCalled: Bool { + return recursiveFolderProgressUpdateFromCallsCount > 0 + } + var recursiveFolderProgressUpdateFromReceivedRelativePath: String? + var recursiveFolderProgressUpdateFromReceivedInvocations: [String] = [] + var recursiveFolderProgressUpdateFromClosure: ((String) -> Void)? + func recursiveFolderProgressUpdate(from relativePath: String) { + recursiveFolderProgressUpdateFromCallsCount += 1 + recursiveFolderProgressUpdateFromReceivedRelativePath = relativePath + recursiveFolderProgressUpdateFromReceivedInvocations.append(relativePath) + recursiveFolderProgressUpdateFromClosure?(relativePath) + } + //MARK: - renameBook + + var renameBookAtWithCallsCount = 0 + var renameBookAtWithCalled: Bool { + return renameBookAtWithCallsCount > 0 + } + var renameBookAtWithReceivedArguments: (relativePath: String, newTitle: String)? + var renameBookAtWithReceivedInvocations: [(relativePath: String, newTitle: String)] = [] + var renameBookAtWithClosure: ((String, String) -> Void)? + func renameBook(at relativePath: String, with newTitle: String) { + renameBookAtWithCallsCount += 1 + renameBookAtWithReceivedArguments = (relativePath: relativePath, newTitle: newTitle) + renameBookAtWithReceivedInvocations.append((relativePath: relativePath, newTitle: newTitle)) + renameBookAtWithClosure?(relativePath, newTitle) + } + //MARK: - renameFolder + + var renameFolderAtWithThrowableError: Error? + var renameFolderAtWithCallsCount = 0 + var renameFolderAtWithCalled: Bool { + return renameFolderAtWithCallsCount > 0 + } + var renameFolderAtWithReceivedArguments: (relativePath: String, newTitle: String)? + var renameFolderAtWithReceivedInvocations: [(relativePath: String, newTitle: String)] = [] + var renameFolderAtWithReturnValue: String! + var renameFolderAtWithClosure: ((String, String) throws -> String)? + func renameFolder(at relativePath: String, with newTitle: String) throws -> String { + if let error = renameFolderAtWithThrowableError { + throw error + } + renameFolderAtWithCallsCount += 1 + renameFolderAtWithReceivedArguments = (relativePath: relativePath, newTitle: newTitle) + renameFolderAtWithReceivedInvocations.append((relativePath: relativePath, newTitle: newTitle)) + if let renameFolderAtWithClosure = renameFolderAtWithClosure { + return try renameFolderAtWithClosure(relativePath, newTitle) + } else { + return renameFolderAtWithReturnValue + } + } + //MARK: - updateDetails + + var updateDetailsAtDetailsCallsCount = 0 + var updateDetailsAtDetailsCalled: Bool { + return updateDetailsAtDetailsCallsCount > 0 + } + var updateDetailsAtDetailsReceivedArguments: (relativePath: String, details: String)? + var updateDetailsAtDetailsReceivedInvocations: [(relativePath: String, details: String)] = [] + var updateDetailsAtDetailsClosure: ((String, String) -> Void)? + func updateDetails(at relativePath: String, details: String) { + updateDetailsAtDetailsCallsCount += 1 + updateDetailsAtDetailsReceivedArguments = (relativePath: relativePath, details: details) + updateDetailsAtDetailsReceivedInvocations.append((relativePath: relativePath, details: details)) + updateDetailsAtDetailsClosure?(relativePath, details) + } + //MARK: - reorderItem + + var reorderItemWithInsideSourceIndexPathDestinationIndexPathCallsCount = 0 + var reorderItemWithInsideSourceIndexPathDestinationIndexPathCalled: Bool { + return reorderItemWithInsideSourceIndexPathDestinationIndexPathCallsCount > 0 + } + var reorderItemWithInsideSourceIndexPathDestinationIndexPathReceivedArguments: (relativePath: String, folderRelativePath: String?, sourceIndexPath: IndexPath, destinationIndexPath: IndexPath)? + var reorderItemWithInsideSourceIndexPathDestinationIndexPathReceivedInvocations: [(relativePath: String, folderRelativePath: String?, sourceIndexPath: IndexPath, destinationIndexPath: IndexPath)] = [] + var reorderItemWithInsideSourceIndexPathDestinationIndexPathClosure: ((String, String?, IndexPath, IndexPath) -> Void)? + func reorderItem(with relativePath: String, inside folderRelativePath: String?, sourceIndexPath: IndexPath, destinationIndexPath: IndexPath) { + reorderItemWithInsideSourceIndexPathDestinationIndexPathCallsCount += 1 + reorderItemWithInsideSourceIndexPathDestinationIndexPathReceivedArguments = (relativePath: relativePath, folderRelativePath: folderRelativePath, sourceIndexPath: sourceIndexPath, destinationIndexPath: destinationIndexPath) + reorderItemWithInsideSourceIndexPathDestinationIndexPathReceivedInvocations.append((relativePath: relativePath, folderRelativePath: folderRelativePath, sourceIndexPath: sourceIndexPath, destinationIndexPath: destinationIndexPath)) + reorderItemWithInsideSourceIndexPathDestinationIndexPathClosure?(relativePath, folderRelativePath, sourceIndexPath, destinationIndexPath) + } + //MARK: - sortContents + + var sortContentsAtByCallsCount = 0 + var sortContentsAtByCalled: Bool { + return sortContentsAtByCallsCount > 0 + } + var sortContentsAtByReceivedArguments: (relativePath: String?, type: SortType)? + var sortContentsAtByReceivedInvocations: [(relativePath: String?, type: SortType)] = [] + var sortContentsAtByClosure: ((String?, SortType) -> Void)? + func sortContents(at relativePath: String?, by type: SortType) { + sortContentsAtByCallsCount += 1 + sortContentsAtByReceivedArguments = (relativePath: relativePath, type: type) + sortContentsAtByReceivedInvocations.append((relativePath: relativePath, type: type)) + sortContentsAtByClosure?(relativePath, type) + } + //MARK: - updatePlaybackTime + + var updatePlaybackTimeRelativePathTimeDateScheduleSaveCallsCount = 0 + var updatePlaybackTimeRelativePathTimeDateScheduleSaveCalled: Bool { + return updatePlaybackTimeRelativePathTimeDateScheduleSaveCallsCount > 0 + } + var updatePlaybackTimeRelativePathTimeDateScheduleSaveReceivedArguments: (relativePath: String, time: Double, date: Date, scheduleSave: Bool)? + var updatePlaybackTimeRelativePathTimeDateScheduleSaveReceivedInvocations: [(relativePath: String, time: Double, date: Date, scheduleSave: Bool)] = [] + var updatePlaybackTimeRelativePathTimeDateScheduleSaveClosure: ((String, Double, Date, Bool) -> Void)? + func updatePlaybackTime(relativePath: String, time: Double, date: Date, scheduleSave: Bool) { + updatePlaybackTimeRelativePathTimeDateScheduleSaveCallsCount += 1 + updatePlaybackTimeRelativePathTimeDateScheduleSaveReceivedArguments = (relativePath: relativePath, time: time, date: date, scheduleSave: scheduleSave) + updatePlaybackTimeRelativePathTimeDateScheduleSaveReceivedInvocations.append((relativePath: relativePath, time: time, date: date, scheduleSave: scheduleSave)) + updatePlaybackTimeRelativePathTimeDateScheduleSaveClosure?(relativePath, time, date, scheduleSave) + } + //MARK: - updateBookSpeed + + var updateBookSpeedAtSpeedCallsCount = 0 + var updateBookSpeedAtSpeedCalled: Bool { + return updateBookSpeedAtSpeedCallsCount > 0 + } + var updateBookSpeedAtSpeedReceivedArguments: (relativePath: String, speed: Float)? + var updateBookSpeedAtSpeedReceivedInvocations: [(relativePath: String, speed: Float)] = [] + var updateBookSpeedAtSpeedClosure: ((String, Float) -> Void)? + func updateBookSpeed(at relativePath: String, speed: Float) { + updateBookSpeedAtSpeedCallsCount += 1 + updateBookSpeedAtSpeedReceivedArguments = (relativePath: relativePath, speed: speed) + updateBookSpeedAtSpeedReceivedInvocations.append((relativePath: relativePath, speed: speed)) + updateBookSpeedAtSpeedClosure?(relativePath, speed) + } + //MARK: - getItemSpeed + + var getItemSpeedAtCallsCount = 0 + var getItemSpeedAtCalled: Bool { + return getItemSpeedAtCallsCount > 0 + } + var getItemSpeedAtReceivedRelativePath: String? + var getItemSpeedAtReceivedInvocations: [String] = [] + var getItemSpeedAtReturnValue: Float! + var getItemSpeedAtClosure: ((String) -> Float)? + func getItemSpeed(at relativePath: String) -> Float { + getItemSpeedAtCallsCount += 1 + getItemSpeedAtReceivedRelativePath = relativePath + getItemSpeedAtReceivedInvocations.append(relativePath) + if let getItemSpeedAtClosure = getItemSpeedAtClosure { + return getItemSpeedAtClosure(relativePath) + } else { + return getItemSpeedAtReturnValue + } + } + //MARK: - markAsFinished + + var markAsFinishedFlagRelativePathCallsCount = 0 + var markAsFinishedFlagRelativePathCalled: Bool { + return markAsFinishedFlagRelativePathCallsCount > 0 + } + var markAsFinishedFlagRelativePathReceivedArguments: (flag: Bool, relativePath: String)? + var markAsFinishedFlagRelativePathReceivedInvocations: [(flag: Bool, relativePath: String)] = [] + var markAsFinishedFlagRelativePathClosure: ((Bool, String) -> Void)? + func markAsFinished(flag: Bool, relativePath: String) { + markAsFinishedFlagRelativePathCallsCount += 1 + markAsFinishedFlagRelativePathReceivedArguments = (flag: flag, relativePath: relativePath) + markAsFinishedFlagRelativePathReceivedInvocations.append((flag: flag, relativePath: relativePath)) + markAsFinishedFlagRelativePathClosure?(flag, relativePath) + } + //MARK: - jumpToStart + + var jumpToStartRelativePathCallsCount = 0 + var jumpToStartRelativePathCalled: Bool { + return jumpToStartRelativePathCallsCount > 0 + } + var jumpToStartRelativePathReceivedRelativePath: String? + var jumpToStartRelativePathReceivedInvocations: [String] = [] + var jumpToStartRelativePathClosure: ((String) -> Void)? + func jumpToStart(relativePath: String) { + jumpToStartRelativePathCallsCount += 1 + jumpToStartRelativePathReceivedRelativePath = relativePath + jumpToStartRelativePathReceivedInvocations.append(relativePath) + jumpToStartRelativePathClosure?(relativePath) + } + //MARK: - getCurrentPlaybackRecord + + var getCurrentPlaybackRecordCallsCount = 0 + var getCurrentPlaybackRecordCalled: Bool { + return getCurrentPlaybackRecordCallsCount > 0 + } + var getCurrentPlaybackRecordReturnValue: PlaybackRecord! + var getCurrentPlaybackRecordClosure: (() -> PlaybackRecord)? + func getCurrentPlaybackRecord() -> PlaybackRecord { + getCurrentPlaybackRecordCallsCount += 1 + if let getCurrentPlaybackRecordClosure = getCurrentPlaybackRecordClosure { + return getCurrentPlaybackRecordClosure() + } else { + return getCurrentPlaybackRecordReturnValue + } + } + //MARK: - getPlaybackRecords + + var getPlaybackRecordsFromToCallsCount = 0 + var getPlaybackRecordsFromToCalled: Bool { + return getPlaybackRecordsFromToCallsCount > 0 + } + var getPlaybackRecordsFromToReceivedArguments: (startDate: Date, endDate: Date)? + var getPlaybackRecordsFromToReceivedInvocations: [(startDate: Date, endDate: Date)] = [] + var getPlaybackRecordsFromToReturnValue: [PlaybackRecord]? + var getPlaybackRecordsFromToClosure: ((Date, Date) -> [PlaybackRecord]?)? + func getPlaybackRecords(from startDate: Date, to endDate: Date) -> [PlaybackRecord]? { + getPlaybackRecordsFromToCallsCount += 1 + getPlaybackRecordsFromToReceivedArguments = (startDate: startDate, endDate: endDate) + getPlaybackRecordsFromToReceivedInvocations.append((startDate: startDate, endDate: endDate)) + if let getPlaybackRecordsFromToClosure = getPlaybackRecordsFromToClosure { + return getPlaybackRecordsFromToClosure(startDate, endDate) + } else { + return getPlaybackRecordsFromToReturnValue + } + } + //MARK: - recordTime + + var recordTimeCallsCount = 0 + var recordTimeCalled: Bool { + return recordTimeCallsCount > 0 + } + var recordTimeReceivedPlaybackRecord: PlaybackRecord? + var recordTimeReceivedInvocations: [PlaybackRecord] = [] + var recordTimeClosure: ((PlaybackRecord) -> Void)? + func recordTime(_ playbackRecord: PlaybackRecord) { + recordTimeCallsCount += 1 + recordTimeReceivedPlaybackRecord = playbackRecord + recordTimeReceivedInvocations.append(playbackRecord) + recordTimeClosure?(playbackRecord) + } + //MARK: - getTotalListenedTime + + var getTotalListenedTimeCallsCount = 0 + var getTotalListenedTimeCalled: Bool { + return getTotalListenedTimeCallsCount > 0 + } + var getTotalListenedTimeReturnValue: TimeInterval! + var getTotalListenedTimeClosure: (() -> TimeInterval)? + func getTotalListenedTime() -> TimeInterval { + getTotalListenedTimeCallsCount += 1 + if let getTotalListenedTimeClosure = getTotalListenedTimeClosure { + return getTotalListenedTimeClosure() + } else { + return getTotalListenedTimeReturnValue + } + } + //MARK: - getBookmarks + + var getBookmarksOfRelativePathCallsCount = 0 + var getBookmarksOfRelativePathCalled: Bool { + return getBookmarksOfRelativePathCallsCount > 0 + } + var getBookmarksOfRelativePathReceivedArguments: (type: BookmarkType, relativePath: String)? + var getBookmarksOfRelativePathReceivedInvocations: [(type: BookmarkType, relativePath: String)] = [] + var getBookmarksOfRelativePathReturnValue: [SimpleBookmark]? + var getBookmarksOfRelativePathClosure: ((BookmarkType, String) -> [SimpleBookmark]?)? + func getBookmarks(of type: BookmarkType, relativePath: String) -> [SimpleBookmark]? { + getBookmarksOfRelativePathCallsCount += 1 + getBookmarksOfRelativePathReceivedArguments = (type: type, relativePath: relativePath) + getBookmarksOfRelativePathReceivedInvocations.append((type: type, relativePath: relativePath)) + if let getBookmarksOfRelativePathClosure = getBookmarksOfRelativePathClosure { + return getBookmarksOfRelativePathClosure(type, relativePath) + } else { + return getBookmarksOfRelativePathReturnValue + } + } + //MARK: - getBookmark + + var getBookmarkAtRelativePathTypeCallsCount = 0 + var getBookmarkAtRelativePathTypeCalled: Bool { + return getBookmarkAtRelativePathTypeCallsCount > 0 + } + var getBookmarkAtRelativePathTypeReceivedArguments: (time: Double, relativePath: String, type: BookmarkType)? + var getBookmarkAtRelativePathTypeReceivedInvocations: [(time: Double, relativePath: String, type: BookmarkType)] = [] + var getBookmarkAtRelativePathTypeReturnValue: SimpleBookmark? + var getBookmarkAtRelativePathTypeClosure: ((Double, String, BookmarkType) -> SimpleBookmark?)? + func getBookmark(at time: Double, relativePath: String, type: BookmarkType) -> SimpleBookmark? { + getBookmarkAtRelativePathTypeCallsCount += 1 + getBookmarkAtRelativePathTypeReceivedArguments = (time: time, relativePath: relativePath, type: type) + getBookmarkAtRelativePathTypeReceivedInvocations.append((time: time, relativePath: relativePath, type: type)) + if let getBookmarkAtRelativePathTypeClosure = getBookmarkAtRelativePathTypeClosure { + return getBookmarkAtRelativePathTypeClosure(time, relativePath, type) + } else { + return getBookmarkAtRelativePathTypeReturnValue + } + } + //MARK: - createBookmark + + var createBookmarkAtRelativePathTypeCallsCount = 0 + var createBookmarkAtRelativePathTypeCalled: Bool { + return createBookmarkAtRelativePathTypeCallsCount > 0 + } + var createBookmarkAtRelativePathTypeReceivedArguments: (time: Double, relativePath: String, type: BookmarkType)? + var createBookmarkAtRelativePathTypeReceivedInvocations: [(time: Double, relativePath: String, type: BookmarkType)] = [] + var createBookmarkAtRelativePathTypeReturnValue: SimpleBookmark? + var createBookmarkAtRelativePathTypeClosure: ((Double, String, BookmarkType) -> SimpleBookmark?)? + func createBookmark(at time: Double, relativePath: String, type: BookmarkType) -> SimpleBookmark? { + createBookmarkAtRelativePathTypeCallsCount += 1 + createBookmarkAtRelativePathTypeReceivedArguments = (time: time, relativePath: relativePath, type: type) + createBookmarkAtRelativePathTypeReceivedInvocations.append((time: time, relativePath: relativePath, type: type)) + if let createBookmarkAtRelativePathTypeClosure = createBookmarkAtRelativePathTypeClosure { + return createBookmarkAtRelativePathTypeClosure(time, relativePath, type) + } else { + return createBookmarkAtRelativePathTypeReturnValue + } + } + //MARK: - addNote + + var addNoteBookmarkCallsCount = 0 + var addNoteBookmarkCalled: Bool { + return addNoteBookmarkCallsCount > 0 + } + var addNoteBookmarkReceivedArguments: (note: String, bookmark: SimpleBookmark)? + var addNoteBookmarkReceivedInvocations: [(note: String, bookmark: SimpleBookmark)] = [] + var addNoteBookmarkClosure: ((String, SimpleBookmark) -> Void)? + func addNote(_ note: String, bookmark: SimpleBookmark) { + addNoteBookmarkCallsCount += 1 + addNoteBookmarkReceivedArguments = (note: note, bookmark: bookmark) + addNoteBookmarkReceivedInvocations.append((note: note, bookmark: bookmark)) + addNoteBookmarkClosure?(note, bookmark) + } + //MARK: - deleteBookmark + + var deleteBookmarkCallsCount = 0 + var deleteBookmarkCalled: Bool { + return deleteBookmarkCallsCount > 0 + } + var deleteBookmarkReceivedBookmark: SimpleBookmark? + var deleteBookmarkReceivedInvocations: [SimpleBookmark] = [] + var deleteBookmarkClosure: ((SimpleBookmark) -> Void)? + func deleteBookmark(_ bookmark: SimpleBookmark) { + deleteBookmarkCallsCount += 1 + deleteBookmarkReceivedBookmark = bookmark + deleteBookmarkReceivedInvocations.append(bookmark) + deleteBookmarkClosure?(bookmark) + } +} +class PlaybackServiceProtocolMock: PlaybackServiceProtocol { + //MARK: - updatePlaybackTime + + var updatePlaybackTimeItemTimeCallsCount = 0 + var updatePlaybackTimeItemTimeCalled: Bool { + return updatePlaybackTimeItemTimeCallsCount > 0 + } + var updatePlaybackTimeItemTimeReceivedArguments: (item: PlayableItem, time: Double)? + var updatePlaybackTimeItemTimeReceivedInvocations: [(item: PlayableItem, time: Double)] = [] + var updatePlaybackTimeItemTimeClosure: ((PlayableItem, Double) -> Void)? + func updatePlaybackTime(item: PlayableItem, time: Double) { + updatePlaybackTimeItemTimeCallsCount += 1 + updatePlaybackTimeItemTimeReceivedArguments = (item: item, time: time) + updatePlaybackTimeItemTimeReceivedInvocations.append((item: item, time: time)) + updatePlaybackTimeItemTimeClosure?(item, time) + } + //MARK: - getPlayableItem + + var getPlayableItemBeforeParentFolderCallsCount = 0 + var getPlayableItemBeforeParentFolderCalled: Bool { + return getPlayableItemBeforeParentFolderCallsCount > 0 + } + var getPlayableItemBeforeParentFolderReceivedArguments: (relativePath: String, parentFolder: String?)? + var getPlayableItemBeforeParentFolderReceivedInvocations: [(relativePath: String, parentFolder: String?)] = [] + var getPlayableItemBeforeParentFolderReturnValue: PlayableItem? + var getPlayableItemBeforeParentFolderClosure: ((String, String?) -> PlayableItem?)? + func getPlayableItem(before relativePath: String, parentFolder: String?) -> PlayableItem? { + getPlayableItemBeforeParentFolderCallsCount += 1 + getPlayableItemBeforeParentFolderReceivedArguments = (relativePath: relativePath, parentFolder: parentFolder) + getPlayableItemBeforeParentFolderReceivedInvocations.append((relativePath: relativePath, parentFolder: parentFolder)) + if let getPlayableItemBeforeParentFolderClosure = getPlayableItemBeforeParentFolderClosure { + return getPlayableItemBeforeParentFolderClosure(relativePath, parentFolder) + } else { + return getPlayableItemBeforeParentFolderReturnValue + } + } + //MARK: - getPlayableItem + + var getPlayableItemAfterParentFolderAutoplayedRestartFinishedCallsCount = 0 + var getPlayableItemAfterParentFolderAutoplayedRestartFinishedCalled: Bool { + return getPlayableItemAfterParentFolderAutoplayedRestartFinishedCallsCount > 0 + } + var getPlayableItemAfterParentFolderAutoplayedRestartFinishedReceivedArguments: (relativePath: String, parentFolder: String?, autoplayed: Bool, restartFinished: Bool)? + var getPlayableItemAfterParentFolderAutoplayedRestartFinishedReceivedInvocations: [(relativePath: String, parentFolder: String?, autoplayed: Bool, restartFinished: Bool)] = [] + var getPlayableItemAfterParentFolderAutoplayedRestartFinishedReturnValue: PlayableItem? + var getPlayableItemAfterParentFolderAutoplayedRestartFinishedClosure: ((String, String?, Bool, Bool) -> PlayableItem?)? + func getPlayableItem(after relativePath: String, parentFolder: String?, autoplayed: Bool, restartFinished: Bool) -> PlayableItem? { + getPlayableItemAfterParentFolderAutoplayedRestartFinishedCallsCount += 1 + getPlayableItemAfterParentFolderAutoplayedRestartFinishedReceivedArguments = (relativePath: relativePath, parentFolder: parentFolder, autoplayed: autoplayed, restartFinished: restartFinished) + getPlayableItemAfterParentFolderAutoplayedRestartFinishedReceivedInvocations.append((relativePath: relativePath, parentFolder: parentFolder, autoplayed: autoplayed, restartFinished: restartFinished)) + if let getPlayableItemAfterParentFolderAutoplayedRestartFinishedClosure = getPlayableItemAfterParentFolderAutoplayedRestartFinishedClosure { + return getPlayableItemAfterParentFolderAutoplayedRestartFinishedClosure(relativePath, parentFolder, autoplayed, restartFinished) + } else { + return getPlayableItemAfterParentFolderAutoplayedRestartFinishedReturnValue + } + } + //MARK: - getFirstPlayableItem + + var getFirstPlayableItemInIsUnfinishedThrowableError: Error? + var getFirstPlayableItemInIsUnfinishedCallsCount = 0 + var getFirstPlayableItemInIsUnfinishedCalled: Bool { + return getFirstPlayableItemInIsUnfinishedCallsCount > 0 + } + var getFirstPlayableItemInIsUnfinishedReceivedArguments: (folder: SimpleLibraryItem, isUnfinished: Bool?)? + var getFirstPlayableItemInIsUnfinishedReceivedInvocations: [(folder: SimpleLibraryItem, isUnfinished: Bool?)] = [] + var getFirstPlayableItemInIsUnfinishedReturnValue: PlayableItem? + var getFirstPlayableItemInIsUnfinishedClosure: ((SimpleLibraryItem, Bool?) throws -> PlayableItem?)? + func getFirstPlayableItem(in folder: SimpleLibraryItem, isUnfinished: Bool?) throws -> PlayableItem? { + if let error = getFirstPlayableItemInIsUnfinishedThrowableError { + throw error + } + getFirstPlayableItemInIsUnfinishedCallsCount += 1 + getFirstPlayableItemInIsUnfinishedReceivedArguments = (folder: folder, isUnfinished: isUnfinished) + getFirstPlayableItemInIsUnfinishedReceivedInvocations.append((folder: folder, isUnfinished: isUnfinished)) + if let getFirstPlayableItemInIsUnfinishedClosure = getFirstPlayableItemInIsUnfinishedClosure { + return try getFirstPlayableItemInIsUnfinishedClosure(folder, isUnfinished) + } else { + return getFirstPlayableItemInIsUnfinishedReturnValue + } + } + //MARK: - getPlayableItem + + var getPlayableItemFromThrowableError: Error? + var getPlayableItemFromCallsCount = 0 + var getPlayableItemFromCalled: Bool { + return getPlayableItemFromCallsCount > 0 + } + var getPlayableItemFromReceivedItem: SimpleLibraryItem? + var getPlayableItemFromReceivedInvocations: [SimpleLibraryItem] = [] + var getPlayableItemFromReturnValue: PlayableItem? + var getPlayableItemFromClosure: ((SimpleLibraryItem) throws -> PlayableItem?)? + func getPlayableItem(from item: SimpleLibraryItem) throws -> PlayableItem? { + if let error = getPlayableItemFromThrowableError { + throw error + } + getPlayableItemFromCallsCount += 1 + getPlayableItemFromReceivedItem = item + getPlayableItemFromReceivedInvocations.append(item) + if let getPlayableItemFromClosure = getPlayableItemFromClosure { + return try getPlayableItemFromClosure(item) + } else { + return getPlayableItemFromReturnValue + } + } + //MARK: - getNextChapter + + var getNextChapterFromCallsCount = 0 + var getNextChapterFromCalled: Bool { + return getNextChapterFromCallsCount > 0 + } + var getNextChapterFromReceivedItem: PlayableItem? + var getNextChapterFromReceivedInvocations: [PlayableItem] = [] + var getNextChapterFromReturnValue: PlayableChapter? + var getNextChapterFromClosure: ((PlayableItem) -> PlayableChapter?)? + func getNextChapter(from item: PlayableItem) -> PlayableChapter? { + getNextChapterFromCallsCount += 1 + getNextChapterFromReceivedItem = item + getNextChapterFromReceivedInvocations.append(item) + if let getNextChapterFromClosure = getNextChapterFromClosure { + return getNextChapterFromClosure(item) + } else { + return getNextChapterFromReturnValue + } + } +} +class PlayerManagerProtocolMock: PlayerManagerProtocol { + var currentItem: PlayableItem? + var currentSpeed: Float { + get { return underlyingCurrentSpeed } + set(value) { underlyingCurrentSpeed = value } + } + var underlyingCurrentSpeed: Float! + var isPlaying: Bool { + get { return underlyingIsPlaying } + set(value) { underlyingIsPlaying = value } + } + var underlyingIsPlaying: Bool! + //MARK: - load + + var loadAutoplayCallsCount = 0 + var loadAutoplayCalled: Bool { + return loadAutoplayCallsCount > 0 + } + var loadAutoplayReceivedArguments: (item: PlayableItem, autoplay: Bool)? + var loadAutoplayReceivedInvocations: [(item: PlayableItem, autoplay: Bool)] = [] + var loadAutoplayClosure: ((PlayableItem, Bool) -> Void)? + func load(_ item: PlayableItem, autoplay: Bool) { + loadAutoplayCallsCount += 1 + loadAutoplayReceivedArguments = (item: item, autoplay: autoplay) + loadAutoplayReceivedInvocations.append((item: item, autoplay: autoplay)) + loadAutoplayClosure?(item, autoplay) + } + //MARK: - hasLoadedBook + + var hasLoadedBookCallsCount = 0 + var hasLoadedBookCalled: Bool { + return hasLoadedBookCallsCount > 0 + } + var hasLoadedBookReturnValue: Bool! + var hasLoadedBookClosure: (() -> Bool)? + func hasLoadedBook() -> Bool { + hasLoadedBookCallsCount += 1 + if let hasLoadedBookClosure = hasLoadedBookClosure { + return hasLoadedBookClosure() + } else { + return hasLoadedBookReturnValue + } + } + //MARK: - playPreviousItem + + var playPreviousItemCallsCount = 0 + var playPreviousItemCalled: Bool { + return playPreviousItemCallsCount > 0 + } + var playPreviousItemClosure: (() -> Void)? + func playPreviousItem() { + playPreviousItemCallsCount += 1 + playPreviousItemClosure?() + } + //MARK: - playNextItem + + var playNextItemAutoPlayedCallsCount = 0 + var playNextItemAutoPlayedCalled: Bool { + return playNextItemAutoPlayedCallsCount > 0 + } + var playNextItemAutoPlayedReceivedAutoPlayed: Bool? + var playNextItemAutoPlayedReceivedInvocations: [Bool] = [] + var playNextItemAutoPlayedClosure: ((Bool) -> Void)? + func playNextItem(autoPlayed: Bool) { + playNextItemAutoPlayedCallsCount += 1 + playNextItemAutoPlayedReceivedAutoPlayed = autoPlayed + playNextItemAutoPlayedReceivedInvocations.append(autoPlayed) + playNextItemAutoPlayedClosure?(autoPlayed) + } + //MARK: - play + + var playCallsCount = 0 + var playCalled: Bool { + return playCallsCount > 0 + } + var playClosure: (() -> Void)? + func play() { + playCallsCount += 1 + playClosure?() + } + //MARK: - playPause + + var playPauseCallsCount = 0 + var playPauseCalled: Bool { + return playPauseCallsCount > 0 + } + var playPauseClosure: (() -> Void)? + func playPause() { + playPauseCallsCount += 1 + playPauseClosure?() + } + //MARK: - pause + + var pauseFadeCallsCount = 0 + var pauseFadeCalled: Bool { + return pauseFadeCallsCount > 0 + } + var pauseFadeReceivedFade: Bool? + var pauseFadeReceivedInvocations: [Bool] = [] + var pauseFadeClosure: ((Bool) -> Void)? + func pause(fade: Bool) { + pauseFadeCallsCount += 1 + pauseFadeReceivedFade = fade + pauseFadeReceivedInvocations.append(fade) + pauseFadeClosure?(fade) + } + //MARK: - stop + + var stopCallsCount = 0 + var stopCalled: Bool { + return stopCallsCount > 0 + } + var stopClosure: (() -> Void)? + func stop() { + stopCallsCount += 1 + stopClosure?() + } + //MARK: - rewind + + var rewindCallsCount = 0 + var rewindCalled: Bool { + return rewindCallsCount > 0 + } + var rewindClosure: (() -> Void)? + func rewind() { + rewindCallsCount += 1 + rewindClosure?() + } + //MARK: - forward + + var forwardCallsCount = 0 + var forwardCalled: Bool { + return forwardCallsCount > 0 + } + var forwardClosure: (() -> Void)? + func forward() { + forwardCallsCount += 1 + forwardClosure?() + } + //MARK: - jumpTo + + var jumpToRecordBookmarkCallsCount = 0 + var jumpToRecordBookmarkCalled: Bool { + return jumpToRecordBookmarkCallsCount > 0 + } + var jumpToRecordBookmarkReceivedArguments: (time: Double, recordBookmark: Bool)? + var jumpToRecordBookmarkReceivedInvocations: [(time: Double, recordBookmark: Bool)] = [] + var jumpToRecordBookmarkClosure: ((Double, Bool) -> Void)? + func jumpTo(_ time: Double, recordBookmark: Bool) { + jumpToRecordBookmarkCallsCount += 1 + jumpToRecordBookmarkReceivedArguments = (time: time, recordBookmark: recordBookmark) + jumpToRecordBookmarkReceivedInvocations.append((time: time, recordBookmark: recordBookmark)) + jumpToRecordBookmarkClosure?(time, recordBookmark) + } + //MARK: - jumpToChapter + + var jumpToChapterCallsCount = 0 + var jumpToChapterCalled: Bool { + return jumpToChapterCallsCount > 0 + } + var jumpToChapterReceivedChapter: PlayableChapter? + var jumpToChapterReceivedInvocations: [PlayableChapter] = [] + var jumpToChapterClosure: ((PlayableChapter) -> Void)? + func jumpToChapter(_ chapter: PlayableChapter) { + jumpToChapterCallsCount += 1 + jumpToChapterReceivedChapter = chapter + jumpToChapterReceivedInvocations.append(chapter) + jumpToChapterClosure?(chapter) + } + //MARK: - markAsCompleted + + var markAsCompletedCallsCount = 0 + var markAsCompletedCalled: Bool { + return markAsCompletedCallsCount > 0 + } + var markAsCompletedReceivedFlag: Bool? + var markAsCompletedReceivedInvocations: [Bool] = [] + var markAsCompletedClosure: ((Bool) -> Void)? + func markAsCompleted(_ flag: Bool) { + markAsCompletedCallsCount += 1 + markAsCompletedReceivedFlag = flag + markAsCompletedReceivedInvocations.append(flag) + markAsCompletedClosure?(flag) + } + //MARK: - setSpeed + + var setSpeedCallsCount = 0 + var setSpeedCalled: Bool { + return setSpeedCallsCount > 0 + } + var setSpeedReceivedNewValue: Float? + var setSpeedReceivedInvocations: [Float] = [] + var setSpeedClosure: ((Float) -> Void)? + func setSpeed(_ newValue: Float) { + setSpeedCallsCount += 1 + setSpeedReceivedNewValue = newValue + setSpeedReceivedInvocations.append(newValue) + setSpeedClosure?(newValue) + } + //MARK: - setBoostVolume + + var setBoostVolumeCallsCount = 0 + var setBoostVolumeCalled: Bool { + return setBoostVolumeCallsCount > 0 + } + var setBoostVolumeReceivedNewValue: Bool? + var setBoostVolumeReceivedInvocations: [Bool] = [] + var setBoostVolumeClosure: ((Bool) -> Void)? + func setBoostVolume(_ newValue: Bool) { + setBoostVolumeCallsCount += 1 + setBoostVolumeReceivedNewValue = newValue + setBoostVolumeReceivedInvocations.append(newValue) + setBoostVolumeClosure?(newValue) + } + //MARK: - currentSpeedPublisher + + var currentSpeedPublisherCallsCount = 0 + var currentSpeedPublisherCalled: Bool { + return currentSpeedPublisherCallsCount > 0 + } + var currentSpeedPublisherReturnValue: Published.Publisher! + var currentSpeedPublisherClosure: (() -> Published.Publisher)? + func currentSpeedPublisher() -> Published.Publisher { + currentSpeedPublisherCallsCount += 1 + if let currentSpeedPublisherClosure = currentSpeedPublisherClosure { + return currentSpeedPublisherClosure() + } else { + return currentSpeedPublisherReturnValue + } + } + //MARK: - isPlayingPublisher + + var isPlayingPublisherCallsCount = 0 + var isPlayingPublisherCalled: Bool { + return isPlayingPublisherCallsCount > 0 + } + var isPlayingPublisherReturnValue: AnyPublisher! + var isPlayingPublisherClosure: (() -> AnyPublisher)? + func isPlayingPublisher() -> AnyPublisher { + isPlayingPublisherCallsCount += 1 + if let isPlayingPublisherClosure = isPlayingPublisherClosure { + return isPlayingPublisherClosure() + } else { + return isPlayingPublisherReturnValue + } + } + //MARK: - currentItemPublisher + + var currentItemPublisherCallsCount = 0 + var currentItemPublisherCalled: Bool { + return currentItemPublisherCallsCount > 0 + } + var currentItemPublisherReturnValue: Published.Publisher! + var currentItemPublisherClosure: (() -> Published.Publisher)? + func currentItemPublisher() -> Published.Publisher { + currentItemPublisherCallsCount += 1 + if let currentItemPublisherClosure = currentItemPublisherClosure { + return currentItemPublisherClosure() + } else { + return currentItemPublisherReturnValue + } + } +} +class SpeedServiceProtocolMock: SpeedServiceProtocol { + //MARK: - setSpeed + + var setSpeedRelativePathCallsCount = 0 + var setSpeedRelativePathCalled: Bool { + return setSpeedRelativePathCallsCount > 0 + } + var setSpeedRelativePathReceivedArguments: (newValue: Float, relativePath: String?)? + var setSpeedRelativePathReceivedInvocations: [(newValue: Float, relativePath: String?)] = [] + var setSpeedRelativePathClosure: ((Float, String?) -> Void)? + func setSpeed(_ newValue: Float, relativePath: String?) { + setSpeedRelativePathCallsCount += 1 + setSpeedRelativePathReceivedArguments = (newValue: newValue, relativePath: relativePath) + setSpeedRelativePathReceivedInvocations.append((newValue: newValue, relativePath: relativePath)) + setSpeedRelativePathClosure?(newValue, relativePath) + } + //MARK: - getSpeed + + var getSpeedRelativePathCallsCount = 0 + var getSpeedRelativePathCalled: Bool { + return getSpeedRelativePathCallsCount > 0 + } + var getSpeedRelativePathReceivedRelativePath: String? + var getSpeedRelativePathReceivedInvocations: [String?] = [] + var getSpeedRelativePathReturnValue: Float! + var getSpeedRelativePathClosure: ((String?) -> Float)? + func getSpeed(relativePath: String?) -> Float { + getSpeedRelativePathCallsCount += 1 + getSpeedRelativePathReceivedRelativePath = relativePath + getSpeedRelativePathReceivedInvocations.append(relativePath) + if let getSpeedRelativePathClosure = getSpeedRelativePathClosure { + return getSpeedRelativePathClosure(relativePath) + } else { + return getSpeedRelativePathReturnValue + } + } +} +class SyncServiceProtocolMock: SyncServiceProtocol { + var isActive: Bool { + get { return underlyingIsActive } + set(value) { underlyingIsActive = value } + } + var underlyingIsActive: Bool! + var queuedJobsCount: Int { + get { return underlyingQueuedJobsCount } + set(value) { underlyingQueuedJobsCount = value } + } + var underlyingQueuedJobsCount: Int! + //MARK: - syncListContents + + var syncListContentsAtThrowableError: Error? + var syncListContentsAtCallsCount = 0 + var syncListContentsAtCalled: Bool { + return syncListContentsAtCallsCount > 0 + } + var syncListContentsAtReceivedRelativePath: String? + var syncListContentsAtReceivedInvocations: [String?] = [] + var syncListContentsAtReturnValue: ([SyncableItem], SyncableItem?)? + var syncListContentsAtClosure: ((String?) async throws -> ([SyncableItem], SyncableItem?)?)? + func syncListContents(at relativePath: String?) async throws -> ([SyncableItem], SyncableItem?)? { + if let error = syncListContentsAtThrowableError { + throw error + } + syncListContentsAtCallsCount += 1 + syncListContentsAtReceivedRelativePath = relativePath + syncListContentsAtReceivedInvocations.append(relativePath) + if let syncListContentsAtClosure = syncListContentsAtClosure { + return try await syncListContentsAtClosure(relativePath) + } else { + return syncListContentsAtReturnValue + } + } + //MARK: - syncLibraryContents + + var syncLibraryContentsThrowableError: Error? + var syncLibraryContentsCallsCount = 0 + var syncLibraryContentsCalled: Bool { + return syncLibraryContentsCallsCount > 0 + } + var syncLibraryContentsReturnValue: ([SyncableItem], SyncableItem?)! + var syncLibraryContentsClosure: (() async throws -> ([SyncableItem], SyncableItem?))? + func syncLibraryContents() async throws -> ([SyncableItem], SyncableItem?) { + if let error = syncLibraryContentsThrowableError { + throw error + } + syncLibraryContentsCallsCount += 1 + if let syncLibraryContentsClosure = syncLibraryContentsClosure { + return try await syncLibraryContentsClosure() + } else { + return syncLibraryContentsReturnValue + } + } + //MARK: - syncBookmarksList + + var syncBookmarksListRelativePathThrowableError: Error? + var syncBookmarksListRelativePathCallsCount = 0 + var syncBookmarksListRelativePathCalled: Bool { + return syncBookmarksListRelativePathCallsCount > 0 + } + var syncBookmarksListRelativePathReceivedRelativePath: String? + var syncBookmarksListRelativePathReceivedInvocations: [String] = [] + var syncBookmarksListRelativePathReturnValue: [SimpleBookmark]? + var syncBookmarksListRelativePathClosure: ((String) async throws -> [SimpleBookmark]?)? + func syncBookmarksList(relativePath: String) async throws -> [SimpleBookmark]? { + if let error = syncBookmarksListRelativePathThrowableError { + throw error + } + syncBookmarksListRelativePathCallsCount += 1 + syncBookmarksListRelativePathReceivedRelativePath = relativePath + syncBookmarksListRelativePathReceivedInvocations.append(relativePath) + if let syncBookmarksListRelativePathClosure = syncBookmarksListRelativePathClosure { + return try await syncBookmarksListRelativePathClosure(relativePath) + } else { + return syncBookmarksListRelativePathReturnValue + } + } + //MARK: - getRemoteFileURLs + + var getRemoteFileURLsOfTypeThrowableError: Error? + var getRemoteFileURLsOfTypeCallsCount = 0 + var getRemoteFileURLsOfTypeCalled: Bool { + return getRemoteFileURLsOfTypeCallsCount > 0 + } + var getRemoteFileURLsOfTypeReceivedArguments: (relativePath: String, type: SimpleItemType)? + var getRemoteFileURLsOfTypeReceivedInvocations: [(relativePath: String, type: SimpleItemType)] = [] + var getRemoteFileURLsOfTypeReturnValue: [RemoteFileURL]! + var getRemoteFileURLsOfTypeClosure: ((String, SimpleItemType) async throws -> [RemoteFileURL])? + func getRemoteFileURLs(of relativePath: String, type: SimpleItemType) async throws -> [RemoteFileURL] { + if let error = getRemoteFileURLsOfTypeThrowableError { + throw error + } + getRemoteFileURLsOfTypeCallsCount += 1 + getRemoteFileURLsOfTypeReceivedArguments = (relativePath: relativePath, type: type) + getRemoteFileURLsOfTypeReceivedInvocations.append((relativePath: relativePath, type: type)) + if let getRemoteFileURLsOfTypeClosure = getRemoteFileURLsOfTypeClosure { + return try await getRemoteFileURLsOfTypeClosure(relativePath, type) + } else { + return getRemoteFileURLsOfTypeReturnValue + } + } + //MARK: - downloadRemoteFiles + + var downloadRemoteFilesForTypeDelegateThrowableError: Error? + var downloadRemoteFilesForTypeDelegateCallsCount = 0 + var downloadRemoteFilesForTypeDelegateCalled: Bool { + return downloadRemoteFilesForTypeDelegateCallsCount > 0 + } + var downloadRemoteFilesForTypeDelegateReceivedArguments: (relativePath: String, type: SimpleItemType, delegate: URLSessionTaskDelegate)? + var downloadRemoteFilesForTypeDelegateReceivedInvocations: [(relativePath: String, type: SimpleItemType, delegate: URLSessionTaskDelegate)] = [] + var downloadRemoteFilesForTypeDelegateReturnValue: [URLSessionDownloadTask]! + var downloadRemoteFilesForTypeDelegateClosure: ((String, SimpleItemType, URLSessionTaskDelegate) async throws -> [URLSessionDownloadTask])? + func downloadRemoteFiles(for relativePath: String, type: SimpleItemType, delegate: URLSessionTaskDelegate) async throws -> [URLSessionDownloadTask] { + if let error = downloadRemoteFilesForTypeDelegateThrowableError { + throw error + } + downloadRemoteFilesForTypeDelegateCallsCount += 1 + downloadRemoteFilesForTypeDelegateReceivedArguments = (relativePath: relativePath, type: type, delegate: delegate) + downloadRemoteFilesForTypeDelegateReceivedInvocations.append((relativePath: relativePath, type: type, delegate: delegate)) + if let downloadRemoteFilesForTypeDelegateClosure = downloadRemoteFilesForTypeDelegateClosure { + return try await downloadRemoteFilesForTypeDelegateClosure(relativePath, type, delegate) + } else { + return downloadRemoteFilesForTypeDelegateReturnValue + } + } + //MARK: - uploadArtwork + + var uploadArtworkRelativePathDataThrowableError: Error? + var uploadArtworkRelativePathDataCallsCount = 0 + var uploadArtworkRelativePathDataCalled: Bool { + return uploadArtworkRelativePathDataCallsCount > 0 + } + var uploadArtworkRelativePathDataReceivedArguments: (relativePath: String, data: Data)? + var uploadArtworkRelativePathDataReceivedInvocations: [(relativePath: String, data: Data)] = [] + var uploadArtworkRelativePathDataClosure: ((String, Data) async throws -> Void)? + func uploadArtwork(relativePath: String, data: Data) async throws { + if let error = uploadArtworkRelativePathDataThrowableError { + throw error + } + uploadArtworkRelativePathDataCallsCount += 1 + uploadArtworkRelativePathDataReceivedArguments = (relativePath: relativePath, data: data) + uploadArtworkRelativePathDataReceivedInvocations.append((relativePath: relativePath, data: data)) + try await uploadArtworkRelativePathDataClosure?(relativePath, data) + } + //MARK: - scheduleUpload + + var scheduleUploadItemsThrowableError: Error? + var scheduleUploadItemsCallsCount = 0 + var scheduleUploadItemsCalled: Bool { + return scheduleUploadItemsCallsCount > 0 + } + var scheduleUploadItemsReceivedItems: [SimpleLibraryItem]? + var scheduleUploadItemsReceivedInvocations: [[SimpleLibraryItem]] = [] + var scheduleUploadItemsClosure: (([SimpleLibraryItem]) throws -> Void)? + func scheduleUpload(items: [SimpleLibraryItem]) throws { + if let error = scheduleUploadItemsThrowableError { + throw error + } + scheduleUploadItemsCallsCount += 1 + scheduleUploadItemsReceivedItems = items + scheduleUploadItemsReceivedInvocations.append(items) + try scheduleUploadItemsClosure?(items) + } + //MARK: - scheduleDelete + + var scheduleDeleteModeCallsCount = 0 + var scheduleDeleteModeCalled: Bool { + return scheduleDeleteModeCallsCount > 0 + } + var scheduleDeleteModeReceivedArguments: (items: [SimpleLibraryItem], mode: DeleteMode)? + var scheduleDeleteModeReceivedInvocations: [(items: [SimpleLibraryItem], mode: DeleteMode)] = [] + var scheduleDeleteModeClosure: (([SimpleLibraryItem], DeleteMode) -> Void)? + func scheduleDelete(_ items: [SimpleLibraryItem], mode: DeleteMode) { + scheduleDeleteModeCallsCount += 1 + scheduleDeleteModeReceivedArguments = (items: items, mode: mode) + scheduleDeleteModeReceivedInvocations.append((items: items, mode: mode)) + scheduleDeleteModeClosure?(items, mode) + } + //MARK: - scheduleMove + + var scheduleMoveItemsToCallsCount = 0 + var scheduleMoveItemsToCalled: Bool { + return scheduleMoveItemsToCallsCount > 0 + } + var scheduleMoveItemsToReceivedArguments: (items: [String], parentFolder: String?)? + var scheduleMoveItemsToReceivedInvocations: [(items: [String], parentFolder: String?)] = [] + var scheduleMoveItemsToClosure: (([String], String?) -> Void)? + func scheduleMove(items: [String], to parentFolder: String?) { + scheduleMoveItemsToCallsCount += 1 + scheduleMoveItemsToReceivedArguments = (items: items, parentFolder: parentFolder) + scheduleMoveItemsToReceivedInvocations.append((items: items, parentFolder: parentFolder)) + scheduleMoveItemsToClosure?(items, parentFolder) + } + //MARK: - scheduleRenameFolder + + var scheduleRenameFolderAtNameCallsCount = 0 + var scheduleRenameFolderAtNameCalled: Bool { + return scheduleRenameFolderAtNameCallsCount > 0 + } + var scheduleRenameFolderAtNameReceivedArguments: (relativePath: String, name: String)? + var scheduleRenameFolderAtNameReceivedInvocations: [(relativePath: String, name: String)] = [] + var scheduleRenameFolderAtNameClosure: ((String, String) -> Void)? + func scheduleRenameFolder(at relativePath: String, name: String) { + scheduleRenameFolderAtNameCallsCount += 1 + scheduleRenameFolderAtNameReceivedArguments = (relativePath: relativePath, name: name) + scheduleRenameFolderAtNameReceivedInvocations.append((relativePath: relativePath, name: name)) + scheduleRenameFolderAtNameClosure?(relativePath, name) + } + //MARK: - scheduleSetBookmark + + var scheduleSetBookmarkRelativePathTimeNoteCallsCount = 0 + var scheduleSetBookmarkRelativePathTimeNoteCalled: Bool { + return scheduleSetBookmarkRelativePathTimeNoteCallsCount > 0 + } + var scheduleSetBookmarkRelativePathTimeNoteReceivedArguments: (relativePath: String, time: Double, note: String?)? + var scheduleSetBookmarkRelativePathTimeNoteReceivedInvocations: [(relativePath: String, time: Double, note: String?)] = [] + var scheduleSetBookmarkRelativePathTimeNoteClosure: ((String, Double, String?) -> Void)? + func scheduleSetBookmark(relativePath: String, time: Double, note: String?) { + scheduleSetBookmarkRelativePathTimeNoteCallsCount += 1 + scheduleSetBookmarkRelativePathTimeNoteReceivedArguments = (relativePath: relativePath, time: time, note: note) + scheduleSetBookmarkRelativePathTimeNoteReceivedInvocations.append((relativePath: relativePath, time: time, note: note)) + scheduleSetBookmarkRelativePathTimeNoteClosure?(relativePath, time, note) + } + //MARK: - scheduleDeleteBookmark + + var scheduleDeleteBookmarkCallsCount = 0 + var scheduleDeleteBookmarkCalled: Bool { + return scheduleDeleteBookmarkCallsCount > 0 + } + var scheduleDeleteBookmarkReceivedBookmark: SimpleBookmark? + var scheduleDeleteBookmarkReceivedInvocations: [SimpleBookmark] = [] + var scheduleDeleteBookmarkClosure: ((SimpleBookmark) -> Void)? + func scheduleDeleteBookmark(_ bookmark: SimpleBookmark) { + scheduleDeleteBookmarkCallsCount += 1 + scheduleDeleteBookmarkReceivedBookmark = bookmark + scheduleDeleteBookmarkReceivedInvocations.append(bookmark) + scheduleDeleteBookmarkClosure?(bookmark) + } + //MARK: - getAllQueuedJobs + + var getAllQueuedJobsCallsCount = 0 + var getAllQueuedJobsCalled: Bool { + return getAllQueuedJobsCallsCount > 0 + } + var getAllQueuedJobsReturnValue: [QueuedJobInfo]! + var getAllQueuedJobsClosure: (() -> [QueuedJobInfo])? + func getAllQueuedJobs() -> [QueuedJobInfo] { + getAllQueuedJobsCallsCount += 1 + if let getAllQueuedJobsClosure = getAllQueuedJobsClosure { + return getAllQueuedJobsClosure() + } else { + return getAllQueuedJobsReturnValue + } + } + //MARK: - cancelAllJobs + + var cancelAllJobsCallsCount = 0 + var cancelAllJobsCalled: Bool { + return cancelAllJobsCallsCount > 0 + } + var cancelAllJobsClosure: (() -> Void)? + func cancelAllJobs() { + cancelAllJobsCallsCount += 1 + cancelAllJobsClosure?() + } +} diff --git a/BookPlayer/Player/Controls Screen/PlayerControlsViewModel.swift b/BookPlayer/Player/Controls Screen/PlayerControlsViewModel.swift index 31c0432cf..e8df7b658 100644 --- a/BookPlayer/Player/Controls Screen/PlayerControlsViewModel.swift +++ b/BookPlayer/Player/Controls Screen/PlayerControlsViewModel.swift @@ -43,7 +43,7 @@ class PlayerControlsViewModel: BaseViewModel { func handleBoostVolumeToggle(flag: Bool) { UserDefaults.standard.set(flag, forKey: Constants.UserDefaults.boostVolumeEnabled.rawValue) - self.playerManager.boostVolume = flag + self.playerManager.setBoostVolume(flag) } func roundSpeedValue(_ value: Float) -> Float { diff --git a/BookPlayer/Player/PlayerManager.swift b/BookPlayer/Player/PlayerManager.swift index fddc85042..e3c539728 100755 --- a/BookPlayer/Player/PlayerManager.swift +++ b/BookPlayer/Player/PlayerManager.swift @@ -13,12 +13,11 @@ import Foundation import MediaPlayer import WidgetKit -// swiftlint:disable file_length - -public protocol PlayerManagerProtocol: NSObjectProtocol { +// swiftlint:disable:next file_length +/// sourcery: AutoMockable +public protocol PlayerManagerProtocol { var currentItem: PlayableItem? { get set } var currentSpeed: Float { get set } - var boostVolume: Bool { get set } var isPlaying: Bool { get } func load(_ item: PlayableItem, autoplay: Bool) @@ -36,6 +35,7 @@ public protocol PlayerManagerProtocol: NSObjectProtocol { func jumpToChapter(_ chapter: PlayableChapter) func markAsCompleted(_ flag: Bool) func setSpeed(_ newValue: Float) + func setBoostVolume(_ newValue: Bool) func currentSpeedPublisher() -> Published.Publisher func isPlayingPublisher() -> AnyPublisher @@ -649,6 +649,10 @@ extension PlayerManager { } } + func setBoostVolume(_ newValue: Bool) { + self.boostVolume = newValue + } + // swiftlint:disable block_based_kvo // Using this instead of new form, because the new one wouldn't work properly on AVPlayerItem override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey: Any]?, context: UnsafeMutableRawPointer?) { diff --git a/BookPlayer/Player/SpeedService.swift b/BookPlayer/Player/SpeedService.swift index 8a7885ed5..e99ce9a7c 100755 --- a/BookPlayer/Player/SpeedService.swift +++ b/BookPlayer/Player/SpeedService.swift @@ -10,6 +10,7 @@ import BookPlayerKit import Combine import Foundation +/// sourcery: AutoMockable public protocol SpeedServiceProtocol { func setSpeed(_ newValue: Float, relativePath: String?) func getSpeed(relativePath: String?) -> Float diff --git a/BookPlayer/Services/ActionParserService.swift b/BookPlayer/Services/ActionParserService.swift index 5f478dc01..0e44a07c3 100644 --- a/BookPlayer/Services/ActionParserService.swift +++ b/BookPlayer/Services/ActionParserService.swift @@ -114,7 +114,7 @@ class ActionParserService { isOn, forKey: Constants.UserDefaults.boostVolumeEnabled.rawValue ) - playerManager.boostVolume = isOn + playerManager.setBoostVolume(isOn) } private class func handleFileImportAction(_ action: Action) { diff --git a/BookPlayer/Settings/Player Settings Screen/PlayerSettingsViewController.swift b/BookPlayer/Settings/Player Settings Screen/PlayerSettingsViewController.swift index c74104216..cfbbe3bab 100644 --- a/BookPlayer/Settings/Player Settings Screen/PlayerSettingsViewController.swift +++ b/BookPlayer/Settings/Player Settings Screen/PlayerSettingsViewController.swift @@ -192,7 +192,7 @@ class PlayerSettingsViewController: UITableViewController, Storyboarded { guard let playerManager = AppDelegate.shared?.playerManager else { return } - playerManager.boostVolume = self.boostVolumeSwitch.isOn + playerManager.setBoostVolume(self.boostVolumeSwitch.isOn) } @objc func globalSpeedToggleDidChange() { diff --git a/BookPlayerTests/Coordinators/ItemListCoordinatorTests.swift b/BookPlayerTests/Coordinators/ItemListCoordinatorTests.swift index 7ea93aaee..b01d6f072 100644 --- a/BookPlayerTests/Coordinators/ItemListCoordinatorTests.swift +++ b/BookPlayerTests/Coordinators/ItemListCoordinatorTests.swift @@ -8,6 +8,7 @@ import Foundation +import Combine @testable import BookPlayer @testable import BookPlayerKit import XCTest @@ -16,18 +17,26 @@ class LibraryListCoordinatorTests: XCTestCase { var libraryListCoordinator: LibraryListCoordinator! var dataManager: DataManager! + @Published var placeholder: PlayableItem? + @Published var speed: Float = 1 + override func setUp() { let coreServices = AppDelegate.shared!.createCoreServicesIfNeeded(from: CoreDataStack(testPath: "/dev/null")) self.dataManager = coreServices.dataManager let libraryService = coreServices.libraryService + _ = libraryService.getLibrary() + let playerManagerMock = PlayerManagerProtocolMock() + playerManagerMock.currentItemPublisherReturnValue = $placeholder + playerManagerMock.currentSpeedPublisherReturnValue = $speed + playerManagerMock.isPlayingPublisherReturnValue = Just(false).eraseToAnyPublisher() self.libraryListCoordinator = LibraryListCoordinator( navigationController: UINavigationController(), - playerManager: PlayerManagerMock(), + playerManager: playerManagerMock, importManager: ImportManager(libraryService: libraryService), libraryService: libraryService, playbackService: coreServices.playbackService, - syncService: SyncServiceMock() + syncService: SyncServiceProtocolMock() ) self.libraryListCoordinator.start() @@ -66,18 +75,22 @@ class LibraryListCoordinatorTests: XCTestCase { class FolderListCoordinatorTests: XCTestCase { var folderListCoordinator: FolderListCoordinator! + @Published var placeholder: PlayableItem? + override func setUp() { let dataManager = DataManager(coreDataStack: CoreDataStack(testPath: "/dev/null")) let libraryService = LibraryService(dataManager: dataManager) let folder = try! StubFactory.folder(dataManager: dataManager, title: "folder 1") + let playerManagerMock = PlayerManagerProtocolMock() + playerManagerMock.currentItemPublisherReturnValue = $placeholder self.folderListCoordinator = FolderListCoordinator( navigationController: UINavigationController(), folderRelativePath: folder.relativePath, - playerManager: PlayerManagerMock(), + playerManager: playerManagerMock, libraryService: libraryService, playbackService: PlaybackService(libraryService: libraryService), - syncService: SyncServiceMock() + syncService: SyncServiceProtocolMock() ) self.folderListCoordinator.start() diff --git a/BookPlayerTests/Coordinators/PlayerCoordinatorTests.swift b/BookPlayerTests/Coordinators/PlayerCoordinatorTests.swift index 0ea675a71..d45223275 100644 --- a/BookPlayerTests/Coordinators/PlayerCoordinatorTests.swift +++ b/BookPlayerTests/Coordinators/PlayerCoordinatorTests.swift @@ -7,6 +7,7 @@ // import Foundation +import Combine @testable import BookPlayer @testable import BookPlayerKit @@ -15,14 +16,21 @@ import XCTest class PlayerCoordinatorTests: XCTestCase { var playerCoordinator: PlayerCoordinator! + @Published var placeholder: PlayableItem? + @Published var speed: Float = 1 + override func setUp() { let dataManager = DataManager(coreDataStack: CoreDataStack(testPath: "/dev/null")) let libraryService = LibraryService(dataManager: dataManager) + let playerManagerMock = PlayerManagerProtocolMock() + playerManagerMock.currentItemPublisherReturnValue = $placeholder + playerManagerMock.currentSpeedPublisherReturnValue = $speed + playerManagerMock.isPlayingPublisherReturnValue = Just(true).eraseToAnyPublisher() self.playerCoordinator = PlayerCoordinator( - playerManager: PlayerManagerMock(), + playerManager: playerManagerMock, libraryService: libraryService, - syncService: SyncServiceMock(), + syncService: SyncServiceProtocolMock(), presentingViewController: UINavigationController() ) self.playerCoordinator.start() diff --git a/BookPlayerTests/Coordinators/ProfileCoordinatorTests.swift b/BookPlayerTests/Coordinators/ProfileCoordinatorTests.swift index 60e11a849..44c3cadba 100644 --- a/BookPlayerTests/Coordinators/ProfileCoordinatorTests.swift +++ b/BookPlayerTests/Coordinators/ProfileCoordinatorTests.swift @@ -7,6 +7,7 @@ // import Foundation +import Combine @testable import BookPlayer @testable import BookPlayerKit @@ -15,14 +16,20 @@ import XCTest class ProfileCoordinatorTests: XCTestCase { var sut: ProfileCoordinator! + @Published var placeholder: PlayableItem? + override func setUp() { let dataManager = DataManager(coreDataStack: CoreDataStack(testPath: "/dev/null")) let libraryService = LibraryService(dataManager: dataManager) + let playerManagerMock = PlayerManagerProtocolMock() + playerManagerMock.currentItemPublisherReturnValue = $placeholder + let syncServiceMock = SyncServiceProtocolMock() + syncServiceMock.queuedJobsCount = 0 self.sut = ProfileCoordinator( libraryService: libraryService, - playerManager: PlayerManagerMock(), + playerManager: playerManagerMock, accountService: AccountServiceMock(account: nil), - syncService: SyncServiceMock(), + syncService: syncServiceMock, navigationController: UINavigationController() ) self.sut.start() diff --git a/BookPlayerTests/ItemListViewModelTests.swift b/BookPlayerTests/ItemListViewModelTests.swift index e053b13ca..e778ae2c5 100644 --- a/BookPlayerTests/ItemListViewModelTests.swift +++ b/BookPlayerTests/ItemListViewModelTests.swift @@ -18,16 +18,20 @@ class ItemListViewModelTests: XCTestCase { var subscription: AnyCancellable? var dataManager: DataManager! + @Published var placeholder: PlayableItem? + override func setUp() { self.dataManager = DataManager(coreDataStack: CoreDataStack(testPath: "/dev/null")) let libraryService = LibraryService(dataManager: dataManager) + let playerManagerMock = PlayerManagerProtocolMock() + playerManagerMock.currentItemPublisherReturnValue = $placeholder self.sut = ItemListViewModel( folderRelativePath: nil, - playerManager: PlayerManagerMock(), + playerManager: playerManagerMock, libraryService: libraryService, - playbackService: EmptyPlaybackServiceMock(), - syncService: SyncServiceMock(), + playbackService: PlaybackServiceProtocolMock(), + syncService: SyncServiceProtocolMock(), themeAccent: .blue ) diff --git a/BookPlayerTests/MiniPlayerViewModelTests.swift b/BookPlayerTests/MiniPlayerViewModelTests.swift index 478580b3b..7cd253ee2 100644 --- a/BookPlayerTests/MiniPlayerViewModelTests.swift +++ b/BookPlayerTests/MiniPlayerViewModelTests.swift @@ -15,10 +15,14 @@ import XCTest class MiniPlayerViewModelTests: XCTestCase { var sut: MiniPlayerViewModel! - var playerMock: PlayerManagerMock! + var playerMock: PlayerManagerProtocolMock! + + @Published var placeholder: PlayableItem? override func setUp() { - self.playerMock = PlayerManagerMock() + self.playerMock = PlayerManagerProtocolMock() + playerMock.currentItemPublisherReturnValue = $placeholder + playerMock.hasLoadedBookReturnValue = true self.sut = MiniPlayerViewModel(playerManager: self.playerMock) } @@ -42,6 +46,6 @@ class MiniPlayerViewModelTests: XCTestCase { func testPlayPause() { self.sut.handlePlayPauseAction() - XCTAssert(self.playerMock.didPlayPause == true) + XCTAssert(playerMock.playPauseCalled == true) } } diff --git a/BookPlayerTests/Mocks/EmptyLibraryServiceMock.swift b/BookPlayerTests/Mocks/EmptyLibraryServiceMock.swift deleted file mode 100644 index bb64aa6ed..000000000 --- a/BookPlayerTests/Mocks/EmptyLibraryServiceMock.swift +++ /dev/null @@ -1,239 +0,0 @@ -// -// EmptyLibraryServiceMock.swift -// BookPlayerTests -// -// Created by gianni.carlo on 18/5/22. -// Copyright © 2022 Tortuga Power. All rights reserved. -// - -import AVFoundation -import BookPlayerKit -import Foundation -import Combine - -/// Empty class meant to be subclassed to adjust service for test conditions -class EmptyLibraryServiceMock: LibraryServiceProtocol { - func renameBook(at relativePath: String, with newTitle: String) { } - - func renameFolder(at relativePath: String, with newTitle: String) throws -> String { return "" } - - var metadataUpdatePublisher: AnyPublisher<[String: Any], Never> = PassthroughSubject<[String: Any], Never>() - .eraseToAnyPublisher() - - func getLibraryLastItem() -> BookPlayerKit.SimpleLibraryItem? { - return nil - } - - func getLibraryCurrentTheme() -> BookPlayerKit.SimpleTheme? { - return nil - } - - func setLibraryTheme(with simpleTheme: BookPlayerKit.SimpleTheme) { } - - func getLastPlayedItems(limit: Int?) -> [BookPlayerKit.SimpleLibraryItem]? { - return nil - } - - func getSimpleItem(with relativePath: String) -> BookPlayerKit.SimpleLibraryItem? { - return nil - } - - func findFirstItem(in parentFolder: String?, isUnfinished: Bool?) -> BookPlayerKit.SimpleLibraryItem? { - return nil - } - - func findFirstItem(in parentFolder: String?, beforeRank: Int16?) -> BookPlayerKit.SimpleLibraryItem? { - return nil - } - - func findFirstItem(in parentFolder: String?, afterRank: Int16?, isUnfinished: Bool?) -> BookPlayerKit.SimpleLibraryItem? { - return nil - } - - func getLibraryReference() -> BookPlayerKit.Library { - return Library() - } - - func getItemReference(with relativePath: String) -> BookPlayerKit.LibraryItem? { - return nil - } - - func getItems(notIn relativePaths: [String], parentFolder: String?) -> [BookPlayerKit.SimpleLibraryItem]? { - return nil - } - - func insertItems(from files: [URL]) -> [SimpleLibraryItem] { - return [] - } - - func moveItems(_ items: [String], inside relativePath: String?) throws { } - - func delete(_ items: [BookPlayerKit.SimpleLibraryItem], mode: BookPlayerKit.DeleteMode) throws { } - - func loadChaptersIfNeeded(relativePath: String, asset: AVAsset) { } - - func getTotalListenedTime() -> TimeInterval { return 0 } - - func renameItem(at relativePath: String, with newTitle: String) throws -> String { return "" } - - func updateDetails(at relativePath: String, details: String) {} - - func filterContents( - at relativePath: String?, - query: String?, - scope: SimpleItemType, - limit: Int?, - offset: Int? - ) -> [SimpleLibraryItem]? { - return [] - } - - func rebuildFolderDetails(_ relativePath: String) {} - - func recursiveFolderProgressUpdate(from relativePath: String) {} - - func addBook(from item: SyncableItem, parentFolder: String?) {} - - func addFolder(from item: SyncableItem, type: ItemType, parentFolder: String?) {} - - func getItems(notIn relativePaths: [String], parentFolder: String?) throws -> [String] { return [] } - - func updatePlaybackTime(relativePath: String, time: Double, date: Date, scheduleSave: Bool) {} - - func getLibrary() -> Library { - return Library() - } - - func getTheme(with title: String) -> Theme? { - return nil - } - - func setLibraryLastBook(with relativePath: String?) {} - - func createTheme(params: [String: Any]) -> SimpleTheme { - return SimpleTheme(with: Theme()) - } - - func createBook(from url: URL) -> Book { - return Book() - } - - func getChapters(from relativePath: String) -> [SimpleChapter]? { - return nil - } - - func getItem(with relativePath: String) -> LibraryItem? { - return nil - } - - func findBooks(containing fileURL: URL) -> [Book]? { - return nil - } - - func updateFolder(at relativePath: String, type: SimpleItemType) throws {} - - func findFolder(with fileURL: URL) -> Folder? { - return nil - } - - func findFolder(with relativePath: String) -> Folder? { - return nil - } - - func hasLibraryLinked(item: LibraryItem) -> Bool { - return false - } - - func createFolder(with title: String, inside relativePath: String?) throws -> SimpleLibraryItem { - return SimpleLibraryItem( - title: "", - details: "", - speed: 1, - currentTime: 0, - duration: 0, - percentCompleted: 0, - isFinished: false, - relativePath: "", - remoteURL: nil, - artworkURL: nil, - orderRank: 0, - parentFolder: nil, - originalFileName: "", - lastPlayDate: nil, - type: .folder - ) - } - - func fetchContents(at relativePath: String?, limit: Int?, offset: Int?) -> [SimpleLibraryItem]? { - return nil - } - - func getMaxItemsCount(at relativePath: String?) -> Int { - return 0 - } - - func sortContents(at relativePath: String?, by type: SortType) {} - - func reorderItem( - with relativePath: String, - inside folderRelativePath: String?, - sourceIndexPath: IndexPath, - destinationIndexPath: IndexPath - ) {} - - func updatePlaybackTime(relativePath: String, time: Double) {} - - func updateBookSpeed(at relativePath: String, speed: Float) {} - - func getItemSpeed(at relativePath: String) -> Float { - return 1 - } - - func updateBookLastPlayDate(at relativePath: String, date: Date) {} - - func markAsFinished(flag: Bool, relativePath: String) {} - - func jumpToStart(relativePath: String) {} - - func getCurrentPlaybackRecord() -> PlaybackRecord { - return PlaybackRecord() - } - - func getPlaybackRecords(from startDate: Date, to endDate: Date) -> [PlaybackRecord]? { - return nil - } - - func recordTime(_ playbackRecord: PlaybackRecord) {} - - func getBookmarks(of type: BookmarkType, relativePath: String) -> [SimpleBookmark]? { - return nil - } - - func getBookmark(at time: Double, relativePath: String, type: BookmarkType) -> SimpleBookmark? { - return nil - } - - func createBookmark(at time: Double, relativePath: String, type: BookmarkType) -> SimpleBookmark? { - return nil - } - - func addNote(_ note: String, bookmark: SimpleBookmark) {} - - func deleteBookmark(_ bookmark: SimpleBookmark) {} - - func renameItem(at relativePath: String, with newTitle: String) {} - - func insertItems(from files: [URL], into folder: Folder?, library: Library, processedItems: [LibraryItem]?) -> [LibraryItem] { - return [] - } - - func handleDirectory(item: URL, folder: Folder, library: Library) {} - - func moveItems(_ items: [LibraryItem], inside relativePath: String?, moveFiles: Bool) throws {} - - func delete(_ items: [LibraryItem], mode: DeleteMode) throws {} - - func getItemProperty(_ property: String, relativePath: String) -> Any? { - return nil - } -} diff --git a/BookPlayerTests/Mocks/EmptyPlaybackServiceMock.swift b/BookPlayerTests/Mocks/EmptyPlaybackServiceMock.swift deleted file mode 100644 index b5f4d137f..000000000 --- a/BookPlayerTests/Mocks/EmptyPlaybackServiceMock.swift +++ /dev/null @@ -1,40 +0,0 @@ -// -// EmptyPlaybackServiceMock.swift -// BookPlayerTests -// -// Created by gianni.carlo on 18/5/22. -// Copyright © 2022 Tortuga Power. All rights reserved. -// - -import BookPlayerKit -import Foundation - -/// Empty class meant to be subclassed to adjust service for test conditions -class EmptyPlaybackServiceMock: PlaybackServiceProtocol { - func getFirstPlayableItem(in folder: BookPlayerKit.SimpleLibraryItem, isUnfinished: Bool?) throws -> BookPlayerKit.PlayableItem? { - return nil - } - - func getPlayableItem(from item: BookPlayerKit.SimpleLibraryItem) throws -> BookPlayerKit.PlayableItem? { - return nil - } - - func updatePlaybackTime(item: PlayableItem, time: Double) {} - - func getPlayableItem(before relativePath: String, parentFolder: String?) -> PlayableItem? { - return nil - } - - func getNextChapter(from item: PlayableItem) -> PlayableChapter? { - return nil - } - - func getPlayableItem( - after relativePath: String, - parentFolder: String?, - autoplayed: Bool, - restartFinished: Bool - ) -> PlayableItem? { - return nil - } -} diff --git a/BookPlayerTests/Mocks/EmptySpeedServiceMock.swift b/BookPlayerTests/Mocks/EmptySpeedServiceMock.swift deleted file mode 100644 index 9ec268ff3..000000000 --- a/BookPlayerTests/Mocks/EmptySpeedServiceMock.swift +++ /dev/null @@ -1,21 +0,0 @@ -// -// EmptySpeedServiceMock.swift -// BookPlayerTests -// -// Created by gianni.carlo on 18/5/22. -// Copyright © 2022 Tortuga Power. All rights reserved. -// - -import BookPlayerKit -import Foundation - -@testable import BookPlayer - -/// Empty class meant to be subclassed to adjust service for test conditions -class EmptySpeedServiceMock: SpeedServiceProtocol { - func setSpeed(_ newValue: Float, relativePath: String?) {} - - func getSpeed(relativePath: String?) -> Float { - return 1 - } -} diff --git a/BookPlayerTests/Mocks/KeychainServiceMock.swift b/BookPlayerTests/Mocks/KeychainServiceMock.swift deleted file mode 100644 index 83ca6de59..000000000 --- a/BookPlayerTests/Mocks/KeychainServiceMock.swift +++ /dev/null @@ -1,26 +0,0 @@ -// -// KeychainServiceMock.swift -// BookPlayerTests -// -// Created by gianni.carlo on 24/4/22. -// Copyright © 2022 Tortuga Power. All rights reserved. -// - -import Foundation -import BookPlayerKit - -class KeychainServiceMock: KeychainServiceProtocol { - var accessToken: String? - - func setAccessToken(_ token: String) throws { - accessToken = token - } - - func getAccessToken() throws -> String? { - return accessToken - } - - func removeAccessToken() throws { - accessToken = nil - } -} diff --git a/BookPlayerTests/Mocks/PlayerManagerMock.swift b/BookPlayerTests/Mocks/PlayerManagerMock.swift deleted file mode 100644 index c3091fdd3..000000000 --- a/BookPlayerTests/Mocks/PlayerManagerMock.swift +++ /dev/null @@ -1,77 +0,0 @@ -// -// PlayerManagerMock.swift -// BookPlayerTests -// -// Created by Gianni Carlo on 11/20/21. -// Copyright © 2021 Tortuga Power. All rights reserved. -// - -import BookPlayerKit -import Combine -import Foundation -@testable import BookPlayer - -class PlayerManagerMock: NSObject, PlayerManagerProtocol { - @Published var currentItem: PlayableItem? - @Published var currentSpeed: Float = 1.0 - var didPlayPause = false - var boostVolume = false - var isPlaying = false - - func playPause() { - self.isPlaying = !self.isPlaying - self.didPlayPause = true - } - - func isPlayingPublisher() -> AnyPublisher { - return Just(true).eraseToAnyPublisher() - } - - func currentItemPublisher() -> Published.Publisher { - return self.$currentItem - } - - func play() {} - - func pause(fade: Bool) {} - - func stop() {} - - func load(_ item: PlayableItem, autoplay: Bool) { - NotificationCenter.default.post(name: .bookReady, object: nil, userInfo: ["loaded": true]) - } - - func hasLoadedBook() -> Bool { return true } - - func rewind() {} - - func forward() {} - - func jumpTo(_ time: Double, recordBookmark: Bool) {} - - func jumpToChapter(_ chapter: PlayableChapter) {} - - func markAsCompleted(_ flag: Bool) {} - - func playPreviousItem() {} - - func playNextItem(autoPlayed: Bool) {} - - func playItem(_ item: PlayableItem) {} - - func getSpeedOptions() -> [Float] { return [] } - - func getCurrentSpeed() -> Float { return 1.0 } - - func currentSpeedPublisher() -> AnyPublisher { - return self.$currentSpeed.eraseToAnyPublisher() - } - - func setSpeed(_ newValue: Float) { - self.currentSpeed = newValue - } - - func currentSpeedPublisher() -> Published.Publisher { - return self.$currentSpeed - } -} diff --git a/BookPlayerTests/Mocks/SyncServiceMock.swift b/BookPlayerTests/Mocks/SyncServiceMock.swift deleted file mode 100644 index a52d4f3f7..000000000 --- a/BookPlayerTests/Mocks/SyncServiceMock.swift +++ /dev/null @@ -1,70 +0,0 @@ -// -// SyncServiceMock.swift -// BookPlayerTests -// -// Created by gianni.carlo on 23/4/22. -// Copyright © 2022 Tortuga Power. All rights reserved. -// - -import BookPlayerKit -import Foundation -import RevenueCat - -class SyncServiceMock: SyncServiceProtocol { - var queuedJobsCount: Int = 0 - - func getAllQueuedJobs() -> [BookPlayerKit.QueuedJobInfo] { - return [] - } - - func uploadArtwork(relativePath: String, data: Data) async throws { } - - func syncBookmarksList(relativePath: String) async throws -> [BookPlayerKit.SimpleBookmark]? { - return nil - } - - func scheduleUpload(items: [BookPlayerKit.SimpleLibraryItem]) throws {} - - func scheduleSetBookmark(relativePath: String, time: Double, note: String?) {} - - func scheduleDeleteBookmark(_ bookmark: BookPlayerKit.SimpleBookmark) {} - - func scheduleMove(items: [String], to parentFolder: String?) {} - - func scheduleDelete(_ items: [BookPlayerKit.SimpleLibraryItem], mode: BookPlayerKit.DeleteMode) {} - - func syncListContents(at relativePath: String?) async throws -> ([BookPlayerKit.SyncableItem], BookPlayerKit.SyncableItem?)? { - return nil - } - - func syncLibraryContents() async throws -> ([BookPlayerKit.SyncableItem], BookPlayerKit.SyncableItem?) { - return ([], nil) - } - - func getRemoteFileURLs(of relativePath: String, type: BookPlayerKit.SimpleItemType) async throws -> [BookPlayerKit.RemoteFileURL] { - return [] - } - - func downloadRemoteFiles(for relativePath: String, type: BookPlayerKit.SimpleItemType, delegate: URLSessionTaskDelegate) async throws -> [URLSessionDownloadTask] { - return [] - } - - var isActive: Bool = false - - func fetchListContents(at relativePath: String?, shouldSync: Bool) async throws -> ([SyncableItem], SyncableItem?) { return ([], nil) } - - func cancelAllJobs() {} - - func accountUpdated(_ customerInfo: CustomerInfo) {} - - func getRemoteFileURL(of relativePath: String) async throws -> URL { - return URL(string: "https://google.com")! - } - - func downloadRemoteFile( - for relativePath: String, - delegate: URLSessionTaskDelegate - ) async throws -> URLSessionDownloadTask { - return URLSessionDownloadTask() - } -} diff --git a/BookPlayerTests/PlayerManagerTests.swift b/BookPlayerTests/PlayerManagerTests.swift index 0adb5a83a..862206e9d 100644 --- a/BookPlayerTests/PlayerManagerTests.swift +++ b/BookPlayerTests/PlayerManagerTests.swift @@ -22,10 +22,10 @@ class PlayerManagerTests: XCTestCase { UserDefaults.standard.removeObject(forKey: Constants.UserDefaults.chapterContextEnabled.rawValue) UserDefaults.standard.removeObject(forKey: Constants.UserDefaults.remainingTimeEnabled.rawValue) self.sut = PlayerManager( - libraryService: EmptyLibraryServiceMock(), - playbackService: EmptyPlaybackServiceMock(), - syncService: SyncServiceMock(), - speedService: EmptySpeedServiceMock(), + libraryService: LibraryServiceProtocolMock(), + playbackService: PlaybackServiceProtocolMock(), + syncService: SyncServiceProtocolMock(), + speedService: SpeedServiceProtocolMock(), socketService: SocketService() ) } diff --git a/BookPlayerTests/Services/AccountServiceTests.swift b/BookPlayerTests/Services/AccountServiceTests.swift index 4dc2da1fd..603077d6a 100644 --- a/BookPlayerTests/Services/AccountServiceTests.swift +++ b/BookPlayerTests/Services/AccountServiceTests.swift @@ -15,12 +15,12 @@ import XCTest class AccountServiceTests: XCTestCase { var sut: AccountService! - var mockKeychain: KeychainServiceMock! + var mockKeychain: KeychainServiceProtocolMock! override func setUp() { DataTestUtils.clearFolderContents(url: DataManager.getProcessedFolderURL()) let dataManager = DataManager(coreDataStack: CoreDataStack(testPath: "/dev/null")) - self.mockKeychain = KeychainServiceMock() + self.mockKeychain = KeychainServiceProtocolMock() self.sut = AccountService(dataManager: dataManager, keychain: self.mockKeychain) } @@ -96,7 +96,7 @@ class AccountServiceTests: XCTestCase { func testDeleteAccoount() async throws { let dataManager = DataManager(coreDataStack: CoreDataStack(testPath: "/dev/null")) let mockResponse = DeleteResponse(message: "success") - let keychainMock = KeychainServiceMock() + let keychainMock = KeychainServiceProtocolMock() self.sut = AccountService( dataManager: dataManager, diff --git a/BookPlayerTests/Services/LibraryServiceTests.swift b/BookPlayerTests/Services/LibraryServiceTests.swift index e2c8eaf7b..aca4b2351 100644 --- a/BookPlayerTests/Services/LibraryServiceTests.swift +++ b/BookPlayerTests/Services/LibraryServiceTests.swift @@ -608,7 +608,7 @@ class LibraryServiceTests: XCTestCase { XCTAssert(fetchedBookmark == nil) } - func testRenameBookItem() throws { + func testRenameBookItem() { let book = StubFactory.book( dataManager: self.sut.dataManager, title: "test-book1", diff --git a/Shared/Services/KeychainService.swift b/Shared/Services/KeychainService.swift index 953c4c709..4103a43bb 100644 --- a/Shared/Services/KeychainService.swift +++ b/Shared/Services/KeychainService.swift @@ -9,6 +9,7 @@ import Foundation import Security +/// sourcery: AutoMockable public protocol KeychainServiceProtocol { func setAccessToken(_ token: String) throws func getAccessToken() throws -> String? diff --git a/Shared/Services/LibraryService.swift b/Shared/Services/LibraryService.swift index aa6231cbf..f7b670d87 100644 --- a/Shared/Services/LibraryService.swift +++ b/Shared/Services/LibraryService.swift @@ -11,6 +11,7 @@ import CoreData import Foundation import Combine +/// sourcery: AutoMockable public protocol LibraryServiceProtocol { /// Metadata publisher that collects changes during 10 seconds before normalizing the payload var metadataUpdatePublisher: AnyPublisher<[String: Any], Never> { get } diff --git a/Shared/Services/PlaybackService.swift b/Shared/Services/PlaybackService.swift index 31b640179..e3f20fbee 100644 --- a/Shared/Services/PlaybackService.swift +++ b/Shared/Services/PlaybackService.swift @@ -8,6 +8,7 @@ import Foundation +/// sourcery: AutoMockable public protocol PlaybackServiceProtocol { func updatePlaybackTime(item: PlayableItem, time: Double) func getPlayableItem(before relativePath: String, parentFolder: String?) -> PlayableItem? diff --git a/Shared/Services/Sync/SyncService.swift b/Shared/Services/Sync/SyncService.swift index 6cdaf8439..a96a597df 100644 --- a/Shared/Services/Sync/SyncService.swift +++ b/Shared/Services/Sync/SyncService.swift @@ -10,6 +10,7 @@ import Combine import Foundation import RevenueCat +/// sourcery: AutoMockable public protocol SyncServiceProtocol { /// Flag to check if it can sync or not var isActive: Bool { get set } diff --git a/Templates/AutoMockable.stencil b/Templates/AutoMockable.stencil new file mode 100644 index 000000000..2f59ec711 --- /dev/null +++ b/Templates/AutoMockable.stencil @@ -0,0 +1,118 @@ + +import Foundation +#if os(iOS) || os(tvOS) || os(watchOS) +import UIKit +import AVFoundation +#elseif os(OSX) +import AppKit +#endif + +{% for import in argument.autoMockableImports %} +import {{ import }} +{% endfor %} +{% for import in argument.autoMockableTestableImports %} +@testable import {{ import }} +{% endfor %} +{% macro swiftifyMethodName name %}{{ name | replace:"(","_" | replace:")","" | replace:":","_" | replace:"`","" | snakeToCamelCase | lowerFirstWord }}{% endmacro %} +{% macro methodThrowableErrorDeclaration method %} + var {% call swiftifyMethodName method.selectorName %}ThrowableError: Error? +{% endmacro %} +{% macro methodThrowableErrorUsage method %} + if let error = {% call swiftifyMethodName method.selectorName %}ThrowableError { + throw error + } +{% endmacro %} +{% macro methodReceivedParameters method %} + {%if method.parameters.count == 1 %} + {% call swiftifyMethodName method.selectorName %}Received{% for param in method.parameters %}{{ param.name|upperFirstLetter }} = {{ param.name }}{% endfor %} + {% call swiftifyMethodName method.selectorName %}ReceivedInvocations.append({% for param in method.parameters %}{{ param.name }}){% endfor %} + {% else %} + {% if not method.parameters.count == 0 %} + {% call swiftifyMethodName method.selectorName %}ReceivedArguments = ({% for param in method.parameters %}{{ param.name }}: {{ param.name }}{% if not forloop.last%}, {% endif %}{% endfor %}) + {% call swiftifyMethodName method.selectorName %}ReceivedInvocations.append(({% for param in method.parameters %}{{ param.name }}: {{ param.name }}{% if not forloop.last%}, {% endif %}{% endfor %})) + {% endif %} + {% endif %} +{% endmacro %} +{% macro methodClosureName method %}{% call swiftifyMethodName method.selectorName %}Closure{% endmacro %} +{% macro closureReturnTypeName method %}{% if method.isOptionalReturnType %}{{ method.unwrappedReturnTypeName }}?{% else %}{{ method.returnTypeName }}{% endif %}{% endmacro %} +{% macro methodClosureDeclaration method %} + var {% call methodClosureName method %}: (({% for param in method.parameters %}{{ param.typeName }}{% if not forloop.last %}, {% endif %}{% endfor %}) {% if method.isAsync %}async {% endif %}{% if method.throws %}throws {% endif %}-> {% if method.isInitializer %}Void{% else %}{% call closureReturnTypeName method %}{% endif %})? +{% endmacro %} +{% macro methodClosureCallParameters method %}{% for param in method.parameters %}{{ param.name }}{% if not forloop.last %}, {% endif %}{% endfor %}{% endmacro %} +{% macro mockMethod method %} + //MARK: - {{ method.shortName }} + + {% if method.throws %} + {% call methodThrowableErrorDeclaration method %} + {% endif %} + {% if not method.isInitializer %} + var {% call swiftifyMethodName method.selectorName %}CallsCount = 0 + var {% call swiftifyMethodName method.selectorName %}Called: Bool { + return {% call swiftifyMethodName method.selectorName %}CallsCount > 0 + } + {% endif %} + {% if method.parameters.count == 1 %} + var {% call swiftifyMethodName method.selectorName %}Received{% for param in method.parameters %}{{ param.name|upperFirstLetter }}: {{ '(' if param.isClosure }}{{ param.typeName.unwrappedTypeName }}{{ ')' if param.isClosure }}?{% endfor %} + var {% call swiftifyMethodName method.selectorName %}ReceivedInvocations{% for param in method.parameters %}: [{{ '(' if param.isClosure }}{{ param.typeName.unwrappedTypeName }}{{ ')' if param.isClosure }}{%if param.typeName.isOptional%}?{%endif%}]{% endfor %} = [] + {% elif not method.parameters.count == 0 %} + var {% call swiftifyMethodName method.selectorName %}ReceivedArguments: ({% for param in method.parameters %}{{ param.name }}: {{ param.unwrappedTypeName if param.typeAttributes.escaping else param.typeName }}{{ ', ' if not forloop.last }}{% endfor %})? + var {% call swiftifyMethodName method.selectorName %}ReceivedInvocations: [({% for param in method.parameters %}{{ param.name }}: {{ param.unwrappedTypeName if param.typeAttributes.escaping else param.typeName }}{{ ', ' if not forloop.last }}{% endfor %})] = [] + {% endif %} + {% if not method.returnTypeName.isVoid and not method.isInitializer %} + var {% call swiftifyMethodName method.selectorName %}ReturnValue: {{ '(' if method.returnTypeName.isClosure and not method.isOptionalReturnType }}{{ method.returnTypeName }}{{ ')' if method.returnTypeName.isClosure and not method.isOptionalReturnType }}{{ '!' if not method.isOptionalReturnType }} + {% endif %} + {% call methodClosureDeclaration method %} +{% if method.isInitializer %} + required {{ method.name }} { + {% call methodReceivedParameters method %} + {% call methodClosureName method %}?({% call methodClosureCallParameters method %}) + } +{% else %} + {% for name, attribute in method.attributes %} + {% for value in attribute %} + {{ value }} + {% endfor %} + {% endfor %} + func {{ method.name }}{{ ' async' if method.isAsync }}{{ ' throws' if method.throws }}{% if not method.returnTypeName.isVoid %} -> {{ method.returnTypeName }}{% endif %} { + {% if method.throws %} + {% call methodThrowableErrorUsage method %} + {% endif %} + {% call swiftifyMethodName method.selectorName %}CallsCount += 1 + {% call methodReceivedParameters method %} + {% if method.returnTypeName.isVoid %} + {% if method.throws %}try {% endif %}{% if method.isAsync %}await {% endif %}{% call methodClosureName method %}?({% call methodClosureCallParameters method %}) + {% else %} + if let {% call methodClosureName method %} = {% call methodClosureName method %} { + return {{ 'try ' if method.throws }}{{ 'await ' if method.isAsync }}{% call methodClosureName method %}({% call methodClosureCallParameters method %}) + } else { + return {% call swiftifyMethodName method.selectorName %}ReturnValue + } + {% endif %} + } +{% endif %} +{% endmacro %} +{% macro mockOptionalVariable variable %} + var {% call mockedVariableName variable %}: {{ variable.typeName }} +{% endmacro %} +{% macro mockNonOptionalArrayOrDictionaryVariable variable %} + var {% call mockedVariableName variable %}: {{ variable.typeName }} = {% if variable.isArray %}[]{% elif variable.isDictionary %}[:]{% endif %} +{% endmacro %} +{% macro mockNonOptionalVariable variable %} + var {% call mockedVariableName variable %}: {{ variable.typeName }} { + get { return {% call underlyingMockedVariableName variable %} } + set(value) { {% call underlyingMockedVariableName variable %} = value } + } + var {% call underlyingMockedVariableName variable %}: {{ variable.typeName }}! +{% endmacro %} +{% macro underlyingMockedVariableName variable %}underlying{{ variable.name|upperFirstLetter }}{% endmacro %} +{% macro mockedVariableName variable %}{{ variable.name }}{% endmacro %} +{% for type in types.protocols where type.based.AutoMockable or type|annotated:"AutoMockable" %}{% if type.name != "AutoMockable" %} +class {{ type.name }}Mock: {{ type.name }} { +{% for variable in type.allVariables|!definedInExtension %} + {% if variable.isOptional %}{% call mockOptionalVariable variable %}{% elif variable.isArray or variable.isDictionary %}{% call mockNonOptionalArrayOrDictionaryVariable variable %}{% else %}{% call mockNonOptionalVariable variable %}{% endif %} +{% endfor %} +{% for method in type.allMethods|!definedInExtension %} + {% call mockMethod method %} +{% endfor %} +} +{% endif %}{% endfor %}