From 6ad1654d979ae5b2f230ac68a02d45e02eb420f7 Mon Sep 17 00:00:00 2001 From: Stefan Ceriu Date: Tue, 2 Jun 2026 14:28:57 +0300 Subject: [PATCH] Convert the old MockTimelineController to the generated `TimelineControllerMock` --- .../Mocks/TimelineControllerFactoryMock.swift | 4 +- .../View/PollFormScreen.swift | 2 +- .../View/EmojiPickerScreen.swift | 4 +- .../TimelineMediaPreviewModifier.swift | 2 +- .../TimelineMediaPreviewDetailsView.swift | 2 +- ...neMediaPreviewRedactConfirmationView.swift | 2 +- .../LocationSharingScreenViewModel.swift | 2 +- .../View/MediaEventsTimelineScreen.swift | 4 +- .../View/MediaUploadPreviewScreen.swift | 2 +- .../View/PinnedEventsTimelineScreen.swift | 2 +- .../View/RoomPollsHistoryScreen.swift | 6 +- .../Screens/RoomScreen/View/RoomScreen.swift | 2 +- .../Screens/Timeline/TimelineViewModel.swift | 4 +- .../ReadReceiptsSummaryView.swift | 2 +- .../Style/TimelineItemBubbledStylerView.swift | 4 +- .../TimelineReadReceiptsView.swift | 2 +- .../HighlightedTimelineItemModifier.swift | 2 +- .../Screens/Timeline/View/TimelineView.swift | 2 +- .../MockTimelineController.swift | 480 ++++++++---------- .../UITests/UITestsAppCoordinator.swift | 18 +- .../EmojiPickerScreenViewModelTests.swift | 2 +- .../LocationSharingScreenViewModelTests.swift | 8 +- ...diaUploadPreviewScreenViewModelTests.swift | 2 +- UnitTests/Sources/PillContextTests.swift | 22 +- .../PollFormScreenViewModelTests.swift | 2 +- ...RoomPollsHistoryScreenViewModelTests.swift | 20 +- .../TimelineMediaPreviewViewModelTests.swift | 13 +- .../Sources/TimelineViewModelTests.swift | 50 +- .../Sources/VoiceMessageRecorderTests.swift | 12 +- 29 files changed, 299 insertions(+), 380 deletions(-) diff --git a/ElementX/Sources/Mocks/TimelineControllerFactoryMock.swift b/ElementX/Sources/Mocks/TimelineControllerFactoryMock.swift index 083b1dc5c..b2e5a8b0c 100644 --- a/ElementX/Sources/Mocks/TimelineControllerFactoryMock.swift +++ b/ElementX/Sources/Mocks/TimelineControllerFactoryMock.swift @@ -21,7 +21,7 @@ extension TimelineControllerFactoryMock { if let timelineController = configuration.threadTimelineController { return timelineController } else { - return MockTimelineController(timelineItems: RoomTimelineItemFixtures.largeChunk) + return TimelineControllerMock(.init(timelineItems: RoomTimelineItemFixtures.largeChunk)) } } @@ -29,7 +29,7 @@ extension TimelineControllerFactoryMock { if let timelineController = configuration.threadTimelineController { return .success(timelineController) } else { - let timelineController = MockTimelineController(timelineKind: .thread(rootEventID: threadRootEventID), timelineItems: RoomTimelineItemFixtures.largeChunk) + let timelineController = TimelineControllerMock(.init(timelineKind: .thread(rootEventID: threadRootEventID), timelineItems: RoomTimelineItemFixtures.largeChunk)) return .success(timelineController) } } diff --git a/ElementX/Sources/Screens/CreatePollScreen/View/PollFormScreen.swift b/ElementX/Sources/Screens/CreatePollScreen/View/PollFormScreen.swift index 2f41697df..42b18ad66 100644 --- a/ElementX/Sources/Screens/CreatePollScreen/View/PollFormScreen.swift +++ b/ElementX/Sources/Screens/CreatePollScreen/View/PollFormScreen.swift @@ -226,7 +226,7 @@ struct PollFormScreen_Previews: PreviewProvider, TestablePreview { static func makeViewModel(mode: PollFormMode) -> PollFormScreenViewModel { PollFormScreenViewModel(mode: mode, - timelineController: MockTimelineController(), + timelineController: TimelineControllerMock(.init()), analytics: AnalyticsServiceMock(.init()), userIndicatorController: UserIndicatorControllerMock()) } diff --git a/ElementX/Sources/Screens/EmojiPickerScreen/View/EmojiPickerScreen.swift b/ElementX/Sources/Screens/EmojiPickerScreen/View/EmojiPickerScreen.swift index 6eebfe321..80e94145e 100644 --- a/ElementX/Sources/Screens/EmojiPickerScreen/View/EmojiPickerScreen.swift +++ b/ElementX/Sources/Screens/EmojiPickerScreen/View/EmojiPickerScreen.swift @@ -104,7 +104,7 @@ struct EmojiPickerScreen_Previews: PreviewProvider, TestablePreview { static let viewModel = EmojiPickerScreenViewModel(itemID: .randomEvent, selectedEmojis: ["😀", "😄"], emojiProvider: EmojiProvider(appSettings: .volatile()), - timelineController: MockTimelineController()) + timelineController: TimelineControllerMock(.init())) static var previews: some View { EmojiPickerScreen(context: viewModel.context) @@ -117,7 +117,7 @@ struct EmojiPickerScreenSheet_Previews: PreviewProvider { static let viewModel = EmojiPickerScreenViewModel(itemID: .randomEvent, selectedEmojis: ["😀", "😄"], emojiProvider: EmojiProvider(appSettings: .volatile()), - timelineController: MockTimelineController()) + timelineController: TimelineControllerMock(.init())) static var previews: some View { Text("Timeline view") diff --git a/ElementX/Sources/Screens/FilePreviewScreen/TimelineMediaPreviewModifier.swift b/ElementX/Sources/Screens/FilePreviewScreen/TimelineMediaPreviewModifier.swift index 2024f59b0..16c2341a3 100644 --- a/ElementX/Sources/Screens/FilePreviewScreen/TimelineMediaPreviewModifier.swift +++ b/ElementX/Sources/Screens/FilePreviewScreen/TimelineMediaPreviewModifier.swift @@ -163,7 +163,7 @@ struct TimelineMediaPreviewModifier_Previews: PreviewProvider { thumbnailSource: nil, contentType: .pdf)) - let timelineController = MockTimelineController(timelineKind: .media(.mediaFilesScreen), timelineItems: [item]) + let timelineController = TimelineControllerMock(.init(timelineKind: .media(.mediaFilesScreen), timelineItems: [item])) let mediaProvider = MediaProviderMock(.init()) diff --git a/ElementX/Sources/Screens/FilePreviewScreen/View/TimelineMediaPreviewDetailsView.swift b/ElementX/Sources/Screens/FilePreviewScreen/View/TimelineMediaPreviewDetailsView.swift index 12eb01343..d559c7391 100644 --- a/ElementX/Sources/Screens/FilePreviewScreen/View/TimelineMediaPreviewDetailsView.swift +++ b/ElementX/Sources/Screens/FilePreviewScreen/View/TimelineMediaPreviewDetailsView.swift @@ -220,7 +220,7 @@ struct TimelineMediaPreviewDetailsView_Previews: PreviewProvider, TestablePrevie contentType: contentType)) let timelineKind = TimelineKind.media(isPresentedOnRoomScreen ? .roomScreenLive : .mediaFilesScreen) - let timelineController = MockTimelineController(timelineKind: timelineKind, timelineItems: [item]) + let timelineController = TimelineControllerMock(.init(timelineKind: timelineKind, timelineItems: [item])) let viewModel = TimelineMediaPreviewViewModel(initialItem: item, timelineViewModel: TimelineViewModel.mock(timelineKind: timelineKind, diff --git a/ElementX/Sources/Screens/FilePreviewScreen/View/TimelineMediaPreviewRedactConfirmationView.swift b/ElementX/Sources/Screens/FilePreviewScreen/View/TimelineMediaPreviewRedactConfirmationView.swift index 14819922a..e32761fe2 100644 --- a/ElementX/Sources/Screens/FilePreviewScreen/View/TimelineMediaPreviewRedactConfirmationView.swift +++ b/ElementX/Sources/Screens/FilePreviewScreen/View/TimelineMediaPreviewRedactConfirmationView.swift @@ -142,7 +142,7 @@ struct TimelineMediaPreviewRedactConfirmationView_Previews: PreviewProvider, Tes thumbnailInfo: .mockThumbnail, contentType: contentType)) - let timelineController = MockTimelineController(timelineKind: .media(.mediaFilesScreen), timelineItems: [item]) + let timelineController = TimelineControllerMock(.init(timelineKind: .media(.mediaFilesScreen), timelineItems: [item])) return TimelineMediaPreviewViewModel(initialItem: item, timelineViewModel: TimelineViewModel.mock(timelineKind: timelineController.timelineKind, timelineController: timelineController), diff --git a/ElementX/Sources/Screens/LocationSharing/LocationSharingScreenViewModel.swift b/ElementX/Sources/Screens/LocationSharing/LocationSharingScreenViewModel.swift index ad05569eb..2d1fbc3e4 100644 --- a/ElementX/Sources/Screens/LocationSharing/LocationSharingScreenViewModel.swift +++ b/ElementX/Sources/Screens/LocationSharing/LocationSharingScreenViewModel.swift @@ -392,7 +392,7 @@ extension LocationSharingScreenViewModel { return LocationSharingScreenViewModel(interactionMode: interactionMode, mapURLBuilder: AppSettings.volatile().mapTilerSettings.publisher.value, roomProxy: roomProxy, - timelineController: MockTimelineController(), + timelineController: TimelineControllerMock(.init()), liveLocationManager: LiveLocationManagerMock(), analytics: AnalyticsServiceMock(.init()), userIndicatorController: UserIndicatorControllerMock(), diff --git a/ElementX/Sources/Screens/MediaEventsTimelineScreen/View/MediaEventsTimelineScreen.swift b/ElementX/Sources/Screens/MediaEventsTimelineScreen/View/MediaEventsTimelineScreen.swift index 4bdbf3e62..ac2d535d2 100644 --- a/ElementX/Sources/Screens/MediaEventsTimelineScreen/View/MediaEventsTimelineScreen.swift +++ b/ElementX/Sources/Screens/MediaEventsTimelineScreen/View/MediaEventsTimelineScreen.swift @@ -305,9 +305,9 @@ struct MediaEventsTimelineScreen_Previews: PreviewProvider, TestablePreview { private static func makeTimelineViewModel(empty: Bool) -> TimelineViewModel { let timelineController = if empty { - MockTimelineController.emptyMediaGallery + TimelineControllerMock.emptyMediaGallery } else { - MockTimelineController.mediaGallery + TimelineControllerMock.mediaGallery } let appSettings = AppSettings.volatile() diff --git a/ElementX/Sources/Screens/MediaUploadPreviewScreen/View/MediaUploadPreviewScreen.swift b/ElementX/Sources/Screens/MediaUploadPreviewScreen/View/MediaUploadPreviewScreen.swift index d29846473..68241a7c5 100644 --- a/ElementX/Sources/Screens/MediaUploadPreviewScreen/View/MediaUploadPreviewScreen.swift +++ b/ElementX/Sources/Screens/MediaUploadPreviewScreen/View/MediaUploadPreviewScreen.swift @@ -372,7 +372,7 @@ struct MediaUploadPreviewScreen_Previews: PreviewProvider, TestablePreview { isRoomEncrypted: true, shouldShowCaptionWarning: true, mediaUploadingPreprocessor: MediaUploadingPreprocessor(appSettings: .volatile()), - timelineController: MockTimelineController(), + timelineController: TimelineControllerMock(.init()), clientProxy: ClientProxyMock(.init()), userIndicatorController: UserIndicatorControllerMock()) static var previews: some View { diff --git a/ElementX/Sources/Screens/PinnedEventsTimelineScreen/View/PinnedEventsTimelineScreen.swift b/ElementX/Sources/Screens/PinnedEventsTimelineScreen/View/PinnedEventsTimelineScreen.swift index bc81378f1..3d0bba01e 100644 --- a/ElementX/Sources/Screens/PinnedEventsTimelineScreen/View/PinnedEventsTimelineScreen.swift +++ b/ElementX/Sources/Screens/PinnedEventsTimelineScreen/View/PinnedEventsTimelineScreen.swift @@ -72,7 +72,7 @@ struct PinnedEventsTimelineScreen_Previews: PreviewProvider, TestablePreview { analyticsService: AnalyticsServiceMock(.init())) static let emptyTimelineViewModel: TimelineViewModel = { - let timelineController = MockTimelineController(timelineKind: .pinned, timelineItems: []) + let timelineController = TimelineControllerMock(.init(timelineKind: .pinned, timelineItems: [])) let appSettings = AppSettings.volatile() diff --git a/ElementX/Sources/Screens/RoomPollsHistoryScreen/View/RoomPollsHistoryScreen.swift b/ElementX/Sources/Screens/RoomPollsHistoryScreen/View/RoomPollsHistoryScreen.swift index ee7f18523..bbbc87fea 100644 --- a/ElementX/Sources/Screens/RoomPollsHistoryScreen/View/RoomPollsHistoryScreen.swift +++ b/ElementX/Sources/Screens/RoomPollsHistoryScreen/View/RoomPollsHistoryScreen.swift @@ -115,7 +115,7 @@ private extension DateFormatter { struct RoomPollsHistoryScreen_Previews: PreviewProvider, TestablePreview { static let viewModelEmpty: RoomPollsHistoryScreenViewModel = { - let timelineController = MockTimelineController(timelineItems: []) + let timelineController = TimelineControllerMock(.init(timelineItems: [])) let roomProxyMockConfiguration = JoinedRoomProxyMockConfiguration(name: "Polls") return RoomPollsHistoryScreenViewModel(pollInteractionHandler: PollInteractionHandlerMock(), timelineController: timelineController, @@ -134,8 +134,8 @@ struct RoomPollsHistoryScreen_Previews: PreviewProvider, TestablePreview { timelineItemsTimestamps[item.id] = date } - let timelineController = MockTimelineController(timelineItems: polls, - timelineItemsTimestamps: timelineItemsTimestamps) + let timelineController = TimelineControllerMock(.init(timelineItems: polls, + timelineItemsTimestamps: timelineItemsTimestamps)) let roomProxyMockConfiguration = JoinedRoomProxyMockConfiguration(name: "Polls", timelineStartReached: true) return RoomPollsHistoryScreenViewModel(pollInteractionHandler: PollInteractionHandlerMock(), diff --git a/ElementX/Sources/Screens/RoomScreen/View/RoomScreen.swift b/ElementX/Sources/Screens/RoomScreen/View/RoomScreen.swift index d1442f689..7d417292c 100644 --- a/ElementX/Sources/Screens/RoomScreen/View/RoomScreen.swift +++ b/ElementX/Sources/Screens/RoomScreen/View/RoomScreen.swift @@ -364,7 +364,7 @@ struct RoomScreen_Previews: PreviewProvider, TestablePreview { let appSettings = AppSettings.volatile() let timelineViewModel = TimelineViewModel(roomProxy: roomProxyMock, - timelineController: MockTimelineController(), + timelineController: TimelineControllerMock(.init()), userSession: UserSessionMock(.init()), mediaPlayerProvider: MediaPlayerProviderMock(), userIndicatorController: UserIndicatorControllerMock(), diff --git a/ElementX/Sources/Screens/Timeline/TimelineViewModel.swift b/ElementX/Sources/Screens/Timeline/TimelineViewModel.swift index b80311954..3739b4a05 100644 --- a/ElementX/Sources/Screens/Timeline/TimelineViewModel.swift +++ b/ElementX/Sources/Screens/Timeline/TimelineViewModel.swift @@ -1115,7 +1115,7 @@ class TimelineViewModel: TimelineViewModelType, TimelineViewModelProtocol { extension TimelineViewModel { static let mock = mock(timelineKind: .live) - static func mock(timelineKind: TimelineKind = .live, timelineController: MockTimelineController? = nil, hasPredecessor: Bool = false) -> TimelineViewModel { + static func mock(timelineKind: TimelineKind = .live, timelineController: TimelineControllerMock? = nil, hasPredecessor: Bool = false) -> TimelineViewModel { let clientProxyMock = ClientProxyMock(.init()) clientProxyMock.roomSummaryForAliasReturnValue = .mock(id: "!room:matrix.org", name: "Room") clientProxyMock.roomSummaryForIdentifierReturnValue = .mock(id: "!room:matrix.org", name: "Room", canonicalAlias: "#room:matrix.org") @@ -1125,7 +1125,7 @@ extension TimelineViewModel { return TimelineViewModel(roomProxy: roomProxy, focussedEventID: nil, - timelineController: timelineController ?? MockTimelineController(timelineKind: timelineKind), + timelineController: timelineController ?? TimelineControllerMock(.init(timelineKind: timelineKind)), userSession: UserSessionMock(.init(clientProxy: clientProxyMock)), mediaPlayerProvider: MediaPlayerProviderMock(), userIndicatorController: UserIndicatorControllerMock(), diff --git a/ElementX/Sources/Screens/Timeline/View/ReadReceipts/ReadReceiptsSummaryView.swift b/ElementX/Sources/Screens/Timeline/View/ReadReceipts/ReadReceiptsSummaryView.swift index 4a27d2ced..07f90ffbd 100644 --- a/ElementX/Sources/Screens/Timeline/View/ReadReceipts/ReadReceiptsSummaryView.swift +++ b/ElementX/Sources/Screens/Timeline/View/ReadReceipts/ReadReceiptsSummaryView.swift @@ -48,7 +48,7 @@ struct ReadReceiptsSummaryView_Previews: PreviewProvider, TestablePreview { let appSettings = AppSettings.volatile() return TimelineViewModel(roomProxy: roomProxyMock, - timelineController: MockTimelineController(), + timelineController: TimelineControllerMock(.init()), userSession: UserSessionMock(.init()), mediaPlayerProvider: MediaPlayerProviderMock(), userIndicatorController: UserIndicatorControllerMock(), diff --git a/ElementX/Sources/Screens/Timeline/View/Style/TimelineItemBubbledStylerView.swift b/ElementX/Sources/Screens/Timeline/View/Style/TimelineItemBubbledStylerView.swift index cc8c8c455..81df2a4b9 100644 --- a/ElementX/Sources/Screens/Timeline/View/Style/TimelineItemBubbledStylerView.swift +++ b/ElementX/Sources/Screens/Timeline/View/Style/TimelineItemBubbledStylerView.swift @@ -340,7 +340,7 @@ struct TimelineItemBubbledStylerView_Previews: PreviewProvider, TestablePreview let roomProxy = JoinedRoomProxyMock(.init()) return TimelineViewModel(roomProxy: roomProxy, focussedEventID: nil, - timelineController: MockTimelineController(), + timelineController: TimelineControllerMock(.init()), userSession: UserSessionMock(.init()), mediaPlayerProvider: MediaPlayerProviderMock(), userIndicatorController: UserIndicatorControllerMock(), @@ -359,7 +359,7 @@ struct TimelineItemBubbledStylerView_Previews: PreviewProvider, TestablePreview let roomProxy = JoinedRoomProxyMock(.init(name: "Preview Room", pinnedEventIDs: ["pinned"])) return TimelineViewModel(roomProxy: roomProxy, focussedEventID: nil, - timelineController: MockTimelineController(), + timelineController: TimelineControllerMock(.init()), userSession: UserSessionMock(.init()), mediaPlayerProvider: MediaPlayerProviderMock(), userIndicatorController: UserIndicatorControllerMock(), diff --git a/ElementX/Sources/Screens/Timeline/View/Supplementary/TimelineReadReceiptsView.swift b/ElementX/Sources/Screens/Timeline/View/Supplementary/TimelineReadReceiptsView.swift index 6b53e1a10..e1f712bd6 100644 --- a/ElementX/Sources/Screens/Timeline/View/Supplementary/TimelineReadReceiptsView.swift +++ b/ElementX/Sources/Screens/Timeline/View/Supplementary/TimelineReadReceiptsView.swift @@ -83,7 +83,7 @@ struct TimelineReadReceiptsView_Previews: PreviewProvider, TestablePreview { let appSettings = AppSettings.volatile() return TimelineViewModel(roomProxy: JoinedRoomProxyMock(.init(name: "Test", members: members)), - timelineController: MockTimelineController(), + timelineController: TimelineControllerMock(.init()), userSession: UserSessionMock(.init()), mediaPlayerProvider: MediaPlayerProviderMock(), userIndicatorController: UserIndicatorControllerMock(), diff --git a/ElementX/Sources/Screens/Timeline/View/TimelineItemViews/HighlightedTimelineItemModifier.swift b/ElementX/Sources/Screens/Timeline/View/TimelineItemViews/HighlightedTimelineItemModifier.swift index daf1881b6..477eb88e0 100644 --- a/ElementX/Sources/Screens/Timeline/View/TimelineItemViews/HighlightedTimelineItemModifier.swift +++ b/ElementX/Sources/Screens/Timeline/View/TimelineItemViews/HighlightedTimelineItemModifier.swift @@ -94,7 +94,7 @@ struct HighlightedTimelineItemTimeline_Previews: PreviewProvider { return TimelineViewModel(roomProxy: roomProxyMock, focussedEventID: focussedEventID, - timelineController: MockTimelineController(), + timelineController: TimelineControllerMock(.init()), userSession: UserSessionMock(.init()), mediaPlayerProvider: MediaPlayerProviderMock(), userIndicatorController: UserIndicatorControllerMock(), diff --git a/ElementX/Sources/Screens/Timeline/View/TimelineView.swift b/ElementX/Sources/Screens/Timeline/View/TimelineView.swift index 88bfc6fd3..20cfc5e9e 100644 --- a/ElementX/Sources/Screens/Timeline/View/TimelineView.swift +++ b/ElementX/Sources/Screens/Timeline/View/TimelineView.swift @@ -156,7 +156,7 @@ struct TimelineView_Previews: PreviewProvider { // Not testable as this preview let appSettings = AppSettings.volatile() return TimelineViewModel(roomProxy: roomProxyMock, - timelineController: MockTimelineController(), + timelineController: TimelineControllerMock(.init()), userSession: UserSessionMock(.init()), mediaPlayerProvider: MediaPlayerProviderMock(), userIndicatorController: UserIndicatorControllerMock(), diff --git a/ElementX/Sources/Services/Timeline/TimelineController/MockTimelineController.swift b/ElementX/Sources/Services/Timeline/TimelineController/MockTimelineController.swift index e63a58b8b..4ab5f6eeb 100644 --- a/ElementX/Sources/Services/Timeline/TimelineController/MockTimelineController.swift +++ b/ElementX/Sources/Services/Timeline/TimelineController/MockTimelineController.swift @@ -12,318 +12,238 @@ import Combine import Foundation import MatrixRustSDK -class MockTimelineController: TimelineControllerProtocol { - private let lastInsertedMessageID: TimelineItemIdentifier = .event(uniqueID: .init("last_message"), - eventOrTransactionID: .eventID("last_message")) - - private var roomProxy: JoinedRoomProxyProtocol? - private var timelineProxy: TimelineProxyProtocol? - - var roomID: String { - roomProxy?.id ?? "MockRoomIdentifier" - } - - private(set) var timelineKind: TimelineKind - - let callbacks = PassthroughSubject() - - private(set) var timelineItems: [RoomTimelineItemProtocol] = RoomTimelineItemFixtures.default { - didSet { - callbacks.send(.updatedTimelineItems(timelineItems: timelineItems, isSwitchingTimelines: false)) - } - } - - private let timelineItemsTimestamps: [TimelineItemIdentifier: Date] - - /// An array of timeline item arrays that will be inserted in order for each back pagination request. - var backPaginationResponses: [[RoomTimelineItemProtocol]] = [] - - var paginationState: TimelinePaginationState = .initial { - didSet { - callbacks.send(.paginationState(paginationState)) - } - } - - static var mediaGallery: MockTimelineController { - MockTimelineController(timelineKind: .media(.mediaFilesScreen), timelineItems: (0..<5).reduce([]) { partialResult, _ in +struct TimelineControllerMockConfiguration { + var roomProxy: JoinedRoomProxyProtocol? + var timelineKind: TimelineKind = .live + var timelineItems: [RoomTimelineItemProtocol] = RoomTimelineItemFixtures.default + var timelineProxy: TimelineProxyProtocol? + var timelineItemsTimestamps: [TimelineItemIdentifier: Date] = [:] + var paginationState: TimelinePaginationState = .initial +} + +extension TimelineControllerMock { + static var mediaGallery: TimelineControllerMock { + TimelineControllerMock(.init(timelineKind: .media(.mediaFilesScreen), timelineItems: (0..<5).reduce([]) { partialResult, _ in partialResult + [RoomTimelineItemFixtures.separator] + RoomTimelineItemFixtures.mediaChunk - }) + })) } - static var emptyMediaGallery: MockTimelineController { - let mock = MockTimelineController(timelineKind: .media(.mediaFilesScreen)) - mock.paginationState = TimelinePaginationState(backward: .endReached, forward: .endReached) - return mock + static var emptyMediaGallery: TimelineControllerMock { + TimelineControllerMock(.init(timelineKind: .media(.mediaFilesScreen), + paginationState: TimelinePaginationState(backward: .endReached, forward: .endReached))) } - init(roomProxy: JoinedRoomProxyProtocol? = nil, - timelineKind: TimelineKind = .live, - timelineItems: [RoomTimelineItemProtocol] = RoomTimelineItemFixtures.default, - timelineProxy: TimelineProxyProtocol? = nil, - timelineItemsTimestamps: [TimelineItemIdentifier: Date] = [TimelineItemIdentifier: Date]()) { - self.roomProxy = roomProxy - self.timelineKind = timelineKind - self.timelineItems = timelineItems - self.timelineProxy = timelineProxy - self.timelineItemsTimestamps = timelineItemsTimestamps + // swiftlint:disable:next function_body_length cyclomatic_complexity + convenience init(_ configuration: TimelineControllerMockConfiguration) { + self.init() - callbacks.send(.paginationState(paginationState)) + let lastInsertedMessageID: TimelineItemIdentifier = .event(uniqueID: .init("last_message"), + eventOrTransactionID: .eventID("last_message")) + let roomProxy = configuration.roomProxy + let timelineProxy = configuration.timelineProxy + let timelineItemsTimestamps = configuration.timelineItemsTimestamps + + underlyingCallbacks = PassthroughSubject() + underlyingRoomID = roomProxy?.id ?? "MockRoomIdentifier" + underlyingTimelineKind = configuration.timelineKind + underlyingPaginationState = configuration.paginationState + timelineItems = configuration.timelineItems + + callbacks.send(.paginationState(configuration.paginationState)) callbacks.send(.isLive(true)) - } - - private(set) var focusOnEventCallCount = 0 - func focusOnEvent(_ eventID: String, timelineSize: UInt16) async -> Result { - focusOnEventCallCount += 1 - callbacks.send(.isLive(false)) - return .success(()) - } - - private(set) var focusLiveCallCount = 0 - func focusLive() { - focusLiveCallCount += 1 - callbacks.send(.isLive(true)) - } - - private(set) var paginateBackwardsCallCount = 0 - func paginateBackwards(requestSize: UInt16) async -> Result { - paginateBackwardsCallCount += 1 - paginationState = TimelinePaginationState(backward: .paginating, forward: .endReached) - simulateBackPagination() - return .success(()) - } - - private func simulateBackPagination() { - defer { - paginationState = TimelinePaginationState(backward: backPaginationResponses.isEmpty ? .endReached : .idle, - forward: .endReached) + + focusOnEventTimelineSizeClosure = { [weak self] _, _ in + self?.callbacks.send(.isLive(false)) + return .success(()) } - guard !backPaginationResponses.isEmpty else { return } - - let newItems = backPaginationResponses.removeFirst() - timelineItems.insert(contentsOf: newItems, at: 0) - } - - private(set) var paginateForwardsCallCount = 0 - func paginateForwards(requestSize: UInt16) async -> Result { - paginateForwardsCallCount += 1 - return .success(()) - } - - func sendReadReceipt(for itemID: TimelineItemIdentifier) async { - guard let roomProxy, let eventID = itemID.eventID else { return } - _ = await roomProxy.timeline.sendReadReceipt(for: eventID, type: .read) - } - - func processItemAppearance(_ itemID: TimelineItemIdentifier) async { } - - func processItemDisappearance(_ itemID: TimelineItemIdentifier) async { } - - func toggleReaction(_ reaction: String, to eventID: TimelineItemIdentifier.EventOrTransactionID) async { - if let timelineProxy { - _ = await timelineProxy.toggleReaction(reaction, to: eventID) + focusLiveClosure = { [weak self] in + self?.callbacks.send(.isLive(true)) } - } - - func edit(_ eventOrTransactionID: TimelineItemIdentifier.EventOrTransactionID, - message: String, - html: String?, - intentionalMentions: IntentionalMentions) async { - callbacks.send(.messageSentOrEdited) - timelineItems[timelineItems.endIndex - 1] = TextRoomTimelineItem(id: lastInsertedMessageID, - timestamp: .distantFuture, - isOutgoing: true, - isEditable: true, - canBeRepliedTo: true, - sender: .test, - content: .init(body: message), - properties: .init(isEdited: true)) - } - - func editCaption(_ eventOrTransactionID: TimelineItemIdentifier.EventOrTransactionID, - message: String, - html: String?, - intentionalMentions: IntentionalMentions) async { } - - func removeCaption(_ eventOrTransactionID: TimelineItemIdentifier.EventOrTransactionID) async { } - - private(set) var redactCalled = false - func redact(_ eventOrTransactionID: TimelineItemIdentifier.EventOrTransactionID) async { - if let timelineProxy { + paginateBackwardsRequestSizeReturnValue = .success(()) + paginateForwardsRequestSizeReturnValue = .success(()) + + sendReadReceiptForClosure = { [roomProxy] itemID in + guard let roomProxy, let eventID = itemID.eventID else { return } + _ = await roomProxy.timeline.sendReadReceipt(for: eventID, type: .read) + } + + toggleReactionToClosure = { [timelineProxy] reaction, eventOrTransactionID in + guard let timelineProxy else { return } + _ = await timelineProxy.toggleReaction(reaction, to: eventOrTransactionID) + } + + redactClosure = { [timelineProxy] eventOrTransactionID in + guard let timelineProxy else { return } _ = await timelineProxy.redact(eventOrTransactionID, reason: nil) } - redactCalled = true - } - - func pin(eventID: String) async { } - - func unpin(eventID: String) async { } - - func messageEventContent(for itemID: TimelineItemIdentifier) -> RoomMessageEventContentWithoutRelation? { - .init(noHandle: .init()) - } - - func debugInfo(for itemID: TimelineItemIdentifier) -> TimelineItemDebugInfo { - .init(model: "Mock debug description", originalJSON: nil, latestEditJSON: nil) - } - - func sendHandle(for itemID: TimelineItemIdentifier) -> SendHandleProxy? { - nil - } - - func eventTimestamp(for itemID: TimelineItemIdentifier) -> Date? { - timelineItemsTimestamps[itemID] ?? .now - } - - // MARK: - Sending - - func sendMessage(_ message: String, - html: String?, - inReplyToEventID: String?, - intentionalMentions: IntentionalMentions) async { - callbacks.send(.messageSentOrEdited) - timelineItems.append(TextRoomTimelineItem(id: lastInsertedMessageID, - timestamp: .distantFuture, - isOutgoing: true, - isEditable: true, - canBeRepliedTo: true, - sender: .test, - content: .init(body: message))) - } - - func sendAudio(url: URL, - audioInfo: MatrixRustSDK.AudioInfo, - caption: String?, - requestHandle: @MainActor (SendAttachmentJoinHandleProtocol) -> Void) async -> Result { - callbacks.send(.messageSentOrEdited) - - if let timelineProxy { - return await timelineProxy.sendAudio(url: url, - audioInfo: audioInfo, - caption: caption, - requestHandle: requestHandle).mapError(TimelineControllerError.timelineProxyError) + editMessageHtmlIntentionalMentionsClosure = { [weak self] _, message, _, _ in + guard let self else { return } + self.callbacks.send(.messageSentOrEdited) + self.timelineItems[self.timelineItems.endIndex - 1] = TextRoomTimelineItem(id: lastInsertedMessageID, + timestamp: .distantFuture, + isOutgoing: true, + isEditable: true, + canBeRepliedTo: true, + sender: .test, + content: .init(body: message), + properties: .init(isEdited: true)) + self.callbacks.send(.updatedTimelineItems(timelineItems: self.timelineItems, isSwitchingTimelines: false)) } - return .success(()) - } - - func sendFile(url: URL, - fileInfo: MatrixRustSDK.FileInfo, - caption: String?, - requestHandle: @MainActor (SendAttachmentJoinHandleProtocol) -> Void) async -> Result { - callbacks.send(.messageSentOrEdited) - - if let timelineProxy { - return await timelineProxy.sendFile(url: url, - fileInfo: fileInfo, - caption: caption, - requestHandle: requestHandle).mapError(TimelineControllerError.timelineProxyError) + sendMessageHtmlInReplyToEventIDIntentionalMentionsClosure = { [weak self] message, _, _, _ in + guard let self else { return } + self.callbacks.send(.messageSentOrEdited) + self.timelineItems.append(TextRoomTimelineItem(id: lastInsertedMessageID, + timestamp: .distantFuture, + isOutgoing: true, + isEditable: true, + canBeRepliedTo: true, + sender: .test, + content: .init(body: message))) + self.callbacks.send(.updatedTimelineItems(timelineItems: self.timelineItems, isSwitchingTimelines: false)) } - return .success(()) - } - - func sendImage(url: URL, - thumbnailURL: URL, - imageInfo: MatrixRustSDK.ImageInfo, - caption: String?, - requestHandle: @MainActor (SendAttachmentJoinHandleProtocol) -> Void) async -> Result { - callbacks.send(.messageSentOrEdited) - - if let timelineProxy { - return await timelineProxy.sendImage(url: url, - thumbnailURL: thumbnailURL, - imageInfo: imageInfo, - caption: caption, - requestHandle: requestHandle).mapError(TimelineControllerError.timelineProxyError) + sendAudioUrlAudioInfoCaptionRequestHandleClosure = { [weak self, timelineProxy] url, audioInfo, caption, requestHandle in + self?.callbacks.send(.messageSentOrEdited) + if let timelineProxy { + return await timelineProxy.sendAudio(url: url, + audioInfo: audioInfo, + caption: caption, + requestHandle: requestHandle).mapError(TimelineControllerError.timelineProxyError) + } + return .success(()) } - return .success(()) - } - - func sendLocation(body: String, - geoURI: GeoURI, - description: String?, - zoomLevel: UInt8?, - assetType: MatrixRustSDK.AssetType?) async -> Result { - callbacks.send(.messageSentOrEdited) - - if let timelineProxy { - return await timelineProxy.sendLocation(body: body, - geoURI: geoURI, - description: description, - zoomLevel: zoomLevel, - assetType: assetType).mapError(TimelineControllerError.timelineProxyError) + sendFileUrlFileInfoCaptionRequestHandleClosure = { [weak self, timelineProxy] url, fileInfo, caption, requestHandle in + self?.callbacks.send(.messageSentOrEdited) + if let timelineProxy { + return await timelineProxy.sendFile(url: url, + fileInfo: fileInfo, + caption: caption, + requestHandle: requestHandle).mapError(TimelineControllerError.timelineProxyError) + } + return .success(()) } - return .success(()) - } - - func sendVideo(url: URL, - thumbnailURL: URL, - videoInfo: MatrixRustSDK.VideoInfo, - caption: String?, - requestHandle: @MainActor (SendAttachmentJoinHandleProtocol) -> Void) async -> Result { - callbacks.send(.messageSentOrEdited) - - if let timelineProxy { - return await timelineProxy.sendVideo(url: url, - thumbnailURL: thumbnailURL, - videoInfo: videoInfo, - caption: caption, - requestHandle: requestHandle).mapError(TimelineControllerError.timelineProxyError) + sendImageUrlThumbnailURLImageInfoCaptionRequestHandleClosure = { [weak self, timelineProxy] url, thumbnailURL, imageInfo, caption, requestHandle in + self?.callbacks.send(.messageSentOrEdited) + if let timelineProxy { + return await timelineProxy.sendImage(url: url, + thumbnailURL: thumbnailURL, + imageInfo: imageInfo, + caption: caption, + requestHandle: requestHandle).mapError(TimelineControllerError.timelineProxyError) + } + return .success(()) } - return .success(()) - } - - func sendVoiceMessage(url: URL, - audioInfo: MatrixRustSDK.AudioInfo, - waveform: [Float], - requestHandle: @MainActor (SendAttachmentJoinHandleProtocol) -> Void) async -> Result { - callbacks.send(.messageSentOrEdited) - - if let timelineProxy { - return await timelineProxy.sendVoiceMessage(url: url, - audioInfo: audioInfo, - waveform: waveform, - requestHandle: requestHandle).mapError(TimelineControllerError.timelineProxyError) + sendLocationBodyGeoURIDescriptionZoomLevelAssetTypeClosure = { [weak self, timelineProxy] body, geoURI, description, zoomLevel, assetType in + self?.callbacks.send(.messageSentOrEdited) + if let timelineProxy { + return await timelineProxy.sendLocation(body: body, + geoURI: geoURI, + description: description, + zoomLevel: zoomLevel, + assetType: assetType).mapError(TimelineControllerError.timelineProxyError) + } + return .success(()) } - return .success(()) - } - - // MARK: - Polls - - func createPoll(question: String, answers: [String], pollKind: Poll.Kind) async -> Result { - callbacks.send(.messageSentOrEdited) + sendVideoUrlThumbnailURLVideoInfoCaptionRequestHandleClosure = { [weak self, timelineProxy] url, thumbnailURL, videoInfo, caption, requestHandle in + self?.callbacks.send(.messageSentOrEdited) + if let timelineProxy { + return await timelineProxy.sendVideo(url: url, + thumbnailURL: thumbnailURL, + videoInfo: videoInfo, + caption: caption, + requestHandle: requestHandle).mapError(TimelineControllerError.timelineProxyError) + } + return .success(()) + } - if let timelineProxy { - _ = await timelineProxy.createPoll(question: question, answers: answers, pollKind: pollKind) + sendVoiceMessageUrlAudioInfoWaveformRequestHandleClosure = { [weak self, timelineProxy] url, audioInfo, waveform, requestHandle in + self?.callbacks.send(.messageSentOrEdited) + if let timelineProxy { + return await timelineProxy.sendVoiceMessage(url: url, + audioInfo: audioInfo, + waveform: waveform, + requestHandle: requestHandle).mapError(TimelineControllerError.timelineProxyError) + } + return .success(()) + } + + createPollQuestionAnswersPollKindClosure = { [weak self, timelineProxy] question, answers, pollKind in + self?.callbacks.send(.messageSentOrEdited) + if let timelineProxy { + _ = await timelineProxy.createPoll(question: question, answers: answers, pollKind: pollKind) + } + return .success(()) + } + + editPollOriginalQuestionAnswersPollKindClosure = { [timelineProxy] eventID, question, answers, pollKind in + if let timelineProxy { + _ = await timelineProxy.editPoll(original: eventID, question: question, answers: answers, pollKind: pollKind) + } + return .success(()) + } + + sendPollResponsePollStartIDAnswersClosure = { [timelineProxy] pollStartID, answers in + if let timelineProxy { + _ = await timelineProxy.sendPollResponse(pollStartID: pollStartID, answers: answers) + } + return .success(()) + } + + endPollPollStartIDTextClosure = { [timelineProxy] pollStartID, text in + if let timelineProxy { + _ = await timelineProxy.endPoll(pollStartID: pollStartID, text: text) + } + return .success(()) + } + + messageEventContentForReturnValue = .init(noHandle: .init()) + debugInfoForReturnValue = .init(model: "Mock debug description", originalJSON: nil, latestEditJSON: nil) + + eventTimestampForClosure = { [timelineItemsTimestamps] itemID in + timelineItemsTimestamps[itemID] ?? .now } - return .success(()) } - func editPoll(original eventID: String, question: String, answers: [String], pollKind: Poll.Kind) async -> Result { - if let timelineProxy { - _ = await timelineProxy.editPoll(original: eventID, question: question, answers: answers, pollKind: pollKind) - } - return .success(()) + func update(paginationState: TimelinePaginationState) { + self.paginationState = paginationState + callbacks.send(.paginationState(paginationState)) } - func sendPollResponse(pollStartID: String, answers: [String]) async -> Result { - if let timelineProxy { - _ = await timelineProxy.sendPollResponse(pollStartID: pollStartID, answers: answers) + /// Configures `paginateBackwardsRequestSizeClosure` to simulate back pagination from the given response queue, + /// sending the appropriate `updatedTimelineItems` and `paginationState` callbacks each time. + func setupBackPagination(responses: [[RoomTimelineItemProtocol]]) { + var queue = responses + paginateBackwardsRequestSizeClosure = { [weak self] _ in + guard let self else { return .success(()) } + + let paginating = TimelinePaginationState(backward: .paginating, forward: .endReached) + self.paginationState = paginating + self.callbacks.send(.paginationState(paginating)) + + guard !queue.isEmpty else { + let end = TimelinePaginationState(backward: .endReached, forward: .endReached) + self.paginationState = end + self.callbacks.send(.paginationState(end)) + return .success(()) + } + + let newItems = queue.removeFirst() + self.timelineItems.insert(contentsOf: newItems, at: 0) + self.callbacks.send(.updatedTimelineItems(timelineItems: self.timelineItems, isSwitchingTimelines: false)) + + let final = TimelinePaginationState(backward: queue.isEmpty ? .endReached : .idle, forward: .endReached) + self.paginationState = final + self.callbacks.send(.paginationState(final)) + + return .success(()) } - return .success(()) - } - - func endPoll(pollStartID: String, text: String) async -> Result { - if let timelineProxy { - _ = await timelineProxy.endPoll(pollStartID: pollStartID, text: text) - } - return .success(()) } } diff --git a/ElementX/Sources/UITests/UITestsAppCoordinator.swift b/ElementX/Sources/UITests/UITestsAppCoordinator.swift index 6c371430a..975ffa9fb 100644 --- a/ElementX/Sources/UITests/UITestsAppCoordinator.swift +++ b/ElementX/Sources/UITests/UITestsAppCoordinator.swift @@ -290,7 +290,7 @@ class MockScreen: Identifiable { let navigationStackCoordinator = NavigationStackCoordinator() let parameters = RoomScreenCoordinatorParameters(userSession: UserSessionMock(.init()), roomProxy: JoinedRoomProxyMock(.init(name: "Some room name", avatarURL: nil)), - timelineController: MockTimelineController(), + timelineController: TimelineControllerMock(.init()), mediaPlayerProvider: MediaPlayerProviderMock(), emojiProvider: EmojiProvider(appSettings: appSettings), linkMetadataProvider: LinkMetadataProvider(), @@ -308,7 +308,7 @@ class MockScreen: Identifiable { return navigationStackCoordinator case .roomSmallTimeline: let navigationStackCoordinator = NavigationStackCoordinator() - let timelineController = MockTimelineController(timelineItems: RoomTimelineItemFixtures.smallChunk) + let timelineController = TimelineControllerMock(.init(timelineItems: RoomTimelineItemFixtures.smallChunk)) let parameters = RoomScreenCoordinatorParameters(userSession: UserSessionMock(.init()), roomProxy: JoinedRoomProxyMock(.init(name: "New room", avatarURL: .mockMXCAvatar)), timelineController: timelineController, @@ -329,7 +329,7 @@ class MockScreen: Identifiable { return navigationStackCoordinator case .roomSmallTimelineWithReactions: let navigationStackCoordinator = NavigationStackCoordinator() - let timelineController = MockTimelineController(timelineItems: RoomTimelineItemFixtures.default) + let timelineController = TimelineControllerMock(.init(timelineItems: RoomTimelineItemFixtures.default)) let parameters = RoomScreenCoordinatorParameters(userSession: UserSessionMock(.init()), roomProxy: JoinedRoomProxyMock(.init(name: "New room", avatarURL: .mockMXCAvatar)), timelineController: timelineController, @@ -349,7 +349,7 @@ class MockScreen: Identifiable { return navigationStackCoordinator case .roomSmallTimelineWithReadReceipts: let navigationStackCoordinator = NavigationStackCoordinator() - let timelineController = MockTimelineController(timelineItems: RoomTimelineItemFixtures.smallChunkWithReadReceipts) + let timelineController = TimelineControllerMock(.init(timelineItems: RoomTimelineItemFixtures.smallChunkWithReadReceipts)) let parameters = RoomScreenCoordinatorParameters(userSession: UserSessionMock(.init()), roomProxy: JoinedRoomProxyMock(.init(name: "New room", avatarURL: .mockMXCAvatar)), timelineController: timelineController, @@ -501,7 +501,7 @@ class MockScreen: Identifiable { case .roomLayoutHighlight: let navigationStackCoordinator = NavigationStackCoordinator() - let timelineController = MockTimelineController(timelineItems: RoomTimelineItemFixtures.permalinkChunk) + let timelineController = TimelineControllerMock(.init(timelineItems: RoomTimelineItemFixtures.permalinkChunk)) let parameters = RoomScreenCoordinatorParameters(userSession: UserSessionMock(.init()), roomProxy: JoinedRoomProxyMock(.init(name: "Timeline highlight", avatarURL: .mockMXCAvatar)), timelineController: timelineController, @@ -536,7 +536,7 @@ class MockScreen: Identifiable { case .roomWithDisclosedPolls: let navigationStackCoordinator = NavigationStackCoordinator() - let timelineController = MockTimelineController(timelineItems: RoomTimelineItemFixtures.disclosedPolls) + let timelineController = TimelineControllerMock(.init(timelineItems: RoomTimelineItemFixtures.disclosedPolls)) let parameters = RoomScreenCoordinatorParameters(userSession: UserSessionMock(.init()), roomProxy: JoinedRoomProxyMock(.init(name: "Polls timeline", avatarURL: .mockMXCAvatar)), timelineController: timelineController, @@ -558,7 +558,7 @@ class MockScreen: Identifiable { case .roomWithUndisclosedPolls: let navigationStackCoordinator = NavigationStackCoordinator() - let timelineController = MockTimelineController(timelineItems: RoomTimelineItemFixtures.undisclosedPolls) + let timelineController = TimelineControllerMock(.init(timelineItems: RoomTimelineItemFixtures.undisclosedPolls)) let parameters = RoomScreenCoordinatorParameters(userSession: UserSessionMock(.init()), roomProxy: JoinedRoomProxyMock(.init(name: "Polls timeline", avatarURL: .mockMXCAvatar)), timelineController: timelineController, @@ -580,7 +580,7 @@ class MockScreen: Identifiable { case .roomWithOutgoingPolls: let navigationStackCoordinator = NavigationStackCoordinator() - let timelineController = MockTimelineController(timelineItems: RoomTimelineItemFixtures.outgoingPolls) + let timelineController = TimelineControllerMock(.init(timelineItems: RoomTimelineItemFixtures.outgoingPolls)) let parameters = RoomScreenCoordinatorParameters(userSession: UserSessionMock(.init()), roomProxy: JoinedRoomProxyMock(.init(name: "Polls timeline", avatarURL: .mockMXCAvatar)), timelineController: timelineController, @@ -732,7 +732,7 @@ class MockScreen: Identifiable { let navigationStackCoordinator = NavigationStackCoordinator() let coordinator = PollFormScreenCoordinator(parameters: .init(mode: .new(topic: nil), maxNumberOfOptions: 10, - timelineController: MockTimelineController(), + timelineController: TimelineControllerMock(.init()), analytics: analytics, userIndicatorController: UserIndicatorControllerMock())) navigationStackCoordinator.setRootCoordinator(coordinator) diff --git a/UnitTests/Sources/EmojiPickerScreenViewModelTests.swift b/UnitTests/Sources/EmojiPickerScreenViewModelTests.swift index 7c018564e..b7a5d5c3e 100644 --- a/UnitTests/Sources/EmojiPickerScreenViewModelTests.swift +++ b/UnitTests/Sources/EmojiPickerScreenViewModelTests.swift @@ -46,6 +46,6 @@ struct EmojiPickerScreenViewModelTests { viewModel = EmojiPickerScreenViewModel(itemID: .randomEvent, selectedEmojis: selectedEmojis, emojiProvider: EmojiProvider(appSettings: .volatile()), - timelineController: MockTimelineController(timelineProxy: timelineProxy)) + timelineController: TimelineControllerMock(.init(timelineProxy: timelineProxy))) } } diff --git a/UnitTests/Sources/LocationSharingScreenViewModelTests.swift b/UnitTests/Sources/LocationSharingScreenViewModelTests.swift index dbf710878..d8d8f4d88 100644 --- a/UnitTests/Sources/LocationSharingScreenViewModelTests.swift +++ b/UnitTests/Sources/LocationSharingScreenViewModelTests.swift @@ -399,7 +399,7 @@ struct LocationSharingScreenViewModelTests { viewModel = LocationSharingScreenViewModel(interactionMode: .viewLive(sender: nil, initialLiveLocationShare: nil), mapURLBuilder: appSettings.mapTilerSettings.publisher.value, roomProxy: roomProxyMock, - timelineController: MockTimelineController(timelineProxy: TimelineProxyMock(.init())), + timelineController: TimelineControllerMock(.init(timelineProxy: TimelineProxyMock(.init()))), liveLocationManager: LiveLocationManagerMock(.init()), analytics: AnalyticsServiceMock(.init()), userIndicatorController: UserIndicatorControllerMock(), @@ -434,7 +434,7 @@ struct LocationSharingScreenViewModelTests { viewModel = LocationSharingScreenViewModel(interactionMode: .picker(shouldShowLiveLocationOption: true), mapURLBuilder: appSettings.mapTilerSettings.publisher.value, roomProxy: JoinedRoomProxyMock(.init(members: members)), - timelineController: MockTimelineController(timelineProxy: timelineProxy), + timelineController: TimelineControllerMock(.init(timelineProxy: timelineProxy)), liveLocationManager: LiveLocationManagerMock(liveLocationManagerConfiguration), analytics: AnalyticsServiceMock(.init()), userIndicatorController: UserIndicatorControllerMock(), @@ -449,7 +449,7 @@ struct LocationSharingScreenViewModelTests { viewModel = LocationSharingScreenViewModel(interactionMode: .picker(shouldShowLiveLocationOption: true), mapURLBuilder: appSettings.mapTilerSettings.publisher.value, roomProxy: JoinedRoomProxyMock(.init(members: members)), - timelineController: MockTimelineController(timelineProxy: timelineProxy), + timelineController: TimelineControllerMock(.init(timelineProxy: timelineProxy)), liveLocationManager: liveLocationManagerMock, analytics: AnalyticsServiceMock(.init()), userIndicatorController: UserIndicatorControllerMock(), @@ -471,7 +471,7 @@ struct LocationSharingScreenViewModelTests { viewModel = LocationSharingScreenViewModel(interactionMode: .viewLive(sender: sender, initialLiveLocationShare: initialShare), mapURLBuilder: appSettings.mapTilerSettings.publisher.value, roomProxy: roomProxyMock, - timelineController: MockTimelineController(timelineProxy: TimelineProxyMock(.init())), + timelineController: TimelineControllerMock(.init(timelineProxy: TimelineProxyMock(.init()))), liveLocationManager: LiveLocationManagerMock(.init()), analytics: AnalyticsServiceMock(.init()), userIndicatorController: UserIndicatorControllerMock(), diff --git a/UnitTests/Sources/MediaUploadPreviewScreenViewModelTests.swift b/UnitTests/Sources/MediaUploadPreviewScreenViewModelTests.swift index 871ea0516..80ce152c5 100644 --- a/UnitTests/Sources/MediaUploadPreviewScreenViewModelTests.swift +++ b/UnitTests/Sources/MediaUploadPreviewScreenViewModelTests.swift @@ -293,7 +293,7 @@ final class MediaUploadPreviewScreenViewModelTests { isRoomEncrypted: true, shouldShowCaptionWarning: true, mediaUploadingPreprocessor: MediaUploadingPreprocessor(appSettings: appSettings), - timelineController: MockTimelineController(timelineProxy: timelineProxy), + timelineController: TimelineControllerMock(.init(timelineProxy: timelineProxy)), clientProxy: clientProxy, userIndicatorController: userIndicatorController) } diff --git a/UnitTests/Sources/PillContextTests.swift b/UnitTests/Sources/PillContextTests.swift index 04d0bcacf..48b7b989f 100644 --- a/UnitTests/Sources/PillContextTests.swift +++ b/UnitTests/Sources/PillContextTests.swift @@ -23,7 +23,7 @@ struct PillContextTests { let subject = CurrentValueSubject<[RoomMemberProxyProtocol], Never>([]) proxyMock.membersPublisher = subject.asCurrentValuePublisher() let mock = TimelineViewModel(roomProxy: proxyMock, - timelineController: MockTimelineController(), + timelineController: TimelineControllerMock(.init()), userSession: UserSessionMock(.init()), mediaPlayerProvider: MediaPlayerProviderMock(), userIndicatorController: userIndicatorController, @@ -57,7 +57,7 @@ struct PillContextTests { let subject = CurrentValueSubject<[RoomMemberProxyProtocol], Never>([]) proxyMock.membersPublisher = subject.asCurrentValuePublisher() let mock = TimelineViewModel(roomProxy: proxyMock, - timelineController: MockTimelineController(), + timelineController: TimelineControllerMock(.init()), userSession: UserSessionMock(.init()), mediaPlayerProvider: MediaPlayerProviderMock(), userIndicatorController: userIndicatorController, @@ -81,7 +81,7 @@ struct PillContextTests { let id = "test_room" let displayName = "Test" let proxyMock = JoinedRoomProxyMock(.init(id: id, name: displayName, avatarURL: avatarURL)) - let mockController = MockTimelineController(roomProxy: proxyMock) + let mockController = TimelineControllerMock(.init(roomProxy: proxyMock)) let mock = TimelineViewModel(roomProxy: proxyMock, timelineController: mockController, userSession: UserSessionMock(.init()), @@ -105,7 +105,7 @@ struct PillContextTests { let userIndicatorController = UserIndicatorControllerMock() let proxyMock = JoinedRoomProxyMock(.init()) - let mockController = MockTimelineController(roomProxy: proxyMock) + let mockController = TimelineControllerMock(.init(roomProxy: proxyMock)) let clientMock = ClientProxyMock(.init()) clientMock.roomSummaryForIdentifierReturnValue = .mock(id: "1", name: "Foundation 🔭🪐🌌") let mock = TimelineViewModel(roomProxy: proxyMock, @@ -132,7 +132,7 @@ struct PillContextTests { let userIndicatorController = UserIndicatorControllerMock() let proxyMock = JoinedRoomProxyMock(.init()) - let mockController = MockTimelineController(roomProxy: proxyMock) + let mockController = TimelineControllerMock(.init(roomProxy: proxyMock)) let mock = TimelineViewModel(roomProxy: proxyMock, timelineController: mockController, userSession: UserSessionMock(.init()), @@ -157,7 +157,7 @@ struct PillContextTests { let userIndicatorController = UserIndicatorControllerMock() let proxyMock = JoinedRoomProxyMock(.init()) - let mockController = MockTimelineController(roomProxy: proxyMock) + let mockController = TimelineControllerMock(.init(roomProxy: proxyMock)) let clientMock = ClientProxyMock(.init()) clientMock.roomSummaryForAliasReturnValue = .mock(id: "2", name: "Foundation and Empire", @@ -186,7 +186,7 @@ struct PillContextTests { let userIndicatorController = UserIndicatorControllerMock() let proxyMock = JoinedRoomProxyMock(.init()) - let mockController = MockTimelineController(roomProxy: proxyMock) + let mockController = TimelineControllerMock(.init(roomProxy: proxyMock)) let mock = TimelineViewModel(roomProxy: proxyMock, timelineController: mockController, userSession: UserSessionMock(.init()), @@ -211,7 +211,7 @@ struct PillContextTests { let userIndicatorController = UserIndicatorControllerMock() let proxyMock = JoinedRoomProxyMock(.init()) - let mockController = MockTimelineController(roomProxy: proxyMock) + let mockController = TimelineControllerMock(.init(roomProxy: proxyMock)) let clientMock = ClientProxyMock(.init()) clientMock.roomSummaryForIdentifierReturnValue = .mock(id: "1", name: "Foundation 🔭🪐🌌") let mock = TimelineViewModel(roomProxy: proxyMock, @@ -238,7 +238,7 @@ struct PillContextTests { let userIndicatorController = UserIndicatorControllerMock() let proxyMock = JoinedRoomProxyMock(.init()) - let mockController = MockTimelineController(roomProxy: proxyMock) + let mockController = TimelineControllerMock(.init(roomProxy: proxyMock)) let mock = TimelineViewModel(roomProxy: proxyMock, timelineController: mockController, userSession: UserSessionMock(.init()), @@ -263,7 +263,7 @@ struct PillContextTests { let userIndicatorController = UserIndicatorControllerMock() let proxyMock = JoinedRoomProxyMock(.init()) - let mockController = MockTimelineController(roomProxy: proxyMock) + let mockController = TimelineControllerMock(.init(roomProxy: proxyMock)) let clientMock = ClientProxyMock(.init()) clientMock.roomSummaryForAliasReturnValue = .mock(id: "2", name: "Foundation and Empire", @@ -292,7 +292,7 @@ struct PillContextTests { let userIndicatorController = UserIndicatorControllerMock() let proxyMock = JoinedRoomProxyMock(.init()) - let mockController = MockTimelineController(roomProxy: proxyMock) + let mockController = TimelineControllerMock(.init(roomProxy: proxyMock)) let mock = TimelineViewModel(roomProxy: proxyMock, timelineController: mockController, userSession: UserSessionMock(.init()), diff --git a/UnitTests/Sources/PollFormScreenViewModelTests.swift b/UnitTests/Sources/PollFormScreenViewModelTests.swift index f9f0f2844..6561ddb40 100644 --- a/UnitTests/Sources/PollFormScreenViewModelTests.swift +++ b/UnitTests/Sources/PollFormScreenViewModelTests.swift @@ -178,7 +178,7 @@ struct PollFormScreenViewModelTests { private mutating func setupViewModel(mode: PollFormMode = .new(topic: nil)) { viewModel = PollFormScreenViewModel(mode: mode, - timelineController: MockTimelineController(timelineProxy: timelineProxy), + timelineController: TimelineControllerMock(.init(timelineProxy: timelineProxy)), analytics: AnalyticsServiceMock(.init()), userIndicatorController: UserIndicatorControllerMock()) } diff --git a/UnitTests/Sources/RoomPollsHistoryScreenViewModelTests.swift b/UnitTests/Sources/RoomPollsHistoryScreenViewModelTests.swift index b72264b61..f5224df91 100644 --- a/UnitTests/Sources/RoomPollsHistoryScreenViewModelTests.swift +++ b/UnitTests/Sources/RoomPollsHistoryScreenViewModelTests.swift @@ -14,11 +14,11 @@ import Testing struct RoomPollsHistoryScreenViewModelTests { var viewModel: RoomPollsHistoryScreenViewModelProtocol! var interactionHandler: PollInteractionHandlerMock! - var timelineController: MockTimelineController! + var timelineController: TimelineControllerMock! init() throws { interactionHandler = PollInteractionHandlerMock() - timelineController = MockTimelineController() + timelineController = TimelineControllerMock(.init()) viewModel = RoomPollsHistoryScreenViewModel(pollInteractionHandler: interactionHandler, timelineController: timelineController, userIndicatorController: UserIndicatorControllerMock()) @@ -26,12 +26,12 @@ struct RoomPollsHistoryScreenViewModelTests { @Test func backPaginate() async throws { - timelineController.backPaginationResponses = [ + timelineController.setupBackPagination(responses: [ [PollRoomTimelineItem.mock(poll: .emptyDisclosed, isEditable: true), PollRoomTimelineItem.mock(poll: .disclosed(createdByAccountOwner: true)), PollRoomTimelineItem.mock(poll: .disclosed(createdByAccountOwner: false)), PollRoomTimelineItem.mock(poll: .endedDisclosed)] - ] + ]) let deferredViewState = deferFulfillment(viewModel.context.$viewState, keyPath: \.isBackPaginating, transitionValues: [false, true, false]) @@ -45,13 +45,13 @@ struct RoomPollsHistoryScreenViewModelTests { @Test func backPaginateCanBackPaginate() async throws { - timelineController.backPaginationResponses = [ + timelineController.setupBackPagination(responses: [ [PollRoomTimelineItem.mock(poll: .emptyDisclosed, isEditable: true), PollRoomTimelineItem.mock(poll: .disclosed(createdByAccountOwner: true)), PollRoomTimelineItem.mock(poll: .disclosed(createdByAccountOwner: false)), PollRoomTimelineItem.mock(poll: .endedDisclosed)], [] - ] + ]) let deferredViewState = deferFulfillment(viewModel.context.$viewState, keyPath: \.isBackPaginating, transitionValues: [false, true, false]) @@ -65,12 +65,12 @@ struct RoomPollsHistoryScreenViewModelTests { @Test func backPaginateTwice() async throws { - timelineController.backPaginationResponses = [ + timelineController.setupBackPagination(responses: [ [PollRoomTimelineItem.mock(poll: .emptyDisclosed, isEditable: true), PollRoomTimelineItem.mock(poll: .disclosed(createdByAccountOwner: true)), PollRoomTimelineItem.mock(poll: .disclosed(createdByAccountOwner: false))], [PollRoomTimelineItem.mock(poll: .endedDisclosed)] - ] + ]) let deferredViewState = deferFulfillment(viewModel.context.$viewState, keyPath: \.isBackPaginating, transitionValues: [false, true, false]) viewModel.context.send(viewAction: .loadMore) @@ -84,13 +84,13 @@ struct RoomPollsHistoryScreenViewModelTests { @Test func filters() async throws { - timelineController.backPaginationResponses = [ + timelineController.setupBackPagination(responses: [ [PollRoomTimelineItem.mock(poll: .emptyDisclosed, isEditable: true), PollRoomTimelineItem.mock(poll: .disclosed(createdByAccountOwner: true)), PollRoomTimelineItem.mock(poll: .disclosed(createdByAccountOwner: false)), PollRoomTimelineItem.mock(poll: .endedDisclosed)], [] - ] + ]) let deferredViewState = deferFulfillment(viewModel.context.$viewState) { value in !value.pollTimelineItems.isEmpty diff --git a/UnitTests/Sources/TimelineMediaPreviewViewModelTests.swift b/UnitTests/Sources/TimelineMediaPreviewViewModelTests.swift index 9cf64adf5..1feb60006 100644 --- a/UnitTests/Sources/TimelineMediaPreviewViewModelTests.swift +++ b/UnitTests/Sources/TimelineMediaPreviewViewModelTests.swift @@ -22,7 +22,7 @@ struct TimelineMediaPreviewViewModelTests { var mediaProvider: MediaProviderMock! var photoLibraryManager: PhotoLibraryManagerMock! - var timelineController: MockTimelineController! + var timelineController: TimelineControllerMock! @Test mutating func loadingItem() async throws { @@ -94,11 +94,10 @@ struct TimelineMediaPreviewViewModelTests { mutating func loadingMoreItems() async throws { // Given a view model with a loaded item. try await loadingItem() - #expect(timelineController.paginateBackwardsCallCount == 0) + #expect(timelineController.paginateBackwardsRequestSizeCallsCount == 0) // When swiping to a "loading more" item and there are more media items to load. - timelineController.paginationState = .init(backward: .idle, forward: .endReached) - timelineController.backPaginationResponses.append(RoomTimelineItemFixtures.mediaChunk) + timelineController.update(paginationState: .init(backward: .idle, forward: .endReached)) let failure = deferFailure(viewModel.state.previewControllerDriver, timeout: .seconds(1)) { $0.isItemLoaded } context.send(viewAction: .updateCurrentItem(.loading(.paginatingBackwards))) try await failure.fulfill() @@ -106,7 +105,7 @@ struct TimelineMediaPreviewViewModelTests { // Then there should no longer be a media preview and instead of loading any media, a pagination request should be made. #expect(mediaProvider.loadFileFromSourceFilenameCallsCount == 1) #expect(context.viewState.currentItem == .loading(.paginatingBackwards)) // Note: This item only changes when the preview controller handles the new items. - #expect(timelineController.paginateBackwardsCallCount == 1) + #expect(timelineController.paginateBackwardsRequestSizeCallsCount == 1) } @Test @@ -117,7 +116,7 @@ struct TimelineMediaPreviewViewModelTests { // When more items are added via a back pagination. let deferred = deferFulfillment(context.viewState.dataSource.previewItemsPaginationPublisher) { _ in true } - timelineController.backPaginationResponses.append(makeItems()) + timelineController.setupBackPagination(responses: [makeItems()]) _ = await timelineController.paginateBackwards(requestSize: 20) try await deferred.fulfill() @@ -292,7 +291,7 @@ struct TimelineMediaPreviewViewModelTests { private mutating func setupViewModel(initialItemIndex: Int = 0, photoLibraryAuthorizationDenied: Bool = false) { let initialItems = makeItems() - timelineController = MockTimelineController(timelineKind: .media(.mediaFilesScreen), timelineItems: initialItems) + timelineController = TimelineControllerMock(.init(timelineKind: .media(.mediaFilesScreen), timelineItems: initialItems)) mediaProvider = MediaProviderMock(.init()) photoLibraryManager = PhotoLibraryManagerMock(.init(authorizationDenied: photoLibraryAuthorizationDenied)) diff --git a/UnitTests/Sources/TimelineViewModelTests.swift b/UnitTests/Sources/TimelineViewModelTests.swift index f38c65bc3..8b6c11bfd 100644 --- a/UnitTests/Sources/TimelineViewModelTests.swift +++ b/UnitTests/Sources/TimelineViewModelTests.swift @@ -35,7 +35,7 @@ final class TimelineViewModelTests { ] // When showing them in a timeline. - let timelineController = MockTimelineController(timelineItems: items) + let timelineController = TimelineControllerMock(.init(timelineItems: items)) let viewModel = makeViewModel(timelineController: timelineController) // Then the messages should be grouped together. @@ -63,7 +63,7 @@ final class TimelineViewModelTests { ] // When showing them in a timeline. - let timelineController = MockTimelineController(timelineItems: items) + let timelineController = TimelineControllerMock(.init(timelineItems: items)) let viewModel = makeViewModel(timelineController: timelineController) // Then the messages should be grouped by sender. @@ -89,7 +89,7 @@ final class TimelineViewModelTests { ] // When showing them in a timeline. - let timelineController = MockTimelineController(timelineItems: items) + let timelineController = TimelineControllerMock(.init(timelineItems: items)) let viewModel = makeViewModel(timelineController: timelineController) // Then the first message should not be grouped but the other two should. @@ -112,7 +112,7 @@ final class TimelineViewModelTests { ] // When showing them in a timeline. - let timelineController = MockTimelineController(timelineItems: items) + let timelineController = TimelineControllerMock(.init(timelineItems: items)) let viewModel = makeViewModel(timelineController: timelineController) // Then the first and second messages should be grouped and the last one should not. @@ -135,7 +135,7 @@ final class TimelineViewModelTests { ] // When showing them in a timeline. - let timelineController = MockTimelineController(timelineItems: items) + let timelineController = TimelineControllerMock(.init(timelineItems: items)) let viewModel = makeViewModel(timelineController: timelineController) // Then the messages should be grouped together. @@ -152,10 +152,10 @@ final class TimelineViewModelTests { let items = [TextRoomTimelineItem(eventID: "t1"), TextRoomTimelineItem(eventID: "t2"), TextRoomTimelineItem(eventID: "t3")] - let timelineController = MockTimelineController(timelineItems: items) + let timelineController = TimelineControllerMock(.init(timelineItems: items)) let viewModel = makeViewModel(timelineController: timelineController) - #expect(timelineController.focusOnEventCallCount == 0) + #expect(timelineController.focusOnEventTimelineSizeCallsCount == 0) #expect(viewModel.context.viewState.timelineState.isLive) #expect(viewModel.context.viewState.timelineState.focussedEvent == nil) @@ -165,7 +165,7 @@ final class TimelineViewModelTests { try await deferred.fulfill() // Then a new timeline should be loaded and the room focussed on that event. - #expect(timelineController.focusOnEventCallCount == 1) + #expect(timelineController.focusOnEventTimelineSizeCallsCount == 1) #expect(!viewModel.context.viewState.timelineState.isLive) #expect(viewModel.context.viewState.timelineState.focussedEvent == .init(eventID: "t4", appearance: .immediate)) } @@ -176,10 +176,10 @@ final class TimelineViewModelTests { let items = [TextRoomTimelineItem(eventID: "t1"), TextRoomTimelineItem(eventID: "t2"), TextRoomTimelineItem(eventID: "t3")] - let timelineController = MockTimelineController(timelineItems: items) + let timelineController = TimelineControllerMock(.init(timelineItems: items)) let viewModel = makeViewModel(timelineController: timelineController) - #expect(timelineController.focusOnEventCallCount == 0) + #expect(timelineController.focusOnEventTimelineSizeCallsCount == 0) #expect(viewModel.context.viewState.timelineState.isLive) #expect(viewModel.context.viewState.timelineState.focussedEvent == nil) @@ -189,7 +189,7 @@ final class TimelineViewModelTests { try await deferred.fulfill() // Then the timeline should remain live and the item should be focussed. - #expect(timelineController.focusOnEventCallCount == 0) + #expect(timelineController.focusOnEventTimelineSizeCallsCount == 0) #expect(viewModel.context.viewState.timelineState.isLive) #expect(viewModel.context.viewState.timelineState.focussedEvent == .init(eventID: "t1", appearance: .animated)) } @@ -200,7 +200,7 @@ final class TimelineViewModelTests { let items = [TextRoomTimelineItem(eventID: "t1"), TextRoomTimelineItem(eventID: "t2"), TextRoomTimelineItem(eventID: "t3")] - let timelineController = MockTimelineController(timelineItems: items) + let timelineController = TimelineControllerMock(.init(timelineItems: items)) let viewModel = makeViewModel(timelineController: timelineController) @@ -208,7 +208,7 @@ final class TimelineViewModelTests { await viewModel.focusOnEvent(eventID: "t4") try await deferred.fulfill() - #expect(timelineController.focusLiveCallCount == 0) + #expect(timelineController.focusLiveCallsCount == 0) #expect(!viewModel.context.viewState.timelineState.isLive) #expect(viewModel.context.viewState.timelineState.focussedEvent == .init(eventID: "t4", appearance: .immediate)) @@ -218,14 +218,14 @@ final class TimelineViewModelTests { try await deferred.fulfill() // Then the timeline should switch back to being live and the event focus should be removed. - #expect(timelineController.focusLiveCallCount == 1) + #expect(timelineController.focusLiveCallsCount == 1) #expect(viewModel.context.viewState.timelineState.isLive) #expect(viewModel.context.viewState.timelineState.focussedEvent == nil) } @Test func initialFocusViewState() { - let timelineController = MockTimelineController() + let timelineController = TimelineControllerMock(.init()) let viewModel = makeViewModel(focussedEventID: "t10", timelineController: timelineController) #expect(viewModel.context.viewState.timelineState.focussedEvent == .init(eventID: "t10", appearance: .immediate)) @@ -285,14 +285,14 @@ final class TimelineViewModelTests { private func readReceiptsConfiguration(with items: [RoomTimelineItemProtocol]) -> (TimelineViewModel, JoinedRoomProxyMock, TimelineProxyMock, - MockTimelineController) { + TimelineControllerMock) { let timelineProxy = TimelineProxyMock() timelineProxy.sendReadReceiptForTypeReturnValue = .success(()) let roomProxy = JoinedRoomProxyMock(.init(name: "")) roomProxy.timeline = timelineProxy - let timelineController = MockTimelineController(roomProxy: roomProxy, timelineItems: items) + let timelineController = TimelineControllerMock(.init(roomProxy: roomProxy, timelineItems: items)) let appSettings = AppSettings.volatile() @@ -323,7 +323,7 @@ final class TimelineViewModelTests { let appSettings = AppSettings.volatile() // When showing them in a timeline. - let timelineController = MockTimelineController(timelineItems: [message]) + let timelineController = TimelineControllerMock(.init(timelineItems: [message])) let viewModel = TimelineViewModel(roomProxy: JoinedRoomProxyMock(.init(name: "", members: [RoomMemberProxyMock.mockAlice, RoomMemberProxyMock.mockCharlie])), timelineController: timelineController, userSession: UserSessionMock(.init()), @@ -352,7 +352,7 @@ final class TimelineViewModelTests { members: [RoomMemberProxyMock.mockAdmin, RoomMemberProxyMock.mockAlice], ownUserID: RoomMemberProxyMock.mockAdmin.userID)), - timelineController: MockTimelineController(), + timelineController: TimelineControllerMock(.init()), userSession: UserSessionMock(.init()), mediaPlayerProvider: MediaPlayerProviderMock(), userIndicatorController: UserIndicatorControllerMock(), @@ -391,7 +391,7 @@ final class TimelineViewModelTests { members: [RoomMemberProxyMock.mockAdmin, RoomMemberProxyMock.mockAlice], ownUserID: RoomMemberProxyMock.mockAlice.userID)), - timelineController: MockTimelineController(), + timelineController: TimelineControllerMock(.init()), userSession: UserSessionMock(.init()), mediaPlayerProvider: MediaPlayerProviderMock(), userIndicatorController: UserIndicatorControllerMock(), @@ -430,7 +430,7 @@ final class TimelineViewModelTests { members: [RoomMemberProxyMock.mockAdmin, RoomMemberProxyMock.mockBanned[0]], ownUserID: RoomMemberProxyMock.mockAdmin.userID)), - timelineController: MockTimelineController(), + timelineController: TimelineControllerMock(.init()), userSession: UserSessionMock(.init()), mediaPlayerProvider: MediaPlayerProviderMock(), userIndicatorController: UserIndicatorControllerMock(), @@ -475,7 +475,7 @@ final class TimelineViewModelTests { roomProxyMock.underlyingInfoPublisher = infoSubject.asCurrentValuePublisher() let viewModel = TimelineViewModel(roomProxy: roomProxyMock, - timelineController: MockTimelineController(), + timelineController: TimelineControllerMock(.init()), userSession: UserSessionMock(.init()), mediaPlayerProvider: MediaPlayerProviderMock(), userIndicatorController: UserIndicatorControllerMock(), @@ -506,7 +506,7 @@ final class TimelineViewModelTests { roomProxyMock.underlyingInfoPublisher = infoSubject.asCurrentValuePublisher() let viewModel = TimelineViewModel(roomProxy: roomProxyMock, - timelineController: MockTimelineController(), + timelineController: TimelineControllerMock(.init()), userSession: UserSessionMock(.init()), mediaPlayerProvider: MediaPlayerProviderMock(), userIndicatorController: UserIndicatorControllerMock(), @@ -543,7 +543,7 @@ final class TimelineViewModelTests { func tapSendInfoEncryptionAuthentictyDisplaysAlert() { // Given a room with an event whose authenticity could not be verified let items = [TextRoomTimelineItem(eventID: "t1", encryptionAuthenticity: .verificationViolation(color: .red))] - let timelineController = MockTimelineController(timelineItems: items) + let timelineController = TimelineControllerMock(.init(timelineItems: items)) let viewModel = makeViewModel(timelineController: timelineController) #expect(viewModel.state.bindings.alertInfo == nil) @@ -557,7 +557,7 @@ final class TimelineViewModelTests { func tapSendInfoEncryptionForwarderDisplaysAlert() { // Given a room with an event whose key was forwarded let items = [TextRoomTimelineItem(eventID: "t1", keyForwarder: .test)] - let timelineController = MockTimelineController(timelineItems: items) + let timelineController = TimelineControllerMock(.init(timelineItems: items)) let viewModel = makeViewModel(timelineController: timelineController) #expect(viewModel.state.bindings.alertInfo == nil) diff --git a/UnitTests/Sources/VoiceMessageRecorderTests.swift b/UnitTests/Sources/VoiceMessageRecorderTests.swift index 921393fe8..97c26a3bc 100644 --- a/UnitTests/Sources/VoiceMessageRecorderTests.swift +++ b/UnitTests/Sources/VoiceMessageRecorderTests.swift @@ -205,7 +205,7 @@ struct VoiceMessageRecorderTests { @Test func sendVoiceMessage_NoRecordingFile() async { - let timelineController = MockTimelineController() + let timelineController = TimelineControllerMock(.init()) // If there is no recording file, an error is expected audioRecorder.audioFileURL = nil @@ -222,7 +222,7 @@ struct VoiceMessageRecorderTests { // If the converter returns an error audioConverter.convertToOpusOggSourceURLDestinationURLThrowableError = AudioConverterError.conversionFailed(nil) - let timelineController = MockTimelineController() + let timelineController = TimelineControllerMock(.init()) guard case .failure(.failedSendingVoiceMessage) = await voiceMessageRecorder.sendVoiceMessage(timelineController: timelineController, audioConverter: audioConverter) else { Issue.record("An error is expected") @@ -239,7 +239,7 @@ struct VoiceMessageRecorderTests { } let timelineProxy = TimelineProxyMock() - let timelineController = MockTimelineController(timelineProxy: timelineProxy) + let timelineController = TimelineControllerMock(.init(timelineProxy: timelineProxy)) timelineProxy.sendVoiceMessageUrlAudioInfoWaveformRequestHandleReturnValue = .failure(.sdkError(SDKError.generic)) guard case .failure(.failedSendingVoiceMessage) = await voiceMessageRecorder.sendVoiceMessage(timelineController: timelineController, audioConverter: audioConverter) else { @@ -258,7 +258,7 @@ struct VoiceMessageRecorderTests { } let timelineProxy = TimelineProxyMock() - let timelineController = MockTimelineController(timelineProxy: timelineProxy) + let timelineController = TimelineControllerMock(.init(timelineProxy: timelineProxy)) timelineProxy.sendVoiceMessageUrlAudioInfoWaveformRequestHandleReturnValue = .failure(.sdkError(SDKError.generic)) guard case .failure(.failedSendingVoiceMessage) = await voiceMessageRecorder.sendVoiceMessage(timelineController: timelineController, audioConverter: audioConverter) else { @@ -279,7 +279,7 @@ struct VoiceMessageRecorderTests { // If the media upload fails let timelineProxy = TimelineProxyMock() - let timelineController = MockTimelineController(timelineProxy: timelineProxy) + let timelineController = TimelineControllerMock(.init(timelineProxy: timelineProxy)) timelineProxy.sendVoiceMessageUrlAudioInfoWaveformRequestHandleReturnValue = .failure(.sdkError(SDKError.generic)) guard case .failure(.failedSendingVoiceMessage) = await voiceMessageRecorder.sendVoiceMessage(timelineController: timelineController, audioConverter: audioConverter) else { @@ -293,7 +293,7 @@ struct VoiceMessageRecorderTests { let imageFileURL = try #require(Bundle(for: UnitTestsAppCoordinator.self).url(forResource: "test_voice_message", withExtension: "m4a"), "Test audio file is missing") let timelineProxy = TimelineProxyMock() - let timelineController = MockTimelineController(timelineProxy: timelineProxy) + let timelineController = TimelineControllerMock(.init(timelineProxy: timelineProxy)) audioRecorder.currentTime = 42 audioRecorder.audioFileURL = imageFileURL _ = await voiceMessageRecorder.startRecording()