// // Copyright 2023, 2024 New Vector Ltd. // // SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial // Please see LICENSE files in the repository root for full details. // import Combine import XCTest @testable import ElementX @MainActor class PillContextTests: XCTestCase { func testUser() async { let id = "@test:matrix.org" let proxyMock = JoinedRoomProxyMock(.init(name: "Test")) let subject = CurrentValueSubject<[RoomMemberProxyProtocol], Never>([]) proxyMock.membersPublisher = subject.asCurrentValuePublisher() let mock = TimelineViewModel(roomProxy: proxyMock, timelineController: MockTimelineController(), mediaProvider: MediaProviderMock(configuration: .init()), mediaPlayerProvider: MediaPlayerProviderMock(), voiceMessageMediaManager: VoiceMessageMediaManagerMock(), userIndicatorController: ServiceLocator.shared.userIndicatorController, appMediator: AppMediatorMock.default, appSettings: ServiceLocator.shared.settings, analyticsService: ServiceLocator.shared.analytics, emojiProvider: EmojiProvider(appSettings: ServiceLocator.shared.settings), timelineControllerFactory: TimelineControllerFactoryMock(.init()), clientProxy: ClientProxyMock(.init())) let context = PillContext(timelineContext: mock.context, data: PillTextAttachmentData(type: .user(userID: id), font: .preferredFont(forTextStyle: .body))) XCTAssertFalse(context.viewState.isOwnMention) XCTAssertEqual(context.viewState.displayText, id) let name = "Mr. Test" let avatarURL = URL(string: "https://test.jpg") subject.send([RoomMemberProxyMock(with: .init(userID: id, displayName: name, avatarURL: avatarURL, membership: .join))]) await Task.yield() XCTAssertFalse(context.viewState.isOwnMention) XCTAssertNil(context.viewState.image) XCTAssertEqual(context.viewState.displayText, "@\(name)") } func testOwnUser() { let id = "@test:matrix.org" let proxyMock = JoinedRoomProxyMock(.init(name: "Test", ownUserID: id)) let subject = CurrentValueSubject<[RoomMemberProxyProtocol], Never>([]) proxyMock.membersPublisher = subject.asCurrentValuePublisher() let mock = TimelineViewModel(roomProxy: proxyMock, timelineController: MockTimelineController(), mediaProvider: MediaProviderMock(configuration: .init()), mediaPlayerProvider: MediaPlayerProviderMock(), voiceMessageMediaManager: VoiceMessageMediaManagerMock(), userIndicatorController: ServiceLocator.shared.userIndicatorController, appMediator: AppMediatorMock.default, appSettings: ServiceLocator.shared.settings, analyticsService: ServiceLocator.shared.analytics, emojiProvider: EmojiProvider(appSettings: ServiceLocator.shared.settings), timelineControllerFactory: TimelineControllerFactoryMock(.init()), clientProxy: ClientProxyMock(.init())) let context = PillContext(timelineContext: mock.context, data: PillTextAttachmentData(type: .user(userID: id), font: .preferredFont(forTextStyle: .body))) XCTAssertNil(context.viewState.image) XCTAssertTrue(context.viewState.isOwnMention) } func testAllUsers() { let avatarURL = URL(string: "https://matrix.jpg") let id = "test_room" let displayName = "Test" let proxyMock = JoinedRoomProxyMock(.init(id: id, name: displayName, avatarURL: avatarURL)) let mockController = MockTimelineController() mockController.roomProxy = proxyMock let mock = TimelineViewModel(roomProxy: proxyMock, timelineController: mockController, mediaProvider: MediaProviderMock(configuration: .init()), mediaPlayerProvider: MediaPlayerProviderMock(), voiceMessageMediaManager: VoiceMessageMediaManagerMock(), userIndicatorController: ServiceLocator.shared.userIndicatorController, appMediator: AppMediatorMock.default, appSettings: ServiceLocator.shared.settings, analyticsService: ServiceLocator.shared.analytics, emojiProvider: EmojiProvider(appSettings: ServiceLocator.shared.settings), timelineControllerFactory: TimelineControllerFactoryMock(.init()), clientProxy: ClientProxyMock(.init())) let context = PillContext(timelineContext: mock.context, data: PillTextAttachmentData(type: .allUsers, font: .preferredFont(forTextStyle: .body))) XCTAssertTrue(context.viewState.isOwnMention) XCTAssertNil(context.viewState.image) XCTAssertEqual(context.viewState.displayText, PillConstants.atRoom) } func testRoomIDMention() { let proxyMock = JoinedRoomProxyMock(.init()) let mockController = MockTimelineController() let clientMock = ClientProxyMock(.init()) clientMock.roomSummaryForIdentifierReturnValue = .mock(id: "1", name: "Foundation 🔭🪐🌌") mockController.roomProxy = proxyMock let mock = TimelineViewModel(roomProxy: proxyMock, timelineController: mockController, mediaProvider: MediaProviderMock(configuration: .init()), mediaPlayerProvider: MediaPlayerProviderMock(), voiceMessageMediaManager: VoiceMessageMediaManagerMock(), userIndicatorController: ServiceLocator.shared.userIndicatorController, appMediator: AppMediatorMock.default, appSettings: ServiceLocator.shared.settings, analyticsService: ServiceLocator.shared.analytics, emojiProvider: EmojiProvider(appSettings: ServiceLocator.shared.settings), timelineControllerFactory: TimelineControllerFactoryMock(.init()), clientProxy: clientMock) let context = PillContext(timelineContext: mock.context, data: PillTextAttachmentData(type: .roomID("1"), font: .preferredFont(forTextStyle: .body))) XCTAssertFalse(context.viewState.isOwnMention) XCTAssertFalse(context.viewState.isUndefined) XCTAssertEqual(context.viewState.image, .roomAvatar(.room(id: "1", name: "Foundation 🔭🪐🌌", avatarURL: nil))) XCTAssertEqual(context.viewState.displayText, "Foundation 🔭🪐🌌") } func testRoomIDMentionMissingRoom() { let proxyMock = JoinedRoomProxyMock(.init()) let mockController = MockTimelineController() mockController.roomProxy = proxyMock let mock = TimelineViewModel(roomProxy: proxyMock, timelineController: mockController, mediaProvider: MediaProviderMock(configuration: .init()), mediaPlayerProvider: MediaPlayerProviderMock(), voiceMessageMediaManager: VoiceMessageMediaManagerMock(), userIndicatorController: ServiceLocator.shared.userIndicatorController, appMediator: AppMediatorMock.default, appSettings: ServiceLocator.shared.settings, analyticsService: ServiceLocator.shared.analytics, emojiProvider: EmojiProvider(appSettings: ServiceLocator.shared.settings), timelineControllerFactory: TimelineControllerFactoryMock(.init()), clientProxy: ClientProxyMock(.init())) let context = PillContext(timelineContext: mock.context, data: PillTextAttachmentData(type: .roomID("1"), font: .preferredFont(forTextStyle: .body))) XCTAssertFalse(context.viewState.isOwnMention) XCTAssertFalse(context.viewState.isUndefined) XCTAssertEqual(context.viewState.image, .link) XCTAssertEqual(context.viewState.displayText, "1") } func testRoomAliasMention() { let proxyMock = JoinedRoomProxyMock(.init()) let mockController = MockTimelineController() mockController.roomProxy = proxyMock let clientMock = ClientProxyMock(.init()) clientMock.roomSummaryForAliasReturnValue = .mock(id: "2", name: "Foundation and Empire", canonicalAlias: "#foundation-and-empire:matrix.org") let mock = TimelineViewModel(roomProxy: proxyMock, timelineController: mockController, mediaProvider: MediaProviderMock(configuration: .init()), mediaPlayerProvider: MediaPlayerProviderMock(), voiceMessageMediaManager: VoiceMessageMediaManagerMock(), userIndicatorController: ServiceLocator.shared.userIndicatorController, appMediator: AppMediatorMock.default, appSettings: ServiceLocator.shared.settings, analyticsService: ServiceLocator.shared.analytics, emojiProvider: EmojiProvider(appSettings: ServiceLocator.shared.settings), timelineControllerFactory: TimelineControllerFactoryMock(.init()), clientProxy: clientMock) let context = PillContext(timelineContext: mock.context, data: PillTextAttachmentData(type: .roomAlias("#foundation-and-empire:matrix.org"), font: .preferredFont(forTextStyle: .body))) XCTAssertFalse(context.viewState.isOwnMention) XCTAssertFalse(context.viewState.isUndefined) XCTAssertEqual(context.viewState.image, .roomAvatar(.room(id: "2", name: "Foundation and Empire", avatarURL: nil))) XCTAssertEqual(context.viewState.displayText, "Foundation and Empire") } func testRoomAliasMentionMissingRoom() { let proxyMock = JoinedRoomProxyMock(.init()) let mockController = MockTimelineController() mockController.roomProxy = proxyMock let mock = TimelineViewModel(roomProxy: proxyMock, timelineController: mockController, mediaProvider: MediaProviderMock(configuration: .init()), mediaPlayerProvider: MediaPlayerProviderMock(), voiceMessageMediaManager: VoiceMessageMediaManagerMock(), userIndicatorController: ServiceLocator.shared.userIndicatorController, appMediator: AppMediatorMock.default, appSettings: ServiceLocator.shared.settings, analyticsService: ServiceLocator.shared.analytics, emojiProvider: EmojiProvider(appSettings: ServiceLocator.shared.settings), timelineControllerFactory: TimelineControllerFactoryMock(.init()), clientProxy: ClientProxyMock(.init())) let context = PillContext(timelineContext: mock.context, data: PillTextAttachmentData(type: .roomAlias("#foundation-and-empire:matrix.org"), font: .preferredFont(forTextStyle: .body))) XCTAssertFalse(context.viewState.isOwnMention) XCTAssertFalse(context.viewState.isUndefined) XCTAssertEqual(context.viewState.image, .link) XCTAssertEqual(context.viewState.displayText, "#foundation-and-empire:matrix.org") } func testEventOnRoomIDMention() { let proxyMock = JoinedRoomProxyMock(.init()) let mockController = MockTimelineController() mockController.roomProxy = proxyMock let clientMock = ClientProxyMock(.init()) clientMock.roomSummaryForIdentifierReturnValue = .mock(id: "1", name: "Foundation 🔭🪐🌌") let mock = TimelineViewModel(roomProxy: proxyMock, timelineController: mockController, mediaProvider: MediaProviderMock(configuration: .init()), mediaPlayerProvider: MediaPlayerProviderMock(), voiceMessageMediaManager: VoiceMessageMediaManagerMock(), userIndicatorController: ServiceLocator.shared.userIndicatorController, appMediator: AppMediatorMock.default, appSettings: ServiceLocator.shared.settings, analyticsService: ServiceLocator.shared.analytics, emojiProvider: EmojiProvider(appSettings: ServiceLocator.shared.settings), timelineControllerFactory: TimelineControllerFactoryMock(.init()), clientProxy: clientMock) let context = PillContext(timelineContext: mock.context, data: PillTextAttachmentData(type: .event(room: .roomID("1")), font: .preferredFont(forTextStyle: .body))) XCTAssertFalse(context.viewState.isOwnMention) XCTAssertFalse(context.viewState.isUndefined) XCTAssertEqual(context.viewState.image, .link) XCTAssertEqual(context.viewState.displayText, L10n.screenRoomEventPill("Foundation 🔭🪐🌌")) } func testEventOnRoomIDMentionMissingRoom() { let proxyMock = JoinedRoomProxyMock(.init()) let mockController = MockTimelineController() mockController.roomProxy = proxyMock let mock = TimelineViewModel(roomProxy: proxyMock, timelineController: mockController, mediaProvider: MediaProviderMock(configuration: .init()), mediaPlayerProvider: MediaPlayerProviderMock(), voiceMessageMediaManager: VoiceMessageMediaManagerMock(), userIndicatorController: ServiceLocator.shared.userIndicatorController, appMediator: AppMediatorMock.default, appSettings: ServiceLocator.shared.settings, analyticsService: ServiceLocator.shared.analytics, emojiProvider: EmojiProvider(appSettings: ServiceLocator.shared.settings), timelineControllerFactory: TimelineControllerFactoryMock(.init()), clientProxy: ClientProxyMock(.init())) let context = PillContext(timelineContext: mock.context, data: PillTextAttachmentData(type: .event(room: .roomID("1")), font: .preferredFont(forTextStyle: .body))) XCTAssertFalse(context.viewState.isOwnMention) XCTAssertFalse(context.viewState.isUndefined) XCTAssertEqual(context.viewState.image, .link) XCTAssertEqual(context.viewState.displayText, L10n.screenRoomEventPill(L10n.commonRoom)) } func testEventOnRoomAliasMention() async throws { let proxyMock = JoinedRoomProxyMock(.init()) let mockController = MockTimelineController() mockController.roomProxy = proxyMock let clientMock = ClientProxyMock(.init()) clientMock.roomSummaryForAliasReturnValue = .mock(id: "2", name: "Foundation and Empire", canonicalAlias: "#foundation-and-empire:matrix.org") let mock = TimelineViewModel(roomProxy: proxyMock, timelineController: mockController, mediaProvider: MediaProviderMock(configuration: .init()), mediaPlayerProvider: MediaPlayerProviderMock(), voiceMessageMediaManager: VoiceMessageMediaManagerMock(), userIndicatorController: ServiceLocator.shared.userIndicatorController, appMediator: AppMediatorMock.default, appSettings: ServiceLocator.shared.settings, analyticsService: ServiceLocator.shared.analytics, emojiProvider: EmojiProvider(appSettings: ServiceLocator.shared.settings), timelineControllerFactory: TimelineControllerFactoryMock(.init()), clientProxy: clientMock) let context = PillContext(timelineContext: mock.context, data: PillTextAttachmentData(type: .event(room: .roomAlias("#foundation-and-empire:matrix.org")), font: .preferredFont(forTextStyle: .body))) XCTAssertFalse(context.viewState.isOwnMention) XCTAssertFalse(context.viewState.isUndefined) XCTAssertEqual(context.viewState.image, .link) XCTAssertEqual(context.viewState.displayText, L10n.screenRoomEventPill("Foundation and Empire")) } func testEventOnRoomAliasMentionMissingRoom() async throws { let proxyMock = JoinedRoomProxyMock(.init()) let mockController = MockTimelineController() mockController.roomProxy = proxyMock let mock = TimelineViewModel(roomProxy: proxyMock, timelineController: mockController, mediaProvider: MediaProviderMock(configuration: .init()), mediaPlayerProvider: MediaPlayerProviderMock(), voiceMessageMediaManager: VoiceMessageMediaManagerMock(), userIndicatorController: ServiceLocator.shared.userIndicatorController, appMediator: AppMediatorMock.default, appSettings: ServiceLocator.shared.settings, analyticsService: ServiceLocator.shared.analytics, emojiProvider: EmojiProvider(appSettings: ServiceLocator.shared.settings), timelineControllerFactory: TimelineControllerFactoryMock(.init()), clientProxy: ClientProxyMock(.init())) let context = PillContext(timelineContext: mock.context, data: PillTextAttachmentData(type: .event(room: .roomAlias("#foundation-and-empire:matrix.org")), font: .preferredFont(forTextStyle: .body))) XCTAssertFalse(context.viewState.isOwnMention) XCTAssertFalse(context.viewState.isUndefined) XCTAssertEqual(context.viewState.image, .link) XCTAssertEqual(context.viewState.displayText, L10n.screenRoomEventPill(L10n.commonRoom)) } }