From d826d7a04eb2ceff988a4b7d7517ef5bfe3a89cd Mon Sep 17 00:00:00 2001 From: Dariusz Rybicki <dariusz@elixxir.io> Date: Mon, 22 Aug 2022 12:34:14 +0100 Subject: [PATCH] Implement messenger client --- Package.swift | 5 + .../Messenger/Functors/MessengerConnect.swift | 35 ++++ .../Messenger/Functors/MessengerCreate.swift | 35 ++++ .../Functors/MessengerIsConnected.swift | 25 +++ .../Functors/MessengerIsCreated.swift | 24 +++ .../Functors/MessengerIsLoaded.swift | 24 +++ .../Functors/MessengerIsLoggedIn.swift | 24 +++ .../Functors/MessengerIsRegistered.swift | 31 +++ .../Messenger/Functors/MessengerLoad.swift | 28 +++ .../Messenger/Functors/MessengerLogIn.swift | 50 +++++ .../Functors/MessengerRegister.swift | 52 +++++ .../Messenger/Messenger.swift | 46 +++++ .../Messenger/MessengerContext.swift | 17 ++ .../Messenger/MessengerEnvironment.swift | 73 +++++++ Sources/XXMessengerClient/Unimplemented.swift | 1 - .../Utils/MessengerFileManager.swift | 40 ++++ .../Utils/PasswordStorage+Keychain.swift | 21 ++ .../Functors/MessengerConnectTests.swift | 107 ++++++++++ .../Functors/MessengerCreateTests.swift | 159 +++++++++++++++ .../Functors/MessengerIsConnectedTests.swift | 20 ++ .../Functors/MessengerIsCreatedTests.swift | 37 ++++ .../Functors/MessengerIsLoadedTests.swift | 20 ++ .../Functors/MessengerIsLoggedInTests.swift | 20 ++ .../Functors/MessengerIsRegisteredTests.swift | 58 ++++++ .../Functors/MessengerLoadTests.swift | 77 +++++++ .../Functors/MessengerLogInTests.swift | 171 ++++++++++++++++ .../Functors/MessengerRegisterTests.swift | 188 ++++++++++++++++++ .../XXMessengerClientTests.swift | 8 - 28 files changed, 1387 insertions(+), 9 deletions(-) create mode 100644 Sources/XXMessengerClient/Messenger/Functors/MessengerConnect.swift create mode 100644 Sources/XXMessengerClient/Messenger/Functors/MessengerCreate.swift create mode 100644 Sources/XXMessengerClient/Messenger/Functors/MessengerIsConnected.swift create mode 100644 Sources/XXMessengerClient/Messenger/Functors/MessengerIsCreated.swift create mode 100644 Sources/XXMessengerClient/Messenger/Functors/MessengerIsLoaded.swift create mode 100644 Sources/XXMessengerClient/Messenger/Functors/MessengerIsLoggedIn.swift create mode 100644 Sources/XXMessengerClient/Messenger/Functors/MessengerIsRegistered.swift create mode 100644 Sources/XXMessengerClient/Messenger/Functors/MessengerLoad.swift create mode 100644 Sources/XXMessengerClient/Messenger/Functors/MessengerLogIn.swift create mode 100644 Sources/XXMessengerClient/Messenger/Functors/MessengerRegister.swift create mode 100644 Sources/XXMessengerClient/Messenger/Messenger.swift create mode 100644 Sources/XXMessengerClient/Messenger/MessengerContext.swift create mode 100644 Sources/XXMessengerClient/Messenger/MessengerEnvironment.swift delete mode 100644 Sources/XXMessengerClient/Unimplemented.swift create mode 100644 Sources/XXMessengerClient/Utils/MessengerFileManager.swift create mode 100644 Sources/XXMessengerClient/Utils/PasswordStorage+Keychain.swift create mode 100644 Tests/XXMessengerClientTests/Messenger/Functors/MessengerConnectTests.swift create mode 100644 Tests/XXMessengerClientTests/Messenger/Functors/MessengerCreateTests.swift create mode 100644 Tests/XXMessengerClientTests/Messenger/Functors/MessengerIsConnectedTests.swift create mode 100644 Tests/XXMessengerClientTests/Messenger/Functors/MessengerIsCreatedTests.swift create mode 100644 Tests/XXMessengerClientTests/Messenger/Functors/MessengerIsLoadedTests.swift create mode 100644 Tests/XXMessengerClientTests/Messenger/Functors/MessengerIsLoggedInTests.swift create mode 100644 Tests/XXMessengerClientTests/Messenger/Functors/MessengerIsRegisteredTests.swift create mode 100644 Tests/XXMessengerClientTests/Messenger/Functors/MessengerLoadTests.swift create mode 100644 Tests/XXMessengerClientTests/Messenger/Functors/MessengerLogInTests.swift create mode 100644 Tests/XXMessengerClientTests/Messenger/Functors/MessengerRegisterTests.swift delete mode 100644 Tests/XXMessengerClientTests/XXMessengerClientTests.swift diff --git a/Package.swift b/Package.swift index 4f06554e..0024dab5 100644 --- a/Package.swift +++ b/Package.swift @@ -31,6 +31,10 @@ let package = Package( url: "https://github.com/pointfreeco/xctest-dynamic-overlay.git", .upToNextMajor(from: "0.4.0") ), + .package( + url: "https://github.com/kishikawakatsumi/KeychainAccess.git", + .upToNextMajor(from: "4.2.2") + ), ], targets: [ .target( @@ -53,6 +57,7 @@ let package = Package( name: "XXMessengerClient", dependencies: [ .target(name: "XXClient"), + .product(name: "KeychainAccess", package: "KeychainAccess"), .product(name: "XCTestDynamicOverlay", package: "xctest-dynamic-overlay"), ], swiftSettings: swiftSettings diff --git a/Sources/XXMessengerClient/Messenger/Functors/MessengerConnect.swift b/Sources/XXMessengerClient/Messenger/Functors/MessengerConnect.swift new file mode 100644 index 00000000..fa24b8eb --- /dev/null +++ b/Sources/XXMessengerClient/Messenger/Functors/MessengerConnect.swift @@ -0,0 +1,35 @@ +import XXClient +import XCTestDynamicOverlay + +public struct MessengerConnect { + public enum Error: Swift.Error, Equatable { + case notLoaded + } + + public var run: () throws -> Void + + public func callAsFunction() throws { + try run() + } +} + +extension MessengerConnect { + public static func live(_ env: MessengerEnvironment) -> MessengerConnect { + MessengerConnect { + guard let cMix = env.ctx.cMix else { + throw Error.notLoaded + } + env.ctx.e2e = try env.login( + cMixId: cMix.getId(), + identity: try cMix.makeLegacyReceptionIdentity(), + e2eParamsJSON: env.getE2EParams() + ) + } + } +} + +extension MessengerConnect { + public static let unimplemented = MessengerConnect( + run: XCTUnimplemented() + ) +} diff --git a/Sources/XXMessengerClient/Messenger/Functors/MessengerCreate.swift b/Sources/XXMessengerClient/Messenger/Functors/MessengerCreate.swift new file mode 100644 index 00000000..a3514141 --- /dev/null +++ b/Sources/XXMessengerClient/Messenger/Functors/MessengerCreate.swift @@ -0,0 +1,35 @@ +import XXClient +import XCTestDynamicOverlay + +public struct MessengerCreate { + public var run: () throws -> Void + + public func callAsFunction() throws { + try run() + } +} + +extension MessengerCreate { + public static func live(_ env: MessengerEnvironment) -> MessengerCreate { + MessengerCreate { + let ndfData = try env.downloadNDF(env.ndfEnvironment) + let password = env.generateSecret() + try env.passwordStorage.save(password) + let storageDir = env.storageDir() + try env.fileManager.removeDirectory(storageDir) + try env.fileManager.createDirectory(storageDir) + try env.newCMix( + ndfJSON: String(data: ndfData, encoding: .utf8)!, + storageDir: storageDir, + password: password, + registrationCode: nil + ) + } + } +} + +extension MessengerCreate { + public static let unimplemented = MessengerCreate( + run: XCTUnimplemented() + ) +} diff --git a/Sources/XXMessengerClient/Messenger/Functors/MessengerIsConnected.swift b/Sources/XXMessengerClient/Messenger/Functors/MessengerIsConnected.swift new file mode 100644 index 00000000..6a790dd5 --- /dev/null +++ b/Sources/XXMessengerClient/Messenger/Functors/MessengerIsConnected.swift @@ -0,0 +1,25 @@ +import XXClient +import XCTestDynamicOverlay + +public struct MessengerIsConnected { + public var run: () -> Bool + + public func callAsFunction() -> Bool { + run() + } +} + +extension MessengerIsConnected { + public static func live(_ env: MessengerEnvironment) -> MessengerIsConnected { + MessengerIsConnected { + env.ctx.e2e != nil + } + } +} + +extension MessengerIsConnected { + public static let unimplemented = MessengerIsConnected( + run: XCTUnimplemented() + ) +} + diff --git a/Sources/XXMessengerClient/Messenger/Functors/MessengerIsCreated.swift b/Sources/XXMessengerClient/Messenger/Functors/MessengerIsCreated.swift new file mode 100644 index 00000000..cf7f5a4f --- /dev/null +++ b/Sources/XXMessengerClient/Messenger/Functors/MessengerIsCreated.swift @@ -0,0 +1,24 @@ +import XXClient +import XCTestDynamicOverlay + +public struct MessengerIsCreated { + public var run: () -> Bool + + public func callAsFunction() -> Bool { + run() + } +} + +extension MessengerIsCreated { + public static func live(_ env: MessengerEnvironment) -> MessengerIsCreated { + MessengerIsCreated { + env.fileManager.isDirectoryEmpty(env.storageDir()) == false + } + } +} + +extension MessengerIsCreated { + public static let unimplemented = MessengerIsCreated( + run: XCTUnimplemented() + ) +} diff --git a/Sources/XXMessengerClient/Messenger/Functors/MessengerIsLoaded.swift b/Sources/XXMessengerClient/Messenger/Functors/MessengerIsLoaded.swift new file mode 100644 index 00000000..88750885 --- /dev/null +++ b/Sources/XXMessengerClient/Messenger/Functors/MessengerIsLoaded.swift @@ -0,0 +1,24 @@ +import XXClient +import XCTestDynamicOverlay + +public struct MessengerIsLoaded { + public var run: () -> Bool + + public func callAsFunction() -> Bool { + run() + } +} + +extension MessengerIsLoaded { + public static func live(_ env: MessengerEnvironment) -> MessengerIsLoaded { + MessengerIsLoaded { + env.ctx.cMix != nil + } + } +} + +extension MessengerIsLoaded { + public static let unimplemented = MessengerIsLoaded( + run: XCTUnimplemented() + ) +} diff --git a/Sources/XXMessengerClient/Messenger/Functors/MessengerIsLoggedIn.swift b/Sources/XXMessengerClient/Messenger/Functors/MessengerIsLoggedIn.swift new file mode 100644 index 00000000..7f886bef --- /dev/null +++ b/Sources/XXMessengerClient/Messenger/Functors/MessengerIsLoggedIn.swift @@ -0,0 +1,24 @@ +import XXClient +import XCTestDynamicOverlay + +public struct MessengerIsLoggedIn { + public var run: () -> Bool + + public func callAsFunction() -> Bool { + run() + } +} + +extension MessengerIsLoggedIn { + public static func live(_ env: MessengerEnvironment) -> MessengerIsLoggedIn { + MessengerIsLoggedIn { + env.ctx.ud != nil + } + } +} + +extension MessengerIsLoggedIn { + public static let unimplemented = MessengerIsLoggedIn( + run: XCTUnimplemented() + ) +} diff --git a/Sources/XXMessengerClient/Messenger/Functors/MessengerIsRegistered.swift b/Sources/XXMessengerClient/Messenger/Functors/MessengerIsRegistered.swift new file mode 100644 index 00000000..c91db5ac --- /dev/null +++ b/Sources/XXMessengerClient/Messenger/Functors/MessengerIsRegistered.swift @@ -0,0 +1,31 @@ +import XXClient +import XCTestDynamicOverlay + +public struct MessengerIsRegistered { + public enum Error: Swift.Error, Equatable { + case notConnected + } + + public var run: () throws -> Bool + + public func callAsFunction() throws -> Bool { + try run() + } +} + +extension MessengerIsRegistered { + public static func live(_ env: MessengerEnvironment) -> MessengerIsRegistered { + MessengerIsRegistered { + guard let e2e = env.ctx.e2e else { + throw Error.notConnected + } + return try env.isRegisteredWithUD(e2eId: e2e.getId()) + } + } +} + +extension MessengerIsRegistered { + public static let unimplemented = MessengerIsRegistered( + run: XCTUnimplemented() + ) +} diff --git a/Sources/XXMessengerClient/Messenger/Functors/MessengerLoad.swift b/Sources/XXMessengerClient/Messenger/Functors/MessengerLoad.swift new file mode 100644 index 00000000..9b0454a4 --- /dev/null +++ b/Sources/XXMessengerClient/Messenger/Functors/MessengerLoad.swift @@ -0,0 +1,28 @@ +import XXClient +import XCTestDynamicOverlay + +public struct MessengerLoad { + public var run: () throws -> Void + + public func callAsFunction() throws { + try run() + } +} + +extension MessengerLoad { + public static func live(_ env: MessengerEnvironment) -> MessengerLoad { + MessengerLoad { + env.ctx.cMix = try env.loadCMix( + storageDir: env.storageDir(), + password: try env.passwordStorage.load(), + cMixParamsJSON: env.getCMixParams() + ) + } + } +} + +extension MessengerLoad { + public static let unimplemented = MessengerLoad( + run: XCTUnimplemented() + ) +} diff --git a/Sources/XXMessengerClient/Messenger/Functors/MessengerLogIn.swift b/Sources/XXMessengerClient/Messenger/Functors/MessengerLogIn.swift new file mode 100644 index 00000000..4b43a56b --- /dev/null +++ b/Sources/XXMessengerClient/Messenger/Functors/MessengerLogIn.swift @@ -0,0 +1,50 @@ +import XXClient +import XCTestDynamicOverlay + +public struct MessengerLogIn { + public enum Error: Swift.Error, Equatable { + case notLoaded + case notConnected + } + + public var run: () throws -> Void + + public func callAsFunction() throws { + try run() + } +} + +extension MessengerLogIn { + public static func live(_ env: MessengerEnvironment) -> MessengerLogIn { + MessengerLogIn { + guard let cMix = env.ctx.cMix else { + throw Error.notLoaded + } + guard let e2e = env.ctx.e2e else { + throw Error.notConnected + } + if cMix.networkFollowerStatus() != .running { + try cMix.startNetworkFollower(timeoutMS: 30_000) + } + env.ctx.ud = try env.newOrLoadUd( + params: .init( + e2eId: e2e.getId(), + username: nil, + registrationValidationSignature: nil, + cert: env.udCert() ?? e2e.getUdCertFromNdf(), + contactFile: env.udContact() ?? (try e2e.getUdContactFromNdf()), + address: env.udAddress() ?? e2e.getUdAddressFromNdf() + ), + follower: .init { + cMix.networkFollowerStatus().rawValue + } + ) + } + } +} + +extension MessengerLogIn { + public static let unimplemented = MessengerLogIn( + run: XCTUnimplemented() + ) +} diff --git a/Sources/XXMessengerClient/Messenger/Functors/MessengerRegister.swift b/Sources/XXMessengerClient/Messenger/Functors/MessengerRegister.swift new file mode 100644 index 00000000..1440dd43 --- /dev/null +++ b/Sources/XXMessengerClient/Messenger/Functors/MessengerRegister.swift @@ -0,0 +1,52 @@ +import XXClient +import XCTestDynamicOverlay + +public struct MessengerRegister { + public enum Error: Swift.Error, Equatable { + case notLoaded + case notConnected + } + + public var run: (String) throws -> Void + + public func callAsFunction( + username: String + ) throws { + try run(username) + } +} + +extension MessengerRegister { + public static func live(_ env: MessengerEnvironment) -> MessengerRegister { + MessengerRegister { username in + guard let cMix = env.ctx.cMix else { + throw Error.notLoaded + } + guard let e2e = env.ctx.e2e else { + throw Error.notConnected + } + if cMix.networkFollowerStatus() != .running { + try cMix.startNetworkFollower(timeoutMS: 30_000) + } + env.ctx.ud = try env.newOrLoadUd( + params: .init( + e2eId: e2e.getId(), + username: username, + registrationValidationSignature: cMix.getReceptionRegistrationValidationSignature(), + cert: env.udCert() ?? e2e.getUdCertFromNdf(), + contactFile: env.udContact() ?? (try e2e.getUdContactFromNdf()), + address: env.udAddress() ?? e2e.getUdAddressFromNdf() + ), + follower: .init { + cMix.networkFollowerStatus().rawValue + } + ) + } + } +} + +extension MessengerRegister { + public static let unimplemented = MessengerRegister( + run: XCTUnimplemented() + ) +} diff --git a/Sources/XXMessengerClient/Messenger/Messenger.swift b/Sources/XXMessengerClient/Messenger/Messenger.swift new file mode 100644 index 00000000..a477f7cc --- /dev/null +++ b/Sources/XXMessengerClient/Messenger/Messenger.swift @@ -0,0 +1,46 @@ +import XXClient + +public struct Messenger { + public var isCreated: MessengerIsCreated + public var create: MessengerCreate + public var isLoaded: MessengerIsLoaded + public var load: MessengerLoad + public var isConnected: MessengerIsConnected + public var connect: MessengerConnect + public var isRegistered: MessengerIsRegistered + public var register: MessengerRegister + public var isLoggedIn: MessengerIsLoggedIn + public var logIn: MessengerLogIn +} + +extension Messenger { + public static func live(_ env: MessengerEnvironment) -> Messenger { + Messenger( + isCreated: .live(env), + create: .live(env), + isLoaded: .live(env), + load: .live(env), + isConnected: .live(env), + connect: .live(env), + isRegistered: .live(env), + register: .live(env), + isLoggedIn: .live(env), + logIn: .live(env) + ) + } +} + +extension Messenger { + public static let unimplemented = Messenger( + isCreated: .unimplemented, + create: .unimplemented, + isLoaded: .unimplemented, + load: .unimplemented, + isConnected: .unimplemented, + connect: .unimplemented, + isRegistered: .unimplemented, + register: .unimplemented, + isLoggedIn: .unimplemented, + logIn: .unimplemented + ) +} diff --git a/Sources/XXMessengerClient/Messenger/MessengerContext.swift b/Sources/XXMessengerClient/Messenger/MessengerContext.swift new file mode 100644 index 00000000..ba67ed2b --- /dev/null +++ b/Sources/XXMessengerClient/Messenger/MessengerContext.swift @@ -0,0 +1,17 @@ +import XXClient + +public class MessengerContext { + public init( + cMix: CMix? = nil, + e2e: E2E? = nil, + ud: UserDiscovery? = nil + ) { + self.cMix = cMix + self.e2e = e2e + self.ud = ud + } + + public var cMix: CMix? + public var e2e: E2E? + public var ud: UserDiscovery? +} diff --git a/Sources/XXMessengerClient/Messenger/MessengerEnvironment.swift b/Sources/XXMessengerClient/Messenger/MessengerEnvironment.swift new file mode 100644 index 00000000..dfa7dfcd --- /dev/null +++ b/Sources/XXMessengerClient/Messenger/MessengerEnvironment.swift @@ -0,0 +1,73 @@ +import Foundation +import XXClient +import XCTestDynamicOverlay + +public struct MessengerEnvironment { + public var ctx: MessengerContext + public var downloadNDF: DownloadAndVerifySignedNdf + public var fileManager: MessengerFileManager + public var generateSecret: GenerateSecret + public var getCMixParams: GetCMixParams + public var getE2EParams: GetE2EParams + public var isRegisteredWithUD: IsRegisteredWithUD + public var loadCMix: LoadCMix + public var login: Login + public var ndfEnvironment: NDFEnvironment + public var newCMix: NewCMix + public var newOrLoadUd: NewOrLoadUd + public var passwordStorage: PasswordStorage + public var storageDir: () -> String + public var udAddress: () -> String? + public var udCert: () -> Data? + public var udContact: () -> Data? +} + +extension MessengerEnvironment { + public static let defaultStorageDir = FileManager.default + .urls(for: .applicationSupportDirectory, in: .userDomainMask) + .first! + .appendingPathComponent("xx.network.client") + .path + + public static let live = MessengerEnvironment( + ctx: .init(), + downloadNDF: .live, + fileManager: .live(), + generateSecret: .live, + getCMixParams: .liveDefault, + getE2EParams: .liveDefault, + isRegisteredWithUD: .live, + loadCMix: .live, + login: .live, + ndfEnvironment: .mainnet, + newCMix: .live, + newOrLoadUd: .live, + passwordStorage: .keychain, + storageDir: { MessengerEnvironment.defaultStorageDir }, + udAddress: { nil }, + udCert: { nil }, + udContact: { nil } + ) +} + +extension MessengerEnvironment { + public static let unimplemented = MessengerEnvironment( + ctx: .init(), + downloadNDF: .unimplemented, + fileManager: .unimplemented, + generateSecret: .unimplemented, + getCMixParams: .unimplemented, + getE2EParams: .unimplemented, + isRegisteredWithUD: .unimplemented, + loadCMix: .unimplemented, + login: .unimplemented, + ndfEnvironment: .unimplemented, + newCMix: .unimplemented, + newOrLoadUd: .unimplemented, + passwordStorage: .unimplemented, + storageDir: XCTUnimplemented("\(Self.self).storageDir", placeholder: ""), + udAddress: XCTUnimplemented("\(Self.self).udAddress", placeholder: nil), + udCert: XCTUnimplemented("\(Self.self).udCert", placeholder: nil), + udContact: XCTUnimplemented("\(Self.self).udContact", placeholder: nil) + ) +} diff --git a/Sources/XXMessengerClient/Unimplemented.swift b/Sources/XXMessengerClient/Unimplemented.swift deleted file mode 100644 index 9454b9d7..00000000 --- a/Sources/XXMessengerClient/Unimplemented.swift +++ /dev/null @@ -1 +0,0 @@ -private enum Unimplemented {} diff --git a/Sources/XXMessengerClient/Utils/MessengerFileManager.swift b/Sources/XXMessengerClient/Utils/MessengerFileManager.swift new file mode 100644 index 00000000..4ff49c5f --- /dev/null +++ b/Sources/XXMessengerClient/Utils/MessengerFileManager.swift @@ -0,0 +1,40 @@ +import Foundation +import XCTestDynamicOverlay + +public struct MessengerFileManager { + public var isDirectoryEmpty: (String) -> Bool + public var removeDirectory: (String) throws -> Void + public var createDirectory: (String) throws -> Void +} + +extension MessengerFileManager { + public static func live( + fileManager: FileManager = .default + ) -> MessengerFileManager { + MessengerFileManager( + isDirectoryEmpty: { path in + let contents = try? fileManager.contentsOfDirectory(atPath: path) + return contents?.isEmpty ?? true + }, + removeDirectory: { path in + if fileManager.fileExists(atPath: path) { + try fileManager.removeItem(atPath: path) + } + }, + createDirectory: { path in + try fileManager.createDirectory( + atPath: path, + withIntermediateDirectories: true + ) + } + ) + } +} + +extension MessengerFileManager { + public static let unimplemented = MessengerFileManager( + isDirectoryEmpty: XCTUnimplemented("\(Self.self).isDirectoryEmpty"), + removeDirectory: XCTUnimplemented("\(Self.self).removeDirectory"), + createDirectory: XCTUnimplemented("\(Self.self).createDirectory") + ) +} diff --git a/Sources/XXMessengerClient/Utils/PasswordStorage+Keychain.swift b/Sources/XXMessengerClient/Utils/PasswordStorage+Keychain.swift new file mode 100644 index 00000000..0a062cc6 --- /dev/null +++ b/Sources/XXMessengerClient/Utils/PasswordStorage+Keychain.swift @@ -0,0 +1,21 @@ +import KeychainAccess +import XXClient + +extension PasswordStorage { + public static let keychain: PasswordStorage = { + let keychain = KeychainAccess.Keychain( + service: "xx.network.client.messenger" + ) + return PasswordStorage( + save: { password in + keychain[data: "password"] = password + }, + load: { + guard let password = keychain[data: "password"] else { + throw MissingPasswordError() + } + return password + } + ) + }() +} diff --git a/Tests/XXMessengerClientTests/Messenger/Functors/MessengerConnectTests.swift b/Tests/XXMessengerClientTests/Messenger/Functors/MessengerConnectTests.swift new file mode 100644 index 00000000..c44b4907 --- /dev/null +++ b/Tests/XXMessengerClientTests/Messenger/Functors/MessengerConnectTests.swift @@ -0,0 +1,107 @@ +import CustomDump +import XXClient +import XCTest +@testable import XXMessengerClient + +final class MessengerConnectTests: XCTestCase { + func testConnect() throws { + struct DidLogIn: Equatable { + var ephemeral: Bool + var cMixId: Int + var authCallbacksProvided: Bool + var identity: ReceptionIdentity + var e2eParamsJSON: Data + } + var didLogIn: [DidLogIn] = [] + + let cMixId = 1234 + let receptionId = ReceptionIdentity.stub + let e2eParams = "e2e-params".data(using: .utf8)! + + var env: MessengerEnvironment = .unimplemented + env.ctx.cMix = .unimplemented + env.ctx.cMix!.getId.run = { cMixId } + env.ctx.cMix!.makeLegacyReceptionIdentity.run = { receptionId } + env.getE2EParams.run = { e2eParams } + env.login.run = { ephemeral, cMixId, authCallbacks, identity, e2eParamsJSON in + didLogIn.append(.init( + ephemeral: ephemeral, + cMixId: cMixId, + authCallbacksProvided: authCallbacks != nil, + identity: identity, + e2eParamsJSON: e2eParamsJSON + )) + return .unimplemented + } + let connect: MessengerConnect = .live(env) + + try connect() + + XCTAssertNoDifference(didLogIn, [ + DidLogIn( + ephemeral: false, + cMixId: 1234, + authCallbacksProvided: false, + identity: .stub, + e2eParamsJSON: e2eParams + ) + ]) + + XCTAssertNotNil(env.ctx.e2e) + } + + func testConnectWithoutCMix() { + let env: MessengerEnvironment = .unimplemented + env.ctx.cMix = nil + let connect: MessengerConnect = .live(env) + + XCTAssertThrowsError(try connect()) { error in + XCTAssertEqual( + error as? MessengerConnect.Error, + MessengerConnect.Error.notLoaded + ) + } + } + + func testMakeLegacyReceptionIdentityFailure() { + struct Error: Swift.Error, Equatable {} + let error = Error() + + let env: MessengerEnvironment = .unimplemented + env.ctx.cMix = .unimplemented + env.ctx.cMix!.getId.run = { 1234 } + env.ctx.cMix!.makeLegacyReceptionIdentity.run = { throw error } + let connect: MessengerConnect = .live(env) + + XCTAssertThrowsError(try connect()) { err in + XCTAssertEqual(err as? Error, error) + } + } + + func testLoginFailure() { + struct Error: Swift.Error, Equatable {} + let error = Error() + + var env: MessengerEnvironment = .unimplemented + env.ctx.cMix = .unimplemented + env.ctx.cMix!.getId.run = { 1234 } + env.ctx.cMix!.makeLegacyReceptionIdentity.run = { .stub } + env.getE2EParams.run = { "e2e-params".data(using: .utf8)! } + env.login.run = { _, _, _, _, _ in throw error } + let connect: MessengerConnect = .live(env) + + XCTAssertThrowsError(try connect()) { err in + XCTAssertEqual(err as? Error, error) + } + } +} + +private extension ReceptionIdentity { + static let stub = ReceptionIdentity( + id: "id".data(using: .utf8)!, + rsaPrivatePem: "rsaPrivatePem".data(using: .utf8)!, + salt: "salt".data(using: .utf8)!, + dhKeyPrivate: "dhKeyPrivate".data(using: .utf8)!, + e2eGrp: "e2eGrp".data(using: .utf8)! + ) +} diff --git a/Tests/XXMessengerClientTests/Messenger/Functors/MessengerCreateTests.swift b/Tests/XXMessengerClientTests/Messenger/Functors/MessengerCreateTests.swift new file mode 100644 index 00000000..5db87012 --- /dev/null +++ b/Tests/XXMessengerClientTests/Messenger/Functors/MessengerCreateTests.swift @@ -0,0 +1,159 @@ +import XCTest +import XXClient +@testable import XXMessengerClient +import CustomDump + +final class MessengerCreateTests: XCTestCase { + func testCreate() throws { + struct DidNewCMix: Equatable { + var ndfJSON: String + var storageDir: String + var password: Data + var registrationCode: String? + } + + var didDownloadNDF: [NDFEnvironment] = [] + var didGenerateSecret: [Int] = [] + var didSavePassword: [Data] = [] + var didRemoveDirectory: [String] = [] + var didCreateDirectory: [String] = [] + var didNewCMix: [DidNewCMix] = [] + + let ndf = "ndf".data(using: .utf8)! + let password = "password".data(using: .utf8)! + let storageDir = "storage-dir" + + var env: MessengerEnvironment = .unimplemented + env.ndfEnvironment = .unimplemented + env.downloadNDF.run = { ndfEnvironment in + didDownloadNDF.append(ndfEnvironment) + return ndf + } + env.generateSecret.run = { numBytes in + didGenerateSecret.append(numBytes) + return password + } + env.passwordStorage.save = { password in + didSavePassword.append(password) + } + env.storageDir = { + storageDir + } + env.fileManager.removeDirectory = { path in + didRemoveDirectory.append(path) + } + env.fileManager.createDirectory = { path in + didCreateDirectory.append(path) + } + env.newCMix.run = { ndfJSON, storageDir, password, registrationCode in + didNewCMix.append(.init( + ndfJSON: ndfJSON, + storageDir: storageDir, + password: password, + registrationCode: registrationCode + )) + } + let create: MessengerCreate = .live(env) + + try create() + + XCTAssertNoDifference(didDownloadNDF, [.unimplemented]) + XCTAssertNoDifference(didGenerateSecret, [32]) + XCTAssertNoDifference(didSavePassword, [password]) + XCTAssertNoDifference(didRemoveDirectory, [storageDir]) + XCTAssertNoDifference(didCreateDirectory, [storageDir]) + XCTAssertNoDifference(didNewCMix, [.init( + ndfJSON: String(data: ndf, encoding: .utf8)!, + storageDir: storageDir, + password: password, + registrationCode: nil + )]) + } + + func testDownloadNDFFailure() { + struct Error: Swift.Error, Equatable {} + let error = Error() + + var env: MessengerEnvironment = .unimplemented + env.ndfEnvironment = .unimplemented + env.downloadNDF.run = { _ in throw error } + let create: MessengerCreate = .live(env) + + XCTAssertThrowsError(try create()) { err in + XCTAssertEqual(err as? Error, error) + } + } + + func testSavePasswordFailure() { + struct Error: Swift.Error, Equatable {} + let error = Error() + + var env: MessengerEnvironment = .unimplemented + env.ndfEnvironment = .unimplemented + env.downloadNDF.run = { _ in "ndf".data(using: .utf8)! } + env.generateSecret.run = { _ in "password".data(using: .utf8)! } + env.passwordStorage.save = { _ in throw error } + let create: MessengerCreate = .live(env) + + XCTAssertThrowsError(try create()) { err in + XCTAssertEqual(err as? Error, error) + } + } + + func testRemoveDirectoryFailure() { + struct Error: Swift.Error, Equatable {} + let error = Error() + + var env: MessengerEnvironment = .unimplemented + env.ndfEnvironment = .unimplemented + env.downloadNDF.run = { _ in "ndf".data(using: .utf8)! } + env.generateSecret.run = { _ in "password".data(using: .utf8)! } + env.passwordStorage.save = { _ in } + env.storageDir = { "storage-dir" } + env.fileManager.removeDirectory = { _ in throw error } + let create: MessengerCreate = .live(env) + + XCTAssertThrowsError(try create()) { err in + XCTAssertEqual(err as? Error, error) + } + } + + func testCreateDirectoryFailure() { + struct Error: Swift.Error, Equatable {} + let error = Error() + + var env: MessengerEnvironment = .unimplemented + env.ndfEnvironment = .unimplemented + env.downloadNDF.run = { _ in "ndf".data(using: .utf8)! } + env.generateSecret.run = { _ in "password".data(using: .utf8)! } + env.passwordStorage.save = { _ in } + env.storageDir = { "storage-dir" } + env.fileManager.removeDirectory = { _ in } + env.fileManager.createDirectory = { _ in throw error } + let create: MessengerCreate = .live(env) + + XCTAssertThrowsError(try create()) { err in + XCTAssertEqual(err as? Error, error) + } + } + + func testNewCMixFailure() { + struct Error: Swift.Error, Equatable {} + let error = Error() + + var env: MessengerEnvironment = .unimplemented + env.ndfEnvironment = .unimplemented + env.downloadNDF.run = { _ in "ndf".data(using: .utf8)! } + env.generateSecret.run = { _ in "password".data(using: .utf8)! } + env.passwordStorage.save = { _ in } + env.storageDir = { "storage-dir" } + env.fileManager.removeDirectory = { _ in } + env.fileManager.createDirectory = { _ in } + env.newCMix.run = { _, _, _, _ in throw error } + let create: MessengerCreate = .live(env) + + XCTAssertThrowsError(try create()) { err in + XCTAssertEqual(err as? Error, error) + } + } +} diff --git a/Tests/XXMessengerClientTests/Messenger/Functors/MessengerIsConnectedTests.swift b/Tests/XXMessengerClientTests/Messenger/Functors/MessengerIsConnectedTests.swift new file mode 100644 index 00000000..e207e8a5 --- /dev/null +++ b/Tests/XXMessengerClientTests/Messenger/Functors/MessengerIsConnectedTests.swift @@ -0,0 +1,20 @@ +import XCTest +@testable import XXMessengerClient + +final class MessengerIsConnectedTests: XCTestCase { + func testWithE2E() { + let env: MessengerEnvironment = .unimplemented + env.ctx.e2e = .unimplemented + let isConnected: MessengerIsConnected = .live(env) + + XCTAssertTrue(isConnected()) + } + + func testWithoutE2E() { + let env: MessengerEnvironment = .unimplemented + env.ctx.e2e = nil + let isConnected: MessengerIsConnected = .live(env) + + XCTAssertFalse(isConnected()) + } +} diff --git a/Tests/XXMessengerClientTests/Messenger/Functors/MessengerIsCreatedTests.swift b/Tests/XXMessengerClientTests/Messenger/Functors/MessengerIsCreatedTests.swift new file mode 100644 index 00000000..a96c8a60 --- /dev/null +++ b/Tests/XXMessengerClientTests/Messenger/Functors/MessengerIsCreatedTests.swift @@ -0,0 +1,37 @@ +import CustomDump +import XCTest +@testable import XXMessengerClient + +final class MessengerIsCreatedTests: XCTestCase { + func testStorageDirNotEmpty() { + var didIsDirectoryEmpty: [String] = [] + let storageDir = "storage-dir" + + var env: MessengerEnvironment = .unimplemented + env.storageDir = { storageDir } + env.fileManager.isDirectoryEmpty = { path in + didIsDirectoryEmpty.append(path) + return false + } + let isCreated: MessengerIsCreated = .live(env) + + XCTAssertTrue(isCreated()) + XCTAssertNoDifference(didIsDirectoryEmpty, [storageDir]) + } + + func testStorageDirEmpty() { + var didIsDirectoryEmpty: [String] = [] + let storageDir = "storage-dir" + + var env: MessengerEnvironment = .unimplemented + env.storageDir = { storageDir } + env.fileManager.isDirectoryEmpty = { path in + didIsDirectoryEmpty.append(path) + return true + } + let isCreated: MessengerIsCreated = .live(env) + + XCTAssertFalse(isCreated()) + XCTAssertNoDifference(didIsDirectoryEmpty, [storageDir]) + } +} diff --git a/Tests/XXMessengerClientTests/Messenger/Functors/MessengerIsLoadedTests.swift b/Tests/XXMessengerClientTests/Messenger/Functors/MessengerIsLoadedTests.swift new file mode 100644 index 00000000..c83dc523 --- /dev/null +++ b/Tests/XXMessengerClientTests/Messenger/Functors/MessengerIsLoadedTests.swift @@ -0,0 +1,20 @@ +import XCTest +@testable import XXMessengerClient + +final class MessengerIsLoadedTests: XCTestCase { + func testWithCMix() { + let env: MessengerEnvironment = .unimplemented + env.ctx.cMix = .unimplemented + let isLoaded: MessengerIsLoaded = .live(env) + + XCTAssertTrue(isLoaded()) + } + + func testWithoutCMix() { + let env: MessengerEnvironment = .unimplemented + env.ctx.cMix = nil + let isLoaded: MessengerIsLoaded = .live(env) + + XCTAssertFalse(isLoaded()) + } +} diff --git a/Tests/XXMessengerClientTests/Messenger/Functors/MessengerIsLoggedInTests.swift b/Tests/XXMessengerClientTests/Messenger/Functors/MessengerIsLoggedInTests.swift new file mode 100644 index 00000000..6b5b7903 --- /dev/null +++ b/Tests/XXMessengerClientTests/Messenger/Functors/MessengerIsLoggedInTests.swift @@ -0,0 +1,20 @@ +import XCTest +@testable import XXMessengerClient + +final class MessengerIsLoggedInTests: XCTestCase { + func testWithUD() { + let env: MessengerEnvironment = .unimplemented + env.ctx.ud = .unimplemented + let isLoggedIn: MessengerIsLoggedIn = .live(env) + + XCTAssertTrue(isLoggedIn()) + } + + func testWithoutUD() { + let env: MessengerEnvironment = .unimplemented + env.ctx.ud = nil + let isLoggedIn: MessengerIsLoggedIn = .live(env) + + XCTAssertFalse(isLoggedIn()) + } +} diff --git a/Tests/XXMessengerClientTests/Messenger/Functors/MessengerIsRegisteredTests.swift b/Tests/XXMessengerClientTests/Messenger/Functors/MessengerIsRegisteredTests.swift new file mode 100644 index 00000000..250fdad8 --- /dev/null +++ b/Tests/XXMessengerClientTests/Messenger/Functors/MessengerIsRegisteredTests.swift @@ -0,0 +1,58 @@ +import XCTest +@testable import XXMessengerClient + +final class MessengerIsRegisteredTests: XCTestCase { + func testRegistered() throws { + var didIsRegisteredWithUD: [Int] = [] + + var env: MessengerEnvironment = .unimplemented + env.ctx.e2e = .unimplemented + env.ctx.e2e!.getId.run = { 1234 } + env.isRegisteredWithUD.run = { e2eId in + didIsRegisteredWithUD.append(e2eId) + return true + } + let isRegistered: MessengerIsRegistered = .live(env) + + XCTAssertTrue(try isRegistered()) + XCTAssertEqual(didIsRegisteredWithUD, [1234]) + } + + func testNotRegistered() throws { + var env: MessengerEnvironment = .unimplemented + env.ctx.e2e = .unimplemented + env.ctx.e2e!.getId.run = { 1234 } + env.isRegisteredWithUD.run = { _ in false } + let isRegistered: MessengerIsRegistered = .live(env) + + XCTAssertFalse(try isRegistered()) + } + + func testWithoutE2E() { + let env: MessengerEnvironment = .unimplemented + env.ctx.e2e = nil + let isRegistered: MessengerIsRegistered = .live(env) + + XCTAssertThrowsError(try isRegistered()) { err in + XCTAssertEqual( + err as? MessengerIsRegistered.Error, + MessengerIsRegistered.Error.notConnected + ) + } + } + + func testIsRegisteredWithUDFailure() { + struct Error: Swift.Error, Equatable {} + let error = Error() + + var env: MessengerEnvironment = .unimplemented + env.ctx.e2e = .unimplemented + env.ctx.e2e!.getId.run = { 1234 } + env.isRegisteredWithUD.run = { _ in throw error } + let isRegistered: MessengerIsRegistered = .live(env) + + XCTAssertThrowsError(try isRegistered()) { err in + XCTAssertEqual(err as? Error, error) + } + } +} diff --git a/Tests/XXMessengerClientTests/Messenger/Functors/MessengerLoadTests.swift b/Tests/XXMessengerClientTests/Messenger/Functors/MessengerLoadTests.swift new file mode 100644 index 00000000..ef5694c2 --- /dev/null +++ b/Tests/XXMessengerClientTests/Messenger/Functors/MessengerLoadTests.swift @@ -0,0 +1,77 @@ +import CustomDump +import XCTest +import XXClient +@testable import XXMessengerClient + +final class MessengerLoadTests: XCTestCase { + func testLoad() throws { + struct DidLoadCMix: Equatable { + var storageDir: String + var password: Data + var cMixParamsJSON: Data + } + var didLoadCMix: [DidLoadCMix] = [] + + let storageDir = "test-storage-dir" + let password = "password".data(using: .utf8)! + let cMixParams = "cmix-params".data(using: .utf8)! + + var env: MessengerEnvironment = .unimplemented + env.ctx.cMix = nil + env.storageDir = { storageDir } + env.passwordStorage.load = { password } + env.getCMixParams.run = { cMixParams } + env.loadCMix.run = { storageDir, password, cMixParamsJSON in + didLoadCMix.append(.init( + storageDir: storageDir, + password: password, + cMixParamsJSON: cMixParamsJSON + )) + return .unimplemented + } + let load: MessengerLoad = .live(env) + + try load() + + XCTAssertNoDifference(didLoadCMix, [ + DidLoadCMix( + storageDir: storageDir, + password: password, + cMixParamsJSON: cMixParams + ) + ]) + XCTAssertNotNil(env.ctx.cMix) + } + + func testMissingPassword() { + var env: MessengerEnvironment = .unimplemented + env.ctx.cMix = nil + env.storageDir = { "storage-dir" } + env.passwordStorage.load = { throw PasswordStorage.MissingPasswordError() } + let load: MessengerLoad = .live(env) + + XCTAssertThrowsError(try load()) { err in + XCTAssertEqual( + err as? PasswordStorage.MissingPasswordError, + PasswordStorage.MissingPasswordError() + ) + } + } + + func testLoadCMixFailure() { + struct Error: Swift.Error, Equatable {} + let error = Error() + + var env: MessengerEnvironment = .unimplemented + env.ctx.cMix = nil + env.storageDir = { "storage-dir" } + env.passwordStorage.load = { "password".data(using: .utf8)! } + env.getCMixParams.run = { "cmix-params".data(using: .utf8)! } + env.loadCMix.run = { _, _, _ in throw error } + let load: MessengerLoad = .live(env) + + XCTAssertThrowsError(try load()) { err in + XCTAssertEqual(err as? Error, error) + } + } +} diff --git a/Tests/XXMessengerClientTests/Messenger/Functors/MessengerLogInTests.swift b/Tests/XXMessengerClientTests/Messenger/Functors/MessengerLogInTests.swift new file mode 100644 index 00000000..92e511f2 --- /dev/null +++ b/Tests/XXMessengerClientTests/Messenger/Functors/MessengerLogInTests.swift @@ -0,0 +1,171 @@ +import XCTest +import XXClient +@testable import XXMessengerClient +import CustomDump + +final class MessengerLogInTests: XCTestCase { + func testLogin() throws { + var didStartNetworkFollower: [Int] = [] + var didNewOrLoadUDWithParams: [NewOrLoadUd.Params] = [] + var didNewOrLoadUDWithFollower: [UdNetworkStatus] = [] + + let e2eId = 1234 + let networkFollowerStatus: NetworkFollowerStatus = .stopped + let udCertFromNDF = "ndf-ud-cert".data(using: .utf8)! + let udContactFromNDF = "ndf-ud-contact".data(using: .utf8)! + let udAddressFromNDF = "ndf-ud-address" + + var env: MessengerEnvironment = .unimplemented + env.ctx.cMix = .unimplemented + env.ctx.cMix!.networkFollowerStatus.run = { networkFollowerStatus } + env.ctx.cMix!.startNetworkFollower.run = { timeout in + didStartNetworkFollower.append(timeout) + } + env.ctx.e2e = .unimplemented + env.ctx.e2e!.getId.run = { e2eId } + env.udCert = { nil } + env.udContact = { nil } + env.udAddress = { nil } + env.ctx.e2e!.getUdCertFromNdf.run = { udCertFromNDF } + env.ctx.e2e!.getUdContactFromNdf.run = { udContactFromNDF } + env.ctx.e2e!.getUdAddressFromNdf.run = { udAddressFromNDF } + env.newOrLoadUd.run = { params, follower in + didNewOrLoadUDWithParams.append(params) + didNewOrLoadUDWithFollower.append(follower) + return .unimplemented + } + let logIn: MessengerLogIn = .live(env) + try logIn() + + XCTAssertEqual(didStartNetworkFollower, [30_000]) + XCTAssertNoDifference(didNewOrLoadUDWithParams, [.init( + e2eId: e2eId, + username: nil, + registrationValidationSignature: nil, + cert: udCertFromNDF, + contactFile: udContactFromNDF, + address: udAddressFromNDF + )]) + XCTAssertEqual(didNewOrLoadUDWithFollower.count, 1) + XCTAssertEqual( + didNewOrLoadUDWithFollower.first?.handle(), + networkFollowerStatus.rawValue + ) + XCTAssertNotNil(env.ctx.ud) + } + + func testLoginWithAlternativeUD() throws { + var didNewOrLoadUDWithParams: [NewOrLoadUd.Params] = [] + let e2eId = 1234 + let altUdCert = "alt-ud-cert".data(using: .utf8)! + let altUdContact = "alt-ud-contact".data(using: .utf8)! + let altUdAddress = "alt-ud-address" + + var env: MessengerEnvironment = .unimplemented + env.ctx.cMix = .unimplemented + env.ctx.cMix!.networkFollowerStatus.run = { .running } + env.ctx.e2e = .unimplemented + env.ctx.e2e!.getId.run = { e2eId } + env.udCert = { altUdCert } + env.udContact = { altUdContact } + env.udAddress = { altUdAddress } + env.newOrLoadUd.run = { params, _ in + didNewOrLoadUDWithParams.append(params) + return .unimplemented + } + let logIn: MessengerLogIn = .live(env) + try logIn() + + XCTAssertNoDifference(didNewOrLoadUDWithParams, [.init( + e2eId: e2eId, + username: nil, + registrationValidationSignature: nil, + cert: altUdCert, + contactFile: altUdContact, + address: altUdAddress + )]) + XCTAssertNotNil(env.ctx.ud) + } + + func testLoginWithoutCMix() { + let env: MessengerEnvironment = .unimplemented + env.ctx.cMix = nil + let logIn: MessengerLogIn = .live(env) + + XCTAssertThrowsError(try logIn()) { error in + XCTAssertEqual( + error as? MessengerLogIn.Error, + MessengerLogIn.Error.notLoaded + ) + } + } + + func testLoginWithoutE2E() { + let env: MessengerEnvironment = .unimplemented + env.ctx.cMix = .unimplemented + env.ctx.e2e = nil + let logIn: MessengerLogIn = .live(env) + + XCTAssertThrowsError(try logIn()) { error in + XCTAssertEqual( + error as? MessengerLogIn.Error, + MessengerLogIn.Error.notConnected + ) + } + } + + func testStartNetworkFollowerFailure() { + struct Error: Swift.Error, Equatable {} + let error = Error() + + let env: MessengerEnvironment = .unimplemented + env.ctx.cMix = .unimplemented + env.ctx.cMix!.networkFollowerStatus.run = { .stopped } + env.ctx.cMix!.startNetworkFollower.run = { _ in throw error } + let logIn: MessengerLogIn = .live(env) + + XCTAssertThrowsError(try logIn()) { err in + XCTAssertEqual(err as? Error, error) + } + } + + func testGetUdContactFromNdfFailure() { + struct Error: Swift.Error, Equatable {} + let error = Error() + + var env: MessengerEnvironment = .unimplemented + env.ctx.cMix = .unimplemented + env.ctx.cMix!.networkFollowerStatus.run = { .running } + env.ctx.e2e = .unimplemented + env.ctx.e2e!.getId.run = { 1234 } + env.udCert = { nil } + env.udContact = { nil } + env.ctx.e2e!.getUdCertFromNdf.run = { "ndf-ud-cert".data(using: .utf8)! } + env.ctx.e2e!.getUdContactFromNdf.run = { throw error } + let logIn: MessengerLogIn = .live(env) + + XCTAssertThrowsError(try logIn()) { err in + XCTAssertEqual(err as? Error, error) + } + } + + func testNewOrLoadUdFailure() { + struct Error: Swift.Error, Equatable {} + let error = Error() + + var env: MessengerEnvironment = .unimplemented + env.ctx.cMix = .unimplemented + env.ctx.cMix!.networkFollowerStatus.run = { .running } + env.ctx.e2e = .unimplemented + env.ctx.e2e!.getId.run = { 1234 } + env.udCert = { "ud-cert".data(using: .utf8)! } + env.udContact = { "ud-contact".data(using: .utf8)! } + env.udAddress = { "ud-address" } + env.newOrLoadUd.run = { _, _ in throw error } + let logIn: MessengerLogIn = .live(env) + + XCTAssertThrowsError(try logIn()) { err in + XCTAssertEqual(err as? Error, error) + } + } +} diff --git a/Tests/XXMessengerClientTests/Messenger/Functors/MessengerRegisterTests.swift b/Tests/XXMessengerClientTests/Messenger/Functors/MessengerRegisterTests.swift new file mode 100644 index 00000000..deb6a8dc --- /dev/null +++ b/Tests/XXMessengerClientTests/Messenger/Functors/MessengerRegisterTests.swift @@ -0,0 +1,188 @@ +import CustomDump +import XCTest +import XXClient +@testable import XXMessengerClient + +final class MessengerRegisterTests: XCTestCase { + func testRegister() throws { + var didStartNetworkFollower: [Int] = [] + var didNewOrLoadUDWithParams: [NewOrLoadUd.Params] = [] + var didNewOrLoadUDWithFollower: [UdNetworkStatus] = [] + + let e2eId = 1234 + let networkFollowerStatus: NetworkFollowerStatus = .stopped + let registrationSignature = "registration-signature".data(using: .utf8)! + let udCertFromNDF = "ndf-ud-cert".data(using: .utf8)! + let udContactFromNDF = "ndf-ud-contact".data(using: .utf8)! + let udAddressFromNDF = "ndf-ud-address" + let username = "new-user-name" + + var env: MessengerEnvironment = .unimplemented + env.ctx.cMix = .unimplemented + env.ctx.cMix!.networkFollowerStatus.run = { networkFollowerStatus } + env.ctx.cMix!.startNetworkFollower.run = { timeout in + didStartNetworkFollower.append(timeout) + } + env.ctx.cMix!.getReceptionRegistrationValidationSignature.run = { + registrationSignature + } + env.ctx.e2e = .unimplemented + env.ctx.e2e!.getId.run = { e2eId } + env.udCert = { nil } + env.udContact = { nil } + env.udAddress = { nil } + env.ctx.e2e!.getUdCertFromNdf.run = { udCertFromNDF } + env.ctx.e2e!.getUdContactFromNdf.run = { udContactFromNDF } + env.ctx.e2e!.getUdAddressFromNdf.run = { udAddressFromNDF } + env.newOrLoadUd.run = { params, follower in + didNewOrLoadUDWithParams.append(params) + didNewOrLoadUDWithFollower.append(follower) + return .unimplemented + } + let register: MessengerRegister = .live(env) + try register(username: username) + + XCTAssertEqual(didStartNetworkFollower, [30_000]) + XCTAssertNoDifference(didNewOrLoadUDWithParams, [.init( + e2eId: e2eId, + username: username, + registrationValidationSignature: registrationSignature, + cert: udCertFromNDF, + contactFile: udContactFromNDF, + address: udAddressFromNDF + )]) + XCTAssertEqual(didNewOrLoadUDWithFollower.count, 1) + XCTAssertEqual( + didNewOrLoadUDWithFollower.first?.handle(), + networkFollowerStatus.rawValue + ) + XCTAssertNotNil(env.ctx.ud) + } + + func testRegisterWithAlternativeUD() throws { + var didNewOrLoadUDWithParams: [NewOrLoadUd.Params] = [] + let e2eId = 1234 + let registrationSignature = "registration-signature".data(using: .utf8)! + let altUdCert = "alt-ud-cert".data(using: .utf8)! + let altUdContact = "alt-ud-contact".data(using: .utf8)! + let altUdAddress = "alt-ud-address" + let username = "new-user-name" + + var env: MessengerEnvironment = .unimplemented + env.ctx.cMix = .unimplemented + env.ctx.cMix!.networkFollowerStatus.run = { .running } + env.ctx.cMix!.getReceptionRegistrationValidationSignature.run = { + registrationSignature + } + env.ctx.e2e = .unimplemented + env.ctx.e2e!.getId.run = { e2eId } + env.udCert = { altUdCert } + env.udContact = { altUdContact } + env.udAddress = { altUdAddress } + env.newOrLoadUd.run = { params, _ in + didNewOrLoadUDWithParams.append(params) + return .unimplemented + } + let register: MessengerRegister = .live(env) + try register(username: username) + + XCTAssertNoDifference(didNewOrLoadUDWithParams, [.init( + e2eId: e2eId, + username: username, + registrationValidationSignature: registrationSignature, + cert: altUdCert, + contactFile: altUdContact, + address: altUdAddress + )]) + XCTAssertNotNil(env.ctx.ud) + } + + func testRegisterWithoutCMix() { + let env: MessengerEnvironment = .unimplemented + env.ctx.cMix = nil + let register: MessengerRegister = .live(env) + + XCTAssertThrowsError(try register(username: "new-user-name")) { error in + XCTAssertEqual( + error as? MessengerRegister.Error, + MessengerRegister.Error.notLoaded + ) + } + } + + func testRegisterWithoutE2E() { + let env: MessengerEnvironment = .unimplemented + env.ctx.cMix = .unimplemented + env.ctx.e2e = nil + let register: MessengerRegister = .live(env) + + XCTAssertThrowsError(try register(username: "new-user-name")) { error in + XCTAssertEqual( + error as? MessengerRegister.Error, + MessengerRegister.Error.notConnected + ) + } + } + + func testStartNetworkFollowerFailure() { + struct Error: Swift.Error, Equatable {} + let error = Error() + + let env: MessengerEnvironment = .unimplemented + env.ctx.cMix = .unimplemented + env.ctx.cMix!.networkFollowerStatus.run = { .stopped } + env.ctx.cMix!.startNetworkFollower.run = { _ in throw error } + env.ctx.e2e = .unimplemented + let register: MessengerRegister = .live(env) + + XCTAssertThrowsError(try register(username: "new-user-name")) { err in + XCTAssertEqual(err as? Error, error) + } + } + + func testGetUdContactFromNdfFailure() { + struct Error: Swift.Error, Equatable {} + let error = Error() + + var env: MessengerEnvironment = .unimplemented + env.ctx.cMix = .unimplemented + env.ctx.cMix!.networkFollowerStatus.run = { .running } + env.ctx.cMix!.getReceptionRegistrationValidationSignature.run = { + "registration-signature".data(using: .utf8)! + } + env.ctx.e2e = .unimplemented + env.ctx.e2e!.getId.run = { 1234 } + env.udCert = { nil } + env.udContact = { nil } + env.ctx.e2e!.getUdCertFromNdf.run = { "ndf-ud-cert".data(using: .utf8)! } + env.ctx.e2e!.getUdContactFromNdf.run = { throw error } + let register: MessengerRegister = .live(env) + + XCTAssertThrowsError(try register(username: "new-user-name")) { err in + XCTAssertEqual(err as? Error, error) + } + } + + func testNewOrLoadUdFailure() { + struct Error: Swift.Error, Equatable {} + let error = Error() + + var env: MessengerEnvironment = .unimplemented + env.ctx.cMix = .unimplemented + env.ctx.cMix!.networkFollowerStatus.run = { .running } + env.ctx.cMix!.getReceptionRegistrationValidationSignature.run = { + "registration-signature".data(using: .utf8)! + } + env.ctx.e2e = .unimplemented + env.ctx.e2e!.getId.run = { 1234 } + env.udCert = { "ud-cert".data(using: .utf8)! } + env.udContact = { "ud-contact".data(using: .utf8)! } + env.udAddress = { "ud-address" } + env.newOrLoadUd.run = { _, _ in throw error } + let register: MessengerRegister = .live(env) + + XCTAssertThrowsError(try register(username: "new-user-name")) { err in + XCTAssertEqual(err as? Error, error) + } + } +} diff --git a/Tests/XXMessengerClientTests/XXMessengerClientTests.swift b/Tests/XXMessengerClientTests/XXMessengerClientTests.swift deleted file mode 100644 index 11caac7a..00000000 --- a/Tests/XXMessengerClientTests/XXMessengerClientTests.swift +++ /dev/null @@ -1,8 +0,0 @@ -import XCTest -@testable import XXMessengerClient - -final class XXMessengerClientTests: XCTestCase { - func testExample() { - XCTAssert(true) - } -} -- GitLab