diff --git a/ElementX/Sources/Application/AppCoordinator.swift b/ElementX/Sources/Application/AppCoordinator.swift index 0d50222f7..b69e51f3d 100644 --- a/ElementX/Sources/Application/AppCoordinator.swift +++ b/ElementX/Sources/Application/AppCoordinator.swift @@ -473,11 +473,12 @@ extension AppCoordinator: NotificationManagerDelegate { func notificationTapped(_ service: NotificationManagerProtocol, content: UNNotificationContent) async { MXLog.info("[AppCoordinator] tappedNotification") - guard let roomId = content.userInfo[NotificationConstants.UserInfoKey.roomIdentifier] as? String else { + // We store the room identifier into the thread identifier + guard !content.threadIdentifier.isEmpty else { return } - userSessionFlowCoordinator?.tryDisplayingRoomScreen(roomId: roomId) + userSessionFlowCoordinator?.tryDisplayingRoomScreen(roomId: content.threadIdentifier) } func handleInlineReply(_ service: NotificationManagerProtocol, content: UNNotificationContent, replyText: String) async { diff --git a/ElementX/Sources/Mocks/Generated/GeneratedMocks.swift b/ElementX/Sources/Mocks/Generated/GeneratedMocks.swift index 22d6a2b29..0e2f0167e 100644 --- a/ElementX/Sources/Mocks/Generated/GeneratedMocks.swift +++ b/ElementX/Sources/Mocks/Generated/GeneratedMocks.swift @@ -2,7 +2,6 @@ // DO NOT EDIT // swiftlint:disable all - import Combine import MatrixRustSDK class BugReportServiceMock: BugReportServiceProtocol { @@ -11,18 +10,20 @@ class BugReportServiceMock: BugReportServiceProtocol { set(value) { underlyingCrashedLastRun = value } } var underlyingCrashedLastRun: Bool! - // MARK: - crash + + //MARK: - crash var crashCallsCount = 0 var crashCalled: Bool { return crashCallsCount > 0 } var crashClosure: (() -> Void)? + func crash() { crashCallsCount += 1 crashClosure?() } - // MARK: - submitBugReport + //MARK: - submitBugReport var submitBugReportProgressListenerThrowableError: Error? var submitBugReportProgressListenerCallsCount = 0 @@ -33,6 +34,7 @@ class BugReportServiceMock: BugReportServiceProtocol { var submitBugReportProgressListenerReceivedInvocations: [(bugReport: BugReport, progressListener: ProgressListener?)] = [] var submitBugReportProgressListenerReturnValue: SubmitBugReportResponse! var submitBugReportProgressListenerClosure: ((BugReport, ProgressListener?) async throws -> SubmitBugReportResponse)? + func submitBugReport(_ bugReport: BugReport, progressListener: ProgressListener?) async throws -> SubmitBugReportResponse { if let error = submitBugReportProgressListenerThrowableError { throw error @@ -58,7 +60,8 @@ class SessionVerificationControllerProxyMock: SessionVerificationControllerProxy set(value) { underlyingIsVerified = value } } var underlyingIsVerified: Bool! - // MARK: - requestVerification + + //MARK: - requestVerification var requestVerificationCallsCount = 0 var requestVerificationCalled: Bool { @@ -66,6 +69,7 @@ class SessionVerificationControllerProxyMock: SessionVerificationControllerProxy } var requestVerificationReturnValue: Result! var requestVerificationClosure: (() async -> Result)? + func requestVerification() async -> Result { requestVerificationCallsCount += 1 if let requestVerificationClosure = requestVerificationClosure { @@ -74,7 +78,7 @@ class SessionVerificationControllerProxyMock: SessionVerificationControllerProxy return requestVerificationReturnValue } } - // MARK: - startSasVerification + //MARK: - startSasVerification var startSasVerificationCallsCount = 0 var startSasVerificationCalled: Bool { @@ -82,6 +86,7 @@ class SessionVerificationControllerProxyMock: SessionVerificationControllerProxy } var startSasVerificationReturnValue: Result! var startSasVerificationClosure: (() async -> Result)? + func startSasVerification() async -> Result { startSasVerificationCallsCount += 1 if let startSasVerificationClosure = startSasVerificationClosure { @@ -90,7 +95,7 @@ class SessionVerificationControllerProxyMock: SessionVerificationControllerProxy return startSasVerificationReturnValue } } - // MARK: - approveVerification + //MARK: - approveVerification var approveVerificationCallsCount = 0 var approveVerificationCalled: Bool { @@ -98,6 +103,7 @@ class SessionVerificationControllerProxyMock: SessionVerificationControllerProxy } var approveVerificationReturnValue: Result! var approveVerificationClosure: (() async -> Result)? + func approveVerification() async -> Result { approveVerificationCallsCount += 1 if let approveVerificationClosure = approveVerificationClosure { @@ -106,7 +112,7 @@ class SessionVerificationControllerProxyMock: SessionVerificationControllerProxy return approveVerificationReturnValue } } - // MARK: - declineVerification + //MARK: - declineVerification var declineVerificationCallsCount = 0 var declineVerificationCalled: Bool { @@ -114,6 +120,7 @@ class SessionVerificationControllerProxyMock: SessionVerificationControllerProxy } var declineVerificationReturnValue: Result! var declineVerificationClosure: (() async -> Result)? + func declineVerification() async -> Result { declineVerificationCallsCount += 1 if let declineVerificationClosure = declineVerificationClosure { @@ -122,7 +129,7 @@ class SessionVerificationControllerProxyMock: SessionVerificationControllerProxy return declineVerificationReturnValue } } - // MARK: - cancelVerification + //MARK: - cancelVerification var cancelVerificationCallsCount = 0 var cancelVerificationCalled: Bool { @@ -130,6 +137,7 @@ class SessionVerificationControllerProxyMock: SessionVerificationControllerProxy } var cancelVerificationReturnValue: Result! var cancelVerificationClosure: (() async -> Result)? + func cancelVerification() async -> Result { cancelVerificationCallsCount += 1 if let cancelVerificationClosure = cancelVerificationClosure { @@ -139,5 +147,4 @@ class SessionVerificationControllerProxyMock: SessionVerificationControllerProxy } } } - // swiftlint:enable all diff --git a/ElementX/Sources/Mocks/AutoMockable.swift b/ElementX/Sources/Other/Extensions/Dictionary.swift similarity index 63% rename from ElementX/Sources/Mocks/AutoMockable.swift rename to ElementX/Sources/Other/Extensions/Dictionary.swift index d72a54aeb..3a9573d66 100644 --- a/ElementX/Sources/Mocks/AutoMockable.swift +++ b/ElementX/Sources/Other/Extensions/Dictionary.swift @@ -14,6 +14,15 @@ // limitations under the License. // -// This protocol is used only as a marker -// to mark protocols that can be auto-mocked by Sourcery -protocol AutoMockable { } +import Foundation + +extension Dictionary { + var jsonString: String? { + guard let data = try? JSONSerialization.data(withJSONObject: self, + options: [.fragmentsAllowed, .sortedKeys]) else { + return nil + } + + return String(data: data, encoding: .utf8) + } +} diff --git a/ElementX/Sources/Services/BugReport/BugReportServiceProtocol.swift b/ElementX/Sources/Services/BugReport/BugReportServiceProtocol.swift index de75640ed..d217523d3 100644 --- a/ElementX/Sources/Services/BugReport/BugReportServiceProtocol.swift +++ b/ElementX/Sources/Services/BugReport/BugReportServiceProtocol.swift @@ -31,7 +31,8 @@ struct SubmitBugReportResponse: Decodable { var reportUrl: String } -protocol BugReportServiceProtocol: AutoMockable { +// sourcery: AutoMockable +protocol BugReportServiceProtocol { var crashedLastRun: Bool { get } func crash() diff --git a/ElementX/Sources/Services/Client/ClientProxy.swift b/ElementX/Sources/Services/Client/ClientProxy.swift index ac17673d8..038fd2199 100644 --- a/ElementX/Sources/Services/Client/ClientProxy.swift +++ b/ElementX/Sources/Services/Client/ClientProxy.swift @@ -212,30 +212,15 @@ class ClientProxy: ClientProxyProtocol { } } - // swiftlint:disable:next function_parameter_count - func setPusher(pushkey: String, - kind: PusherKind?, - appId: String, - appDisplayName: String, - deviceDisplayName: String, - profileTag: String?, - lang: String, - url: URL?, - format: PushFormat?, - defaultPayload: [AnyHashable: Any]?) async throws { -// let defaultPayloadString = jsonString(from: defaultPayload) -// try await Task.dispatch(on: .global()) { -// try self.client.setPusher(pushkey: pushkey, -// kind: kind?.rustValue, -// appId: appId, -// appDisplayName: appDisplayName, -// deviceDisplayName: deviceDisplayName, -// profileTag: profileTag, -// lang: lang, -// url: url, -// format: format?.rustValue, -// defaultPayload: defaultPayloadString) -// } + func setPusher(with configuration: PusherConfiguration) async throws { + try await Task.dispatch(on: .global()) { + try self.client.setPusher(identifiers: configuration.identifiers, + kind: configuration.kind, + appDisplayName: configuration.appDisplayName, + deviceDisplayName: configuration.deviceDisplayName, + profileTag: configuration.profileTag, + lang: configuration.lang) + } } // MARK: Private @@ -399,17 +384,6 @@ class ClientProxy: ClientProxyProtocol { fileprivate func didReceiveSlidingSyncUpdate(summary: UpdateSummary) { callbacks.send(.receivedSyncUpdate) } - - /// Convenience method to get the json string of an Encodable - private func jsonString(from dictionary: [AnyHashable: Any]?) -> String? { - guard let dictionary, - let data = try? JSONSerialization.data(withJSONObject: dictionary, - options: [.fragmentsAllowed]) else { - return nil - } - - return String(data: data, encoding: .utf8) - } } extension ClientProxy: MediaLoaderProtocol { diff --git a/ElementX/Sources/Services/Client/ClientProxyProtocol.swift b/ElementX/Sources/Services/Client/ClientProxyProtocol.swift index a31f82db9..f2aa20292 100644 --- a/ElementX/Sources/Services/Client/ClientProxyProtocol.swift +++ b/ElementX/Sources/Services/Client/ClientProxyProtocol.swift @@ -31,37 +31,24 @@ enum ClientProxyError: Error { case failedLoadingMedia } -enum PusherKind { - case http - case email - -// var rustValue: MatrixRustSDK.PusherKind { -// switch self { -// case .http: -// return .http -// case .email: -// return .email -// } -// } -} - -enum PushFormat { - case eventIdOnly - -// var rustValue: MatrixRustSDK.PushFormat { -// switch self { -// case .eventIdOnly: -// return .eventIdOnly -// } -// } -} - enum SlidingSyncConstants { static let initialTimelineLimit: UInt = 0 static let lastMessageTimelineLimit: UInt = 1 static let timelinePrecachingTimelineLimit: UInt = 20 } +/// This struct represents the configuration that we are using to register the application through Pusher to Sygnal +/// using the Matrix Rust SDK, more info here: +/// https://github.com/matrix-org/sygnal +struct PusherConfiguration { + let identifiers: PusherIdentifiers + let kind: PusherKind + let appDisplayName: String + let deviceDisplayName: String + let profileTag: String? + let lang: String +} + protocol ClientProxyProtocol: AnyObject, MediaLoaderProtocol { var callbacks: PassthroughSubject { get } @@ -97,15 +84,5 @@ protocol ClientProxyProtocol: AnyObject, MediaLoaderProtocol { func logout() async - // swiftlint:disable:next function_parameter_count - func setPusher(pushkey: String, - kind: PusherKind?, - appId: String, - appDisplayName: String, - deviceDisplayName: String, - profileTag: String?, - lang: String, - url: URL?, - format: PushFormat?, - defaultPayload: [AnyHashable: Any]?) async throws + func setPusher(with configuration: PusherConfiguration) async throws } diff --git a/ElementX/Sources/Services/Client/MockClientProxy.swift b/ElementX/Sources/Services/Client/MockClientProxy.swift index 8039e2a08..5e7fd00c3 100644 --- a/ElementX/Sources/Services/Client/MockClientProxy.swift +++ b/ElementX/Sources/Services/Client/MockClientProxy.swift @@ -89,40 +89,13 @@ class MockClientProxy: ClientProxyProtocol { // 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: URL? - 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: URL?, - format: PushFormat?, - defaultPayload: [AnyHashable: Any]?) async throws { + var setPusherArgument: PusherConfiguration? + var setPusherCalled = false + + func setPusher(with configuration: PusherConfiguration) 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 + setPusherArgument = configuration } } diff --git a/ElementX/Sources/Services/Notification/Manager/NotificationManager.swift b/ElementX/Sources/Services/Notification/Manager/NotificationManager.swift index 96bd1cb1f..9547d9125 100644 --- a/ElementX/Sources/Services/Notification/Manager/NotificationManager.swift +++ b/ElementX/Sources/Services/Notification/Manager/NotificationManager.swift @@ -84,24 +84,25 @@ class NotificationManager: NSObject, NotificationManagerProtocol { private func setPusher(with deviceToken: Data, clientProxy: ClientProxyProtocol) async -> Bool { do { - try await clientProxy.setPusher(pushkey: deviceToken.base64EncodedString(), - kind: .http, - appId: ServiceLocator.shared.settings.pusherAppId, - appDisplayName: "\(InfoPlistReader.main.bundleDisplayName) (iOS)", - deviceDisplayName: UIDevice.current.name, - profileTag: pusherProfileTag(), - lang: Bundle.preferredLanguages.first ?? "en", - url: ServiceLocator.shared.settings.pushGatewayBaseURL, - format: .eventIdOnly, - defaultPayload: [ - "aps": [ - "mutable-content": 1, - "alert": [ - "loc-key": "Notification", - "loc-args": [] - ] - ] - ]) + let defaultPayload = [ + "aps": [ + "mutable-content": 1, + "alert": [ + "loc-key": "Notification", + "loc-args": [] + ] + ] + ] + let configuration = await PusherConfiguration(identifiers: .init(pushkey: deviceToken.base64EncodedString(), + appId: ServiceLocator.shared.settings.pusherAppId), + kind: .http(data: .init(url: ServiceLocator.shared.settings.pushGatewayBaseURL.absoluteString, + format: .eventIdOnly, + defaultPayload: defaultPayload.jsonString)), + appDisplayName: "\(InfoPlistReader.main.bundleDisplayName) (iOS)", + deviceDisplayName: UIDevice.current.name, + profileTag: pusherProfileTag(), + lang: Bundle.preferredLanguages.first ?? "en") + try await clientProxy.setPusher(with: configuration) MXLog.info("[NotificationManager] set pusher succeeded") return true } catch { @@ -144,6 +145,7 @@ extension NotificationManager: UNUserNotificationCenterDelegate { return [.badge, .sound, .list, .banner] } + @MainActor func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse) async { switch response.actionIdentifier { diff --git a/ElementX/Sources/Services/SessionVerification/SessionVerificationControllerProxyProtocol.swift b/ElementX/Sources/Services/SessionVerification/SessionVerificationControllerProxyProtocol.swift index f4353bd92..a4fc7428b 100644 --- a/ElementX/Sources/Services/SessionVerification/SessionVerificationControllerProxyProtocol.swift +++ b/ElementX/Sources/Services/SessionVerification/SessionVerificationControllerProxyProtocol.swift @@ -39,7 +39,8 @@ struct SessionVerificationEmoji: Hashable { let description: String } -protocol SessionVerificationControllerProxyProtocol: AutoMockable { +// sourcery: AutoMockable +protocol SessionVerificationControllerProxyProtocol { var callbacks: PassthroughSubject { get } var isVerified: Bool { get } diff --git a/NCE/Sources/NotificationViewController.swift b/NCE/Sources/NotificationViewController.swift new file mode 100644 index 000000000..fbe4cddfc --- /dev/null +++ b/NCE/Sources/NotificationViewController.swift @@ -0,0 +1,30 @@ +// +// Copyright 2023 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 UIKit +import UserNotifications +import UserNotificationsUI + +class NotificationViewController: UIViewController, UNNotificationContentExtension { + override func viewDidLoad() { + super.viewDidLoad() + // Do any required interface initialization here. + } + + func didReceive(_ notification: UNNotification) { + // Handle the received push notification + } +} diff --git a/NCE/SupportingFiles/Info.plist b/NCE/SupportingFiles/Info.plist new file mode 100644 index 000000000..05efb15c8 --- /dev/null +++ b/NCE/SupportingFiles/Info.plist @@ -0,0 +1,44 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleDisplayName + $(PRODUCT_NAME) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + XPC! + CFBundleShortVersionString + $(MARKETING_VERSION) + CFBundleVersion + $(CURRENT_PROJECT_VERSION) + NSExtension + + NSExtensionAttributes + + UNNotificationExtensionCategory + myNotificationCategory + UNNotificationExtensionInitialContentSizeRatio + 1 + + NSExtensionPointIdentifier + com.apple.usernotifications.content-extension + NSExtensionPrincipalClass + NCE.NotificationViewController + + appGroupIdentifier + $(APP_GROUP_IDENTIFIER) + baseBundleIdentifier + $(BASE_BUNDLE_IDENTIFIER) + keychainAccessGroupIdentifier + $(KEYCHAIN_ACCESS_GROUP_IDENTIFIER) + + diff --git a/NCE/SupportingFiles/target.yml b/NCE/SupportingFiles/target.yml new file mode 100644 index 000000000..64a9d32ad --- /dev/null +++ b/NCE/SupportingFiles/target.yml @@ -0,0 +1,66 @@ +name: NCE + +schemes: + NCE: + analyze: + config: Debug + archive: + config: Release + build: + targets: + NCE: + - running + - testing + - profiling + - analyzing + - archiving + profile: + config: Release + run: + askForAppToLaunch: true + config: Debug + debugEnabled: false + disableMainThreadChecker: false + launchAutomaticallySubstyle: 2 + test: + config: Debug + disableMainThreadChecker: false + +targets: + NCE: + type: app-extension + platform: iOS + + dependencies: + - package: MatrixRustSDK + + info: + path: ../SupportingFiles/Info.plist + properties: + CFBundleDisplayName: $(PRODUCT_NAME) + CFBundleShortVersionString: $(MARKETING_VERSION) + CFBundleVersion: $(CURRENT_PROJECT_VERSION) + appGroupIdentifier: $(APP_GROUP_IDENTIFIER) + baseBundleIdentifier: $(BASE_BUNDLE_IDENTIFIER) + keychainAccessGroupIdentifier: $(KEYCHAIN_ACCESS_GROUP_IDENTIFIER) + NSExtension: + NSExtensionPointIdentifier: com.apple.usernotifications.content-extension + NSExtensionPrincipalClass: NCE.NotificationViewController + NSExtensionAttributes: + UNNotificationExtensionCategory: myNotificationCategory + UNNotificationExtensionInitialContentSizeRatio: 1 + + settings: + base: + PRODUCT_NAME: NCE + PRODUCT_BUNDLE_IDENTIFIER: ${BASE_BUNDLE_IDENTIFIER}.nce + MARKETING_VERSION: $(MARKETING_VERSION) + CURRENT_PROJECT_VERSION: $(CURRENT_PROJECT_VERSION) + DEVELOPMENT_TEAM: $(DEVELOPMENT_TEAM) + SWIFT_OBJC_INTERFACE_HEADER_NAME: GeneratedInterface-Swift.h + debug: + release: + + sources: + - path: ../Sources + - path: ../SupportingFiles diff --git a/NSE/Sources/Other/NotificationItemProxy+NSE.swift b/NSE/Sources/Other/NotificationItemProxy+NSE.swift index dcd07a119..9567f6323 100644 --- a/NSE/Sources/Other/NotificationItemProxy+NSE.swift +++ b/NSE/Sources/Other/NotificationItemProxy+NSE.swift @@ -132,6 +132,8 @@ extension NotificationItemProxy { if let subtitle = subtitle { notification.subtitle = subtitle } + // We can store the room identifier into the thread identifier since it's used for notifications + // that belong to the same group notification.threadIdentifier = roomId notification.categoryIdentifier = NotificationConstants.Category.reply notification.sound = isNoisy ? UNNotificationSound(named: UNNotificationSoundName(rawValue: "message.caf")) : nil diff --git a/Tools/Sourcery/AutoMockable.stencil b/Tools/Sourcery/AutoMockable.stencil index 848f26dcb..68e6223b9 100644 --- a/Tools/Sourcery/AutoMockable.stencil +++ b/Tools/Sourcery/AutoMockable.stencil @@ -1,5 +1,4 @@ // swiftlint:disable all - {% for import in argument.autoMockableImports %} import {{ import }} {% endfor %} @@ -40,7 +39,7 @@ import {{ import }} {% endmacro %} {% macro methodClosureCallParameters method %}{% for param in method.parameters %}{{ param.name }}{% if not forloop.last %}, {% endif %}{% endfor %}{% endmacro %} {% macro mockMethod method %} - // MARK: - {{ method.shortName }} + //MARK: - {{ method.shortName }} {% if method.throws %} {% call methodThrowableErrorDeclaration method %} @@ -67,6 +66,7 @@ import {{ import }} {% call accessLevel method.accessLevel %}{% call staticSpecifier method %}var {% call swiftifyMethodName method.selectorName %}ReturnValue: {{ '(' if method.returnTypeName.isClosure and not method.isOptionalReturnType }}{{ method.returnTypeName }}{{ ')' if method.returnTypeName.isClosure and not method.isOptionalReturnType }}{{ '!' if not method.isOptionalReturnType }} {% endif %} {% call methodClosureDeclaration method %} + {% if method.isInitializer %} {% call accessLevel method.accessLevel %}required {{ method.name }} { {% call methodReceivedParameters method %} @@ -98,7 +98,7 @@ import {{ import }} {% endmacro %} {% macro resetMethod method %} {# for type method which are mocked, a way to reset the invocation, argument, etc #} - {% if method.isStatic and not method.isInitializer %} // MARK: - {{ method.shortName }} + {% if method.isStatic and not method.isInitializer %} //MARK: - {{ method.shortName }} {% if not method.isInitializer %} {% call swiftifyMethodName method.selectorName %}CallsCount = 0 {% endif %} @@ -127,7 +127,8 @@ import {{ import }} get { return {% call underlyingMockedVariableName variable %} } set(value) { {% call underlyingMockedVariableName variable %} = value } } - {% call accessLevel variable.readAccess %}var {% call underlyingMockedVariableName variable %}: {{ variable.typeName }}! + {% set wrappedTypeName %}{% if variable.typeName.isProtocolComposition %}({{ variable.typeName }}){% else %}{{ variable.typeName }}{% endif %}{% endset %} + {% call accessLevel variable.readAccess %}var {% call underlyingMockedVariableName variable %}: {{ wrappedTypeName }}! {% endmacro %} {% macro variableThrowableErrorDeclaration variable %} {% call accessLevel variable.readAccess %}var {% call mockedVariableName variable %}ThrowableError: Error? @@ -146,6 +147,7 @@ import {{ import }} {% call accessLevel variable.readAccess %}var {% call mockedVariableName variable %}Called: Bool { return {% call mockedVariableName variable %}CallsCount > 0 } + {% call accessLevel variable.readAccess %}var {% call mockedVariableName variable %}: {{ variable.typeName }} { get {% if variable.isAsync %}async {% endif %}{% if variable.throws %}throws {% endif %}{ {% if variable.throws %} @@ -181,10 +183,10 @@ import {{ import }} {% endfor %} } {% endif %} + {% for method in type.allMethods|!definedInExtension %} {% call mockMethod method %} {% endfor %} } {% endif %}{% endfor %} - // swiftlint:enable all diff --git a/UnitTests/Sources/NotificationManager/NotificationManagerTests.swift b/UnitTests/Sources/NotificationManager/NotificationManagerTests.swift index fff8376c7..a9378a311 100644 --- a/UnitTests/Sources/NotificationManager/NotificationManagerTests.swift +++ b/UnitTests/Sources/NotificationManager/NotificationManagerTests.swift @@ -56,16 +56,18 @@ final class NotificationManagerTests: XCTestCase { func test_whenRegistered_pusherIsCalledWithCorrectValues() async throws { let pushkeyData = Data("1234".utf8) _ = 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.main.bundleDisplayName) (iOS)") - XCTAssertEqual(clientProxy.setPusherDeviceDisplayName, UIDevice.current.name) - XCTAssertNotNil(clientProxy.setPusherProfileTag) - XCTAssertEqual(clientProxy.setPusherLang, Bundle.preferredLanguages.first) - XCTAssertEqual(clientProxy.setPusherUrl, settings?.pushGatewayBaseURL) - XCTAssertEqual(clientProxy.setPusherFormat, .eventIdOnly) + XCTAssertEqual(clientProxy.setPusherArgument?.identifiers.pushkey, pushkeyData.base64EncodedString()) + XCTAssertEqual(clientProxy.setPusherArgument?.identifiers.appId, settings?.pusherAppId) + XCTAssertEqual(clientProxy.setPusherArgument?.appDisplayName, "\(InfoPlistReader.main.bundleDisplayName) (iOS)") + XCTAssertEqual(clientProxy.setPusherArgument?.deviceDisplayName, UIDevice.current.name) + XCTAssertNotNil(clientProxy.setPusherArgument?.profileTag) + XCTAssertEqual(clientProxy.setPusherArgument?.lang, Bundle.preferredLanguages.first) + guard case let .http(data) = clientProxy.setPusherArgument?.kind else { + XCTFail("Http kind expected") + return + } + XCTAssertEqual(data.url, settings?.pushGatewayBaseURL.absoluteString) + XCTAssertEqual(data.format, .eventIdOnly) let defaultPayload: [AnyHashable: Any] = [ "aps": [ "mutable-content": 1, @@ -75,8 +77,7 @@ final class NotificationManagerTests: XCTestCase { ] ] ] - let actualPayload = NSDictionary(dictionary: clientProxy.setPusherDefaultPayload ?? [:]) - XCTAssertTrue(actualPayload.isEqual(to: defaultPayload)) + XCTAssertEqual(data.defaultPayload, defaultPayload.jsonString) } func test_whenRegisteredAndPusherTagNotSetInSettings_tagGeneratedAndSavedInSettings() async throws { diff --git a/project.yml b/project.yml index 8135b6a6b..238557760 100644 --- a/project.yml +++ b/project.yml @@ -37,6 +37,7 @@ include: - path: UITests/SupportingFiles/target.yml - path: IntegrationTests/SupportingFiles/target.yml - path: NSE/SupportingFiles/target.yml + - path: NCE/SupportingFiles/target.yml packages: MatrixRustSDK: