Skip to content
Snippets Groups Projects
Commit 8098596c authored by Dariusz Rybicki's avatar Dariusz Rybicki
Browse files

Add MessengerSearchUsers function

parent db80fbf6
No related branches found
No related tags found
2 merge requests!102Release 1.0.0,!64XXMessengerClient - Search Users
import Foundation
import XCTestDynamicOverlay
import XXClient
public struct MessengerSearchUsers {
public struct Query: Equatable {
public init(
username: String? = nil,
email: String? = nil,
phone: String? = nil
) {
self.username = username
self.email = email
self.phone = phone
}
public var username: String?
public var email: String?
public var phone: String?
}
public enum Error: Swift.Error, Equatable {
case notConnected
case notLoggedIn
}
public var run: (Query) throws -> [Contact]
public func callAsFunction(query: Query) throws -> [Contact] {
try run(query)
}
}
extension MessengerSearchUsers {
public static func live(_ env: MessengerEnvironment) -> MessengerSearchUsers {
MessengerSearchUsers { query in
guard let e2e = env.e2e() else {
throw Error.notConnected
}
guard let ud = env.ud() else {
throw Error.notLoggedIn
}
var result: Result<[Contact], Swift.Error>!
let semaphore = DispatchSemaphore(value: 0)
_ = try env.searchUD(
e2eId: e2e.getId(),
udContact: try ud.getContact(),
facts: query.facts,
singleRequestParamsJSON: env.getSingleUseParams(),
callback: .init { searchResult in
switch searchResult {
case .success(let contacts):
result = .success(contacts)
case .failure(let error):
result = .failure(error)
}
semaphore.signal()
}
)
semaphore.wait()
return try result.get()
}
}
}
extension MessengerSearchUsers.Query {
public var isEmpty: Bool {
[username, email, phone]
.compactMap { $0 }
.map { $0.isEmpty == false }
.contains(where: { $0 == true }) == false
}
var facts: [Fact] {
var facts: [Fact] = []
if let username = username, username.isEmpty == false {
facts.append(Fact(fact: username, type: 0))
}
if let email = email, email.isEmpty == false {
facts.append(Fact(fact: email, type: 1))
}
if let phone = phone, phone.isEmpty == false {
facts.append(Fact(fact: phone, type: 2))
}
return facts
}
}
extension MessengerSearchUsers {
public static let unimplemented = MessengerSearchUsers(
run: XCTUnimplemented("\(Self.self)")
)
}
...@@ -19,6 +19,7 @@ public struct Messenger { ...@@ -19,6 +19,7 @@ public struct Messenger {
public var waitForNetwork: MessengerWaitForNetwork public var waitForNetwork: MessengerWaitForNetwork
public var waitForNodes: MessengerWaitForNodes public var waitForNodes: MessengerWaitForNodes
public var destroy: MessengerDestroy public var destroy: MessengerDestroy
public var searchUsers: MessengerSearchUsers
} }
extension Messenger { extension Messenger {
...@@ -41,7 +42,8 @@ extension Messenger { ...@@ -41,7 +42,8 @@ extension Messenger {
logIn: .live(env), logIn: .live(env),
waitForNetwork: .live(env), waitForNetwork: .live(env),
waitForNodes: .live(env), waitForNodes: .live(env),
destroy: .live(env) destroy: .live(env),
searchUsers: .live(env)
) )
} }
} }
...@@ -65,6 +67,7 @@ extension Messenger { ...@@ -65,6 +67,7 @@ extension Messenger {
logIn: .unimplemented, logIn: .unimplemented,
waitForNetwork: .unimplemented, waitForNetwork: .unimplemented,
waitForNodes: .unimplemented, waitForNodes: .unimplemented,
destroy: .unimplemented destroy: .unimplemented,
searchUsers: .unimplemented
) )
} }
...@@ -11,6 +11,7 @@ public struct MessengerEnvironment { ...@@ -11,6 +11,7 @@ public struct MessengerEnvironment {
public var generateSecret: GenerateSecret public var generateSecret: GenerateSecret
public var getCMixParams: GetCMixParams public var getCMixParams: GetCMixParams
public var getE2EParams: GetE2EParams public var getE2EParams: GetE2EParams
public var getSingleUseParams: GetSingleUseParams
public var isRegisteredWithUD: IsRegisteredWithUD public var isRegisteredWithUD: IsRegisteredWithUD
public var loadCMix: LoadCMix public var loadCMix: LoadCMix
public var login: Login public var login: Login
...@@ -18,6 +19,7 @@ public struct MessengerEnvironment { ...@@ -18,6 +19,7 @@ public struct MessengerEnvironment {
public var newCMix: NewCMix public var newCMix: NewCMix
public var newOrLoadUd: NewOrLoadUd public var newOrLoadUd: NewOrLoadUd
public var passwordStorage: PasswordStorage public var passwordStorage: PasswordStorage
public var searchUD: SearchUD
public var sleep: (TimeInterval) -> Void public var sleep: (TimeInterval) -> Void
public var storageDir: String public var storageDir: String
public var ud: Stored<UserDiscovery?> public var ud: Stored<UserDiscovery?>
...@@ -43,6 +45,7 @@ extension MessengerEnvironment { ...@@ -43,6 +45,7 @@ extension MessengerEnvironment {
generateSecret: .live, generateSecret: .live,
getCMixParams: .liveDefault, getCMixParams: .liveDefault,
getE2EParams: .liveDefault, getE2EParams: .liveDefault,
getSingleUseParams: .liveDefault,
isRegisteredWithUD: .live, isRegisteredWithUD: .live,
loadCMix: .live, loadCMix: .live,
login: .live, login: .live,
...@@ -50,6 +53,7 @@ extension MessengerEnvironment { ...@@ -50,6 +53,7 @@ extension MessengerEnvironment {
newCMix: .live, newCMix: .live,
newOrLoadUd: .live, newOrLoadUd: .live,
passwordStorage: .keychain, passwordStorage: .keychain,
searchUD: .live,
sleep: { Thread.sleep(forTimeInterval: $0) }, sleep: { Thread.sleep(forTimeInterval: $0) },
storageDir: MessengerEnvironment.defaultStorageDir, storageDir: MessengerEnvironment.defaultStorageDir,
ud: .inMemory(), ud: .inMemory(),
...@@ -70,6 +74,7 @@ extension MessengerEnvironment { ...@@ -70,6 +74,7 @@ extension MessengerEnvironment {
generateSecret: .unimplemented, generateSecret: .unimplemented,
getCMixParams: .unimplemented, getCMixParams: .unimplemented,
getE2EParams: .unimplemented, getE2EParams: .unimplemented,
getSingleUseParams: .unimplemented,
isRegisteredWithUD: .unimplemented, isRegisteredWithUD: .unimplemented,
loadCMix: .unimplemented, loadCMix: .unimplemented,
login: .unimplemented, login: .unimplemented,
...@@ -77,6 +82,7 @@ extension MessengerEnvironment { ...@@ -77,6 +82,7 @@ extension MessengerEnvironment {
newCMix: .unimplemented, newCMix: .unimplemented,
newOrLoadUd: .unimplemented, newOrLoadUd: .unimplemented,
passwordStorage: .unimplemented, passwordStorage: .unimplemented,
searchUD: .unimplemented,
sleep: XCTUnimplemented("\(Self.self).sleep"), sleep: XCTUnimplemented("\(Self.self).sleep"),
storageDir: "unimplemented", storageDir: "unimplemented",
ud: .unimplemented(), ud: .unimplemented(),
......
import CustomDump
import XCTest
import XXClient
@testable import XXMessengerClient
final class MessengerSearchUsersTests: XCTestCase {
func testSearch() throws {
struct SearchUdParams: Equatable {
var e2eId: Int
var udContact: Contact
var facts: [Fact]
var singleRequestParamsJSON: Data
}
var didSearchUdWithParams: [SearchUdParams] = []
var env: MessengerEnvironment = .unimplemented
env.e2e.get = {
var e2e: E2E = .unimplemented
e2e.getId.run = { 123 }
return e2e
}
env.ud.get = {
var ud: UserDiscovery = .unimplemented
ud.getContact.run = { .unimplemented("ud-contact".data(using: .utf8)!) }
return ud
}
env.getSingleUseParams.run = { "single-use-params".data(using: .utf8)! }
env.searchUD.run = { e2eId, udContact, facts, singleRequestParamsJSON, callback in
didSearchUdWithParams.append(.init(
e2eId: e2eId,
udContact: udContact,
facts: facts,
singleRequestParamsJSON: singleRequestParamsJSON
))
callback.handle(.success([
.unimplemented("contact-1".data(using: .utf8)!),
.unimplemented("contact-2".data(using: .utf8)!),
.unimplemented("contact-3".data(using: .utf8)!),
]))
return SingleUseSendReport(rounds: [], ephId: 0, receptionId: Data())
}
let search: MessengerSearchUsers = .live(env)
let query = MessengerSearchUsers.Query(
username: "Username",
email: "Email",
phone: "Phone"
)
let contacts = try search(query: query)
XCTAssertNoDifference(didSearchUdWithParams, [.init(
e2eId: 123,
udContact: .unimplemented("ud-contact".data(using: .utf8)!),
facts: query.facts,
singleRequestParamsJSON: "single-use-params".data(using: .utf8)!
)])
XCTAssertNoDifference(contacts, [
.unimplemented("contact-1".data(using: .utf8)!),
.unimplemented("contact-2".data(using: .utf8)!),
.unimplemented("contact-3".data(using: .utf8)!),
])
}
func testSearchNotConnected() {
var env: MessengerEnvironment = .unimplemented
env.e2e.get = { nil }
let search: MessengerSearchUsers = .live(env)
XCTAssertThrowsError(try search(query: .init())) { error in
XCTAssertNoDifference(error as? MessengerSearchUsers.Error, .notConnected)
}
}
func testSearchNotLoggedIn() {
var env: MessengerEnvironment = .unimplemented
env.e2e.get = { .unimplemented }
env.ud.get = { nil }
let search: MessengerSearchUsers = .live(env)
XCTAssertThrowsError(try search(query: .init())) { error in
XCTAssertNoDifference(error as? MessengerSearchUsers.Error, .notLoggedIn)
}
}
func testSearchFailure() {
struct Failure: Error, Equatable {}
let error = Failure()
var env: MessengerEnvironment = .unimplemented
env.e2e.get = {
var e2e: E2E = .unimplemented
e2e.getId.run = { 0 }
return e2e
}
env.ud.get = {
var ud: UserDiscovery = .unimplemented
ud.getContact.run = { .unimplemented(Data()) }
return ud
}
env.getSingleUseParams.run = { Data() }
env.searchUD.run = { _, _, _, _, _ in throw error }
let search: MessengerSearchUsers = .live(env)
XCTAssertThrowsError(try search(query: .init())) { err in
XCTAssertNoDifference(err as? Failure, error)
}
}
func testSearchCallbackFailure() {
struct Failure: Error, Equatable {}
let error = Failure()
var env: MessengerEnvironment = .unimplemented
env.e2e.get = {
var e2e: E2E = .unimplemented
e2e.getId.run = { 0 }
return e2e
}
env.ud.get = {
var ud: UserDiscovery = .unimplemented
ud.getContact.run = { .unimplemented(Data()) }
return ud
}
env.getSingleUseParams.run = { Data() }
env.searchUD.run = { _, _, _, _, callback in
callback.handle(.failure(error as NSError))
return SingleUseSendReport(rounds: [], ephId: 0, receptionId: Data())
}
let search: MessengerSearchUsers = .live(env)
XCTAssertThrowsError(try search(query: .init())) { err in
XCTAssertNoDifference(err as? Failure, error)
}
}
func testQueryIsEmpty() {
let emptyQueries: [MessengerSearchUsers.Query] = [
.init(username: nil, email: nil, phone: nil),
.init(username: "", email: nil, phone: nil),
.init(username: nil, email: "", phone: nil),
.init(username: nil, email: nil, phone: ""),
.init(username: "", email: "", phone: ""),
]
emptyQueries.forEach { query in
XCTAssertTrue(query.isEmpty, "\(query) should be empty")
}
let nonEmptyQueries: [MessengerSearchUsers.Query] = [
.init(username: "test", email: nil, phone: nil),
.init(username: nil, email: "test", phone: nil),
.init(username: nil, email: nil, phone: "test"),
.init(username: "a", email: "b", phone: "c"),
]
nonEmptyQueries.forEach { query in
XCTAssertFalse(query.isEmpty, "\(query) should not be empty")
}
}
func testQueryFacts() {
XCTAssertNoDifference(
MessengerSearchUsers.Query(username: nil, email: nil, phone: nil).facts,
[]
)
XCTAssertNoDifference(
MessengerSearchUsers.Query(username: "", email: "", phone: "").facts,
[]
)
XCTAssertNoDifference(
MessengerSearchUsers.Query(
username: "username",
email: "email",
phone: "phone"
).facts,
[
Fact(fact: "username", type: 0),
Fact(fact: "email", type: 1),
Fact(fact: "phone", type: 2),
]
)
XCTAssertNoDifference(
MessengerSearchUsers.Query(
username: "username",
email: "",
phone: nil
).facts,
[
Fact(fact: "username", type: 0),
]
)
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment