From bf9b82334d056e2540d19bc32b7a3c583b32b549 Mon Sep 17 00:00:00 2001 From: Aleksandrs Proskurins Date: Fri, 6 Jan 2023 12:53:19 +0200 Subject: [PATCH] User sessions tests (#390) * User sessions tests * Refactor - Merge SessionVerificationControllerProxyMock into MockSessionVerificationControllerProxy. - Merge ClientProxyMock into MockClientProxy. - Simplify naming. Co-authored-by: Doug --- ElementX.xcodeproj/project.pbxproj | 24 ++-- .../Services/Client/MockClientProxy.swift | 36 +++++- ...ckSessionVerificationControllerProxy.swift | 9 +- .../NotificationManager/ClientProxySpy.swift | 116 ------------------ .../NotificationManagerTests.swift | 86 ++++++------- .../UserSession/UserSessionTests.swift | 88 +++++++++++++ changelog.d/pr-390.change | 1 + 7 files changed, 185 insertions(+), 175 deletions(-) delete mode 100644 UnitTests/Sources/NotificationManager/ClientProxySpy.swift create mode 100644 UnitTests/Sources/UserSession/UserSessionTests.swift create mode 100644 changelog.d/pr-390.change diff --git a/ElementX.xcodeproj/project.pbxproj b/ElementX.xcodeproj/project.pbxproj index 2291695a8..76fb68980 100644 --- a/ElementX.xcodeproj/project.pbxproj +++ b/ElementX.xcodeproj/project.pbxproj @@ -255,14 +255,15 @@ 8024BE37156FF0A95A7A3465 /* AnalyticsPromptUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF11DD57D9FACF2A757AB024 /* AnalyticsPromptUITests.swift */; }; 80D00A7C62AAB44F54725C43 /* PermalinkBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = F754E66A8970963B15B2A41E /* PermalinkBuilder.swift */; }; 8196A2E71ACC902DD69F24EE /* UserNotificationControllerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0DE6C5C756E1393202BA95CD /* UserNotificationControllerTests.swift */; }; + 81A7C020CB5F6232242A8414 /* UserSessionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = F36C0A6D59717193F49EA986 /* UserSessionTests.swift */; }; 829062DD3C3F7016FE1A6476 /* RoomDetailsScreenUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3BFDAF6918BB096C44788FC9 /* RoomDetailsScreenUITests.swift */; }; 83E5054739949181CA981193 /* LoginCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD667C4BB98CF4F3FE2CE3B0 /* LoginCoordinator.swift */; }; 85AFBB433AD56704A880F8A0 /* FramePreferenceKey.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4798B3B7A1E8AE3901CEE8C6 /* FramePreferenceKey.swift */; }; - 85DB5F55FC407DDB6A4F01C9 /* test_image.png in Resources */ = {isa = PBXBuildFile; fileRef = 0D15170391F27AF6718D4F2A /* test_image.png */; }; 86675910612A12409262DFBD /* SessionVerificationStateMachineTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A1C22B1B5FA3A765EADB2CC9 /* SessionVerificationStateMachineTests.swift */; }; 8691186F9B99BCDDB7CACDD8 /* KeychainController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E36CB905A2B9EC2C92A2DA7C /* KeychainController.swift */; }; 86C2E93920FD15AD17E193A9 /* BugReportViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7E532D95330139D118A9BF88 /* BugReportViewModel.swift */; }; 872A6457DF573AF8CEAE927A /* LoginHomeserver.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9349F590E35CE514A71E6764 /* LoginHomeserver.swift */; }; + 87315D70BABB38CFBC8CFF61 /* test_image.png in Resources */ = {isa = PBXBuildFile; fileRef = 7EF42E492B7599EBCB4A4174 /* test_image.png */; }; 87756CA950ED55870A1AAE8F /* ServerSelectionCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9D7D706FFF438CAF16F44D8C /* ServerSelectionCoordinator.swift */; }; 87BD4F95F9D603C309837378 /* UserNotification.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA6B262D7584C65BC5B79A0E /* UserNotification.swift */; }; 8810A2A30A68252EBB54EE05 /* HomeScreenModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 71BC7CA1BC1041E93077BBA1 /* HomeScreenModels.swift */; }; @@ -342,7 +343,6 @@ ABF3FAB234AD3565B214309B /* TimelineSenderAvatarView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0BC588051E6572A1AF51D738 /* TimelineSenderAvatarView.swift */; }; AC5CC8250CEAE57B73900C57 /* UserNotificationModalView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD80F22830C2360F3F39DDCE /* UserNotificationModalView.swift */; }; AC69B6DF15FC451AB2945036 /* UserSessionStoreProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = BEBA759D1347CFFB3D84ED1F /* UserSessionStoreProtocol.swift */; }; - ACAB49022C2EBD00AFC67729 /* ClientProxySpy.swift in Sources */ = {isa = PBXBuildFile; fileRef = F1924EF73801E03610E0F2AB /* ClientProxySpy.swift */; }; ACF094CF3BF02DBFA6DFDE60 /* AuthenticationCoordinatorUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5D2D0A6F1ABC99D29462FB84 /* AuthenticationCoordinatorUITests.swift */; }; AD2A81B65A9F6163012086F1 /* MXLog.swift in Sources */ = {isa = PBXBuildFile; fileRef = 111B698739E3410E2CDB7144 /* MXLog.swift */; }; AEE3981A0F090208E4445808 /* MockNotificationServiceProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2B37DCC9025452F46F91340E /* MockNotificationServiceProxy.swift */; }; @@ -554,7 +554,6 @@ 0C13A92C1E9C79F055B8133D /* ar */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = ar; path = ar.lproj/Localizable.stringsdict; sourceTree = ""; }; 0C88046D6A070D9827181C4D /* OnboardingUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnboardingUITests.swift; sourceTree = ""; }; 0CB569EAA5017B5B23970655 /* pt */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = pt; path = pt.lproj/Localizable.strings; sourceTree = ""; }; - 0D15170391F27AF6718D4F2A /* test_image.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = test_image.png; sourceTree = ""; }; 0D8F620C8B314840D8602E3F /* NSE.appex */ = {isa = PBXFileReference; includeInIndex = 0; lastKnownFileType = "wrapper.app-extension"; path = NSE.appex; sourceTree = BUILT_PRODUCTS_DIR; }; 0DB634B42CFE667112369D57 /* VideoPlayerScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VideoPlayerScreen.swift; sourceTree = ""; }; 0DD16CE9A66C9040B066AD60 /* vi */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = vi; path = vi.lproj/Localizable.stringsdict; sourceTree = ""; }; @@ -780,6 +779,7 @@ 7DDBF99755A9008CF8C8499E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = Info.plist; sourceTree = ""; }; 7E154FEA1E6FE964D3DF7859 /* fy */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fy; path = fy.lproj/Localizable.strings; sourceTree = ""; }; 7E532D95330139D118A9BF88 /* BugReportViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BugReportViewModel.swift; sourceTree = ""; }; + 7EF42E492B7599EBCB4A4174 /* test_image.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = test_image.png; sourceTree = ""; }; 7FB27E1BE894F9F9F0134372 /* FilePreviewScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FilePreviewScreen.swift; sourceTree = ""; }; 813B198AE8833FD12E5A9C78 /* RoomDetailsCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomDetailsCoordinator.swift; sourceTree = ""; }; 8140010A796DB2C7977B6643 /* pl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = pl; path = pl.lproj/Localizable.strings; sourceTree = ""; }; @@ -1033,12 +1033,12 @@ F118CF7C5548099AACF7E90C /* RoomMembersCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomMembersCoordinator.swift; sourceTree = ""; }; F15BE37BE2FB86E00C8D150A /* AggregratedReaction.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AggregratedReaction.swift; sourceTree = ""; }; F174A5627CDB3CAF280D1880 /* EmojiPickerScreenModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmojiPickerScreenModels.swift; sourceTree = ""; }; - F1924EF73801E03610E0F2AB /* ClientProxySpy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ClientProxySpy.swift; sourceTree = ""; }; F23BA6D4842D53C5AC9B7584 /* nn */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = nn; path = nn.lproj/Localizable.stringsdict; sourceTree = ""; }; F2D58333B377888012740101 /* LoginViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoginViewModel.swift; sourceTree = ""; }; F31A4E5941ACBA4BB9FEF94C /* UserNotificationToastView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserNotificationToastView.swift; sourceTree = ""; }; F31F59030205A6F65B057E1A /* MatrixEntityRegexTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MatrixEntityRegexTests.swift; sourceTree = ""; }; F3648F2FADEF2672D6A0D489 /* FileCacheTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FileCacheTests.swift; sourceTree = ""; }; + F36C0A6D59717193F49EA986 /* UserSessionTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserSessionTests.swift; sourceTree = ""; }; F3EAE3E9D5EF4A6D5D9C6CFD /* EmojiPickerScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmojiPickerScreenViewModel.swift; sourceTree = ""; }; F506C6ADB1E1DA6638078E11 /* UITests.xctest */ = {isa = PBXFileReference; includeInIndex = 0; lastKnownFileType = wrapper.cfbundle; path = UITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; F5C4AF6E3885730CD560311C /* ScreenshotDetector.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScreenshotDetector.swift; sourceTree = ""; }; @@ -1524,6 +1524,14 @@ path = Scripts; sourceTree = ""; }; + 53280D2292E6C9C7821773FD /* UserSession */ = { + isa = PBXGroup; + children = ( + F36C0A6D59717193F49EA986 /* UserSessionTests.swift */, + ); + path = UserSession; + sourceTree = ""; + }; 5329E48968EB951235E83DAE /* SessionVerification */ = { isa = PBXGroup; children = ( @@ -1723,6 +1731,7 @@ EB3B237387B8288A5A938F1B /* UserAgentBuilderTests.swift */, 0DE6C5C756E1393202BA95CD /* UserNotificationControllerTests.swift */, A3004DFA1B10951962787D90 /* VideoPlayerViewModelTests.swift */, + 53280D2292E6C9C7821773FD /* UserSession */, 7583EAC171059A86B767209F /* MediaProvider */, 7DBC911559934065993A5FF4 /* NotificationManager */, ); @@ -1848,7 +1857,6 @@ 7DBC911559934065993A5FF4 /* NotificationManager */ = { isa = PBXGroup; children = ( - F1924EF73801E03610E0F2AB /* ClientProxySpy.swift */, 0376C429FAB1687C3D905F3E /* MockCoder.swift */, 30ED584467DB380E3CEFB1DB /* NotificationManagerTests.swift */, DC0AEA686E425F86F6BA0404 /* UNNotification+Creator.swift */, @@ -2343,7 +2351,7 @@ E600AACDF87CDBCE32683236 /* Resources */ = { isa = PBXGroup; children = ( - 0D15170391F27AF6718D4F2A /* test_image.png */, + 7EF42E492B7599EBCB4A4174 /* test_image.png */, ); path = Resources; sourceTree = ""; @@ -2755,7 +2763,7 @@ buildActionMask = 2147483647; files = ( 35E975CFDA60E05362A7CF79 /* target.yml in Resources */, - 85DB5F55FC407DDB6A4F01C9 /* test_image.png in Resources */, + 87315D70BABB38CFBC8CFF61 /* test_image.png in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -2878,7 +2886,6 @@ 0F9E38A75337D0146652ACAB /* BackgroundTaskTests.swift in Sources */, 7F61F9ACD5EC9E845EF3EFBF /* BugReportServiceTests.swift in Sources */, C7CFDB4929DDD9A3B5BA085D /* BugReportViewModelTests.swift in Sources */, - ACAB49022C2EBD00AFC67729 /* ClientProxySpy.swift in Sources */, 9C45CE85325CD591DADBC4CA /* ElementXTests.swift in Sources */, 501304F26B52DF7024011B6C /* EmojiMartJSONLoaderTests.swift in Sources */, 25618589E0DE0F1E95FC7B5C /* EmojiProviderTests.swift in Sources */, @@ -2920,6 +2927,7 @@ 8D3E1FADD78E72504DE0E402 /* UserAgentBuilderTests.swift in Sources */, 08248D02BACA75CDC3B39A96 /* UserNotificationCenterSpy.swift in Sources */, 8196A2E71ACC902DD69F24EE /* UserNotificationControllerTests.swift in Sources */, + 81A7C020CB5F6232242A8414 /* UserSessionTests.swift in Sources */, 1504CE9A609A348D90B69E47 /* VideoPlayerViewModelTests.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; diff --git a/ElementX/Sources/Services/Client/MockClientProxy.swift b/ElementX/Sources/Services/Client/MockClientProxy.swift index 17ecdafee..f8559b549 100644 --- a/ElementX/Sources/Services/Client/MockClientProxy.swift +++ b/ElementX/Sources/Services/Client/MockClientProxy.swift @@ -79,14 +79,31 @@ class MockClientProxy: ClientProxyProtocol { throw ClientProxyError.failedLoadingMedia } + var sessionVerificationControllerProxyResult: Result? func sessionVerificationControllerProxy() async -> Result { - .failure(.failedRetrievingSessionVerificationController) + if let sessionVerificationControllerProxyResult { + return sessionVerificationControllerProxyResult + } else { + return .failure(.failedRetrievingSessionVerificationController) + } } - + func logout() async { // no-op } - + + var setPusherCalled = false + var setPusherErrorToThrow: Error? + var setPusherPushkey: String? + var setPusherKind: PusherKind? + var setPusherAppId: String? + var setPusherAppDisplayName: String? + var setPusherDeviceDisplayName: String? + var setPusherProfileTag: String? + var setPusherLang: String? + var setPusherUrl: String? + var setPusherFormat: PushFormat? + var setPusherDefaultPayload: [AnyHashable: Any]? // swiftlint:disable:next function_parameter_count func setPusher(pushkey: String, kind: PusherKind?, @@ -98,6 +115,17 @@ class MockClientProxy: ClientProxyProtocol { url: String?, format: PushFormat?, defaultPayload: [AnyHashable: Any]?) async throws { - // no-op + if let setPusherErrorToThrow { throw setPusherErrorToThrow } + setPusherCalled = true + setPusherPushkey = pushkey + setPusherKind = kind + setPusherAppId = appId + setPusherAppDisplayName = appDisplayName + setPusherDeviceDisplayName = deviceDisplayName + setPusherProfileTag = profileTag + setPusherLang = lang + setPusherUrl = url + setPusherFormat = format + setPusherDefaultPayload = defaultPayload } } diff --git a/ElementX/Sources/Services/SessionVerification/MockSessionVerificationControllerProxy.swift b/ElementX/Sources/Services/SessionVerification/MockSessionVerificationControllerProxy.swift index d8d1a2af0..607ec0026 100644 --- a/ElementX/Sources/Services/SessionVerification/MockSessionVerificationControllerProxy.swift +++ b/ElementX/Sources/Services/SessionVerification/MockSessionVerificationControllerProxy.swift @@ -22,10 +22,11 @@ struct MockSessionVerificationControllerProxy: SessionVerificationControllerProx var callbacks = PassthroughSubject() var isVerified = false + var requestDelay: Duration = .seconds(2) func requestVerification() async -> Result { Task.detached { - try await Task.sleep(nanoseconds: 2_000_000_000) + try await Task.sleep(for: requestDelay) callbacks.send(.receivedVerificationData(Self.emojis)) } @@ -34,7 +35,7 @@ struct MockSessionVerificationControllerProxy: SessionVerificationControllerProx func approveVerification() async -> Result { Task.detached { - try await Task.sleep(nanoseconds: 2_000_000_000) + try await Task.sleep(for: requestDelay) callbacks.send(.finished) } @@ -43,7 +44,7 @@ struct MockSessionVerificationControllerProxy: SessionVerificationControllerProx func declineVerification() async -> Result { Task.detached { - try await Task.sleep(nanoseconds: 2_000_000_000) + try await Task.sleep(for: requestDelay) callbacks.send(.cancelled) } @@ -52,7 +53,7 @@ struct MockSessionVerificationControllerProxy: SessionVerificationControllerProx func cancelVerification() async -> Result { Task.detached { - try await Task.sleep(nanoseconds: 2_000_000_000) + try await Task.sleep(for: requestDelay) callbacks.send(.cancelled) } diff --git a/UnitTests/Sources/NotificationManager/ClientProxySpy.swift b/UnitTests/Sources/NotificationManager/ClientProxySpy.swift deleted file mode 100644 index 350a4ef4f..000000000 --- a/UnitTests/Sources/NotificationManager/ClientProxySpy.swift +++ /dev/null @@ -1,116 +0,0 @@ -// -// Copyright 2022 New Vector Ltd -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -import Combine -@testable import ElementX -import Foundation - -class ClientProxySpy: ClientProxyProtocol { - var visibleRoomsSummaryProvider: ElementX.RoomSummaryProviderProtocol? - - var allRoomsSummaryProvider: ElementX.RoomSummaryProviderProtocol? - - let callbacks = PassthroughSubject() - - var userIdentifier = "" - - var isSoftLogout = false - - var deviceId: String? = "" - - var homeserver = "" - - var restorationToken: ElementX.RestorationToken? - - var roomSummaryProvider: ElementX.RoomSummaryProviderProtocol? - - internal init() { } - - func startSync() { } - - func stopSync() { } - - func restartSync() { } - - func roomForIdentifier(_ identifier: String) async -> ElementX.RoomProxyProtocol? { - nil - } - - func loadUserDisplayName() async -> Result { - .failure(.failedLoadingMedia) - } - - func loadUserAvatarURLString() async -> Result { - .failure(.failedLoadingMedia) - } - - func accountDataEvent(type: String) async -> Result where Content: Decodable { - .failure(.failedLoadingMedia) - } - - func setAccountData(content: Content, type: String) async -> Result where Content: Encodable { - .failure(.failedLoadingMedia) - } - - func sessionVerificationControllerProxy() async -> Result { - .failure(.failedLoadingMedia) - } - - func logout() async { } - - var setPusherCalled = false - var setPusherErrorToThrow: Error? - var setPusherPushkey: String? - var setPusherKind: PusherKind? - var setPusherAppId: String? - var setPusherAppDisplayName: String? - var setPusherDeviceDisplayName: String? - var setPusherProfileTag: String? - var setPusherLang: String? - var setPusherUrl: String? - var setPusherFormat: PushFormat? - var setPusherDefaultPayload: [AnyHashable: Any]? - - // swiftlint:disable:next function_parameter_count - func setPusher(pushkey: String, kind: PusherKind?, appId: String, appDisplayName: String, deviceDisplayName: String, profileTag: String?, lang: String, url: String?, format: PushFormat?, defaultPayload: [AnyHashable: Any]?) async throws { - if let setPusherErrorToThrow { - throw setPusherErrorToThrow - } - setPusherCalled = true - setPusherPushkey = pushkey - setPusherKind = kind - setPusherAppId = appId - setPusherAppDisplayName = appDisplayName - setPusherDeviceDisplayName = deviceDisplayName - setPusherProfileTag = profileTag - setPusherLang = lang - setPusherUrl = url - setPusherFormat = format - setPusherDefaultPayload = defaultPayload - } - - func mediaSourceForURLString(_ urlString: String) -> ElementX.MediaSourceProxy { - MediaSourceProxy(urlString: "") - } - - func loadMediaContentForSource(_ source: ElementX.MediaSourceProxy) async throws -> Data { - Data() - } - - func loadMediaThumbnailForSource(_ source: ElementX.MediaSourceProxy, width: UInt, height: UInt) async throws -> Data { - Data() - } -} diff --git a/UnitTests/Sources/NotificationManager/NotificationManagerTests.swift b/UnitTests/Sources/NotificationManager/NotificationManagerTests.swift index 55809b3ee..ebd1dbfb2 100644 --- a/UnitTests/Sources/NotificationManager/NotificationManagerTests.swift +++ b/UnitTests/Sources/NotificationManager/NotificationManagerTests.swift @@ -20,8 +20,8 @@ import Combine @testable import ElementX final class NotificationManagerTests: XCTestCase { - var sut: NotificationManager! - private let clientProxySpy = ClientProxySpy() + var notificationManager: NotificationManager! + private let clientProxy = MockClientProxy(userIdentifier: "@test:user.net") private let notificationCenter = UserNotificationCenterSpy() private var authorizationStatusWasGranted = false private var shouldDisplayInAppNotificationReturnValue = false @@ -30,16 +30,16 @@ final class NotificationManagerTests: XCTestCase { private let settings = ServiceLocator.shared.settings override func setUp() { - sut = NotificationManager(clientProxy: clientProxySpy, notificationCenter: notificationCenter) + notificationManager = NotificationManager(clientProxy: clientProxy, notificationCenter: notificationCenter) } func test_whenRegistered_pusherIsCalled() async { - _ = await sut.register(with: Data()) - XCTAssertTrue(clientProxySpy.setPusherCalled) + _ = await notificationManager.register(with: Data()) + XCTAssertTrue(clientProxy.setPusherCalled) } func test_whenRegisteredSuccess_completionSuccessIsCalled() async throws { - let success = await sut.register(with: Data()) + let success = await notificationManager.register(with: Data()) XCTAssertTrue(success) } @@ -47,25 +47,25 @@ final class NotificationManagerTests: XCTestCase { enum TestError: Error { case someError } - clientProxySpy.setPusherErrorToThrow = TestError.someError - let success = await sut.register(with: Data()) + clientProxy.setPusherErrorToThrow = TestError.someError + let success = await notificationManager.register(with: Data()) XCTAssertFalse(success) } @MainActor func test_whenRegistered_pusherIsCalledWithCorrectValues() async throws { let pushkeyData = Data("1234".utf8) - _ = await sut.register(with: pushkeyData) - XCTAssertEqual(clientProxySpy.setPusherPushkey, pushkeyData.base64EncodedString()) - XCTAssertEqual(clientProxySpy.setPusherAppId, settings?.pusherAppId) - XCTAssertEqual(clientProxySpy.setPusherKind, .http) - XCTAssertEqual(clientProxySpy.setPusherAppId, settings?.pusherAppId) - XCTAssertEqual(clientProxySpy.setPusherAppDisplayName, "\(InfoPlistReader.target.bundleDisplayName) (iOS)") - XCTAssertEqual(clientProxySpy.setPusherDeviceDisplayName, UIDevice.current.name) - XCTAssertNotNil(clientProxySpy.setPusherProfileTag) - XCTAssertEqual(clientProxySpy.setPusherLang, Bundle.preferredLanguages.first) - XCTAssertEqual(clientProxySpy.setPusherUrl, settings?.pushGatewayBaseURL.absoluteString) - XCTAssertEqual(clientProxySpy.setPusherFormat, .eventIdOnly) + _ = await notificationManager.register(with: pushkeyData) + XCTAssertEqual(clientProxy.setPusherPushkey, pushkeyData.base64EncodedString()) + XCTAssertEqual(clientProxy.setPusherAppId, settings?.pusherAppId) + XCTAssertEqual(clientProxy.setPusherKind, .http) + XCTAssertEqual(clientProxy.setPusherAppId, settings?.pusherAppId) + XCTAssertEqual(clientProxy.setPusherAppDisplayName, "\(InfoPlistReader.target.bundleDisplayName) (iOS)") + XCTAssertEqual(clientProxy.setPusherDeviceDisplayName, UIDevice.current.name) + XCTAssertNotNil(clientProxy.setPusherProfileTag) + XCTAssertEqual(clientProxy.setPusherLang, Bundle.preferredLanguages.first) + XCTAssertEqual(clientProxy.setPusherUrl, settings?.pushGatewayBaseURL.absoluteString) + XCTAssertEqual(clientProxy.setPusherFormat, .eventIdOnly) let defaultPayload: [AnyHashable: Any] = [ "aps": [ "mutable-content": 1, @@ -75,31 +75,31 @@ final class NotificationManagerTests: XCTestCase { ] ] ] - let actualPayload = NSDictionary(dictionary: clientProxySpy.setPusherDefaultPayload ?? [:]) + let actualPayload = NSDictionary(dictionary: clientProxy.setPusherDefaultPayload ?? [:]) XCTAssertTrue(actualPayload.isEqual(to: defaultPayload)) } func test_whenRegisteredAndPusherTagNotSetInSettings_tagGeneratedAndSavedInSettings() async throws { settings?.pusherProfileTag = nil - _ = await sut.register(with: Data()) + _ = await notificationManager.register(with: Data()) XCTAssertNotNil(settings?.pusherProfileTag) } func test_whenRegisteredAndPusherTagIsSetInSettings_tagNotGenerated() async throws { settings?.pusherProfileTag = "12345" - _ = await sut.register(with: Data()) + _ = await notificationManager.register(with: Data()) XCTAssertEqual(settings?.pusherProfileTag, "12345") } func test_whenShowLocalNotification_notificationRequestGetsAdded() async throws { - await sut.showLocalNotification(with: "Title", subtitle: "Subtitle") + await notificationManager.showLocalNotification(with: "Title", subtitle: "Subtitle") let request = try XCTUnwrap(notificationCenter.addRequest) XCTAssertEqual(request.content.title, "Title") XCTAssertEqual(request.content.subtitle, "Subtitle") } func test_whenStart_notificationCategoriesAreSet() throws { - sut.start() + notificationManager.start() let replyAction = UNTextInputNotificationAction(identifier: NotificationConstants.Action.inlineReply, title: ElementL10n.actionQuickReply, options: []) @@ -111,13 +111,13 @@ final class NotificationManagerTests: XCTestCase { } func test_whenStart_delegateIsSet() throws { - sut.start() + notificationManager.start() let delegate = try XCTUnwrap(notificationCenter.delegate) - XCTAssertTrue(delegate.isEqual(sut)) + XCTAssertTrue(delegate.isEqual(notificationManager)) } func test_whenStart_requestAuthorizationCalledWithCorrectParams() async throws { - sut.start() + notificationManager.start() await Task.yield() XCTAssertEqual(notificationCenter.requestAuthorizationOptions, [.alert, .sound, .badge]) } @@ -125,53 +125,53 @@ final class NotificationManagerTests: XCTestCase { func test_whenStartAndAuthorizationGranted_delegateCalled() async throws { authorizationStatusWasGranted = false notificationCenter.requestAuthorizationGrantedReturnValue = true - sut.delegate = self - sut.start() + notificationManager.delegate = self + notificationManager.start() try await Task.sleep(for: .milliseconds(100)) XCTAssertTrue(authorizationStatusWasGranted) } func test_whenWillPresentNotificationsDelegateNotSet_CorrectPresentationOptionsReturned() async throws { - sut.start() + notificationManager.start() let archiver = MockCoder(requiringSecureCoding: false) let notification = try XCTUnwrap(UNNotification(coder: archiver)) - let options = await sut.userNotificationCenter(UNUserNotificationCenter.current(), willPresent: notification) + let options = await notificationManager.userNotificationCenter(UNUserNotificationCenter.current(), willPresent: notification) XCTAssertEqual(options, [.badge, .sound, .list, .banner]) } func test_whenWillPresentNotificationsDelegateSetAndNotificationsShoudNotBeDisplayed_CorrectPresentationOptionsReturned() async throws { shouldDisplayInAppNotificationReturnValue = false - sut.delegate = self - sut.start() + notificationManager.delegate = self + notificationManager.start() let notification = try UNNotification.with(userInfo: [AnyHashable: Any]()) - let options = await sut.userNotificationCenter(UNUserNotificationCenter.current(), willPresent: notification) + let options = await notificationManager.userNotificationCenter(UNUserNotificationCenter.current(), willPresent: notification) XCTAssertEqual(options, []) } func test_whenWillPresentNotificationsDelegateSetAndNotificationsShoudBeDisplayed_CorrectPresentationOptionsReturned() async throws { shouldDisplayInAppNotificationReturnValue = true - sut.delegate = self - sut.start() + notificationManager.delegate = self + notificationManager.start() let notification = try UNNotification.with(userInfo: [AnyHashable: Any]()) - let options = await sut.userNotificationCenter(UNUserNotificationCenter.current(), willPresent: notification) + let options = await notificationManager.userNotificationCenter(UNUserNotificationCenter.current(), willPresent: notification) XCTAssertEqual(options, [.badge, .sound, .list, .banner]) } func test_whenNotificationCenterReceivedResponseInLineReply_delegateIsCalled() async throws { handleInlineReplyDelegateCalled = false - sut.delegate = self - sut.start() + notificationManager.delegate = self + notificationManager.start() let response = try UNTextInputNotificationResponse.with(userInfo: [AnyHashable: Any](), actionIdentifier: NotificationConstants.Action.inlineReply) - await sut.userNotificationCenter(UNUserNotificationCenter.current(), didReceive: response) + await notificationManager.userNotificationCenter(UNUserNotificationCenter.current(), didReceive: response) XCTAssertTrue(handleInlineReplyDelegateCalled) } func test_whenNotificationCenterReceivedResponseWithActionIdentifier_delegateIsCalled() async throws { notificationTappedDelegateCalled = false - sut.delegate = self - sut.start() + notificationManager.delegate = self + notificationManager.start() let response = try UNTextInputNotificationResponse.with(userInfo: [AnyHashable: Any](), actionIdentifier: UNNotificationDefaultActionIdentifier) - await sut.userNotificationCenter(UNUserNotificationCenter.current(), didReceive: response) + await notificationManager.userNotificationCenter(UNUserNotificationCenter.current(), didReceive: response) XCTAssertTrue(notificationTappedDelegateCalled) } } diff --git a/UnitTests/Sources/UserSession/UserSessionTests.swift b/UnitTests/Sources/UserSession/UserSessionTests.swift new file mode 100644 index 000000000..49732c34f --- /dev/null +++ b/UnitTests/Sources/UserSession/UserSessionTests.swift @@ -0,0 +1,88 @@ +// +// Copyright 2022 New Vector Ltd +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +import Combine +@testable import ElementX +import XCTest + +final class UserSessionTests: XCTestCase { + var userSession: UserSession! + let clientProxy = MockClientProxy(userIdentifier: "@test:user.net") + + private var cancellables: Set = [] + + override func setUpWithError() throws { + cancellables = [] + userSession = UserSession(clientProxy: clientProxy, mediaProvider: MockMediaProvider()) + } + + func test_whenUserSessionReceivesSyncUpdateAndSessionControllerRetrievedAndSessionNotVerified_sessionVerificationNeededEventReceived() throws { + let expectation = expectation(description: "SessionVerificationNeeded expectation") + userSession.callbacks.sink { callback in + switch callback { + case .sessionVerificationNeeded: + expectation.fulfill() + default: + break + } + } + .store(in: &cancellables) + + let controller = MockSessionVerificationControllerProxy(callbacks: PassthroughSubject(), + isVerified: false, + requestDelay: .zero) + clientProxy.sessionVerificationControllerProxyResult = .success(controller) + clientProxy.callbacks.send(.receivedSyncUpdate) + waitForExpectations(timeout: 1.0) + } + + func test_whenUserSessionReceivesSyncUpdateAndSessionIsVerified_didVerifySessionEventReceived() throws { + let expectation = expectation(description: "DidVerifySessionEvent expectation") + let controller = MockSessionVerificationControllerProxy(callbacks: PassthroughSubject(), + isVerified: false, + requestDelay: .zero) + clientProxy.sessionVerificationControllerProxyResult = .success(controller) + + controller.callbacks.sink { value in + switch value { + case .finished: + expectation.fulfill() + default: + break + } + } + .store(in: &cancellables) + + clientProxy.callbacks.send(.receivedSyncUpdate) + controller.callbacks.send(.finished) + waitForExpectations(timeout: 1.0) + } + + func test_whenUserSessionReceivesUpdatedRestoreToken_updateRestoreTokenNeededEventReceived() throws { + let expectation = expectation(description: "UpdatedRestoreToken expectation") + userSession.callbacks.sink { callback in + switch callback { + case .updateRestoreTokenNeeded: + expectation.fulfill() + default: + break + } + } + .store(in: &cancellables) + + clientProxy.callbacks.send(.updatedRestoreToken) + waitForExpectations(timeout: 1.0) + } +} diff --git a/changelog.d/pr-390.change b/changelog.d/pr-390.change new file mode 100644 index 000000000..3959da527 --- /dev/null +++ b/changelog.d/pr-390.change @@ -0,0 +1 @@ +UserSession: Add unit tests. \ No newline at end of file