127 lines
4.4 KiB
Swift
127 lines
4.4 KiB
Swift
import XCTest
|
|
@testable import Rosetta
|
|
|
|
@MainActor
|
|
final class SearchParityTests: XCTestCase {
|
|
func testSearchViewModelAndChatListUseSameQueryNormalization() async {
|
|
let searchDispatcher = MockSearchDispatcher()
|
|
let chatDispatcher = MockSearchDispatcher()
|
|
let searchVM = SearchViewModel(searchDispatcher: searchDispatcher)
|
|
let chatVM = ChatListViewModel(searchDispatcher: chatDispatcher)
|
|
|
|
searchVM.setSearchQuery(" @Alice ")
|
|
chatVM.setSearchQuery(" @Alice ")
|
|
|
|
try? await Task.sleep(for: .milliseconds(1200))
|
|
|
|
XCTAssertEqual(searchDispatcher.sentQueries, ["alice"])
|
|
XCTAssertEqual(chatDispatcher.sentQueries, ["alice"])
|
|
}
|
|
|
|
func testSavedAliasesAndExactPublicKeyFallback() throws {
|
|
let ownPair = try Self.makeKeyPair()
|
|
let peerPair = try Self.makeKeyPair()
|
|
|
|
let dialog = Self.makeDialog(
|
|
account: ownPair.publicKeyHex,
|
|
opponentKey: peerPair.publicKeyHex,
|
|
username: "peer_user",
|
|
title: "Peer User"
|
|
)
|
|
|
|
let saved = SearchParityPolicy.localAugmentedUsers(
|
|
query: "Saved Messages",
|
|
currentPublicKey: ownPair.publicKeyHex,
|
|
dialogs: [dialog]
|
|
)
|
|
XCTAssertEqual(saved.count, 1)
|
|
XCTAssertEqual(saved.first?.publicKey, ownPair.publicKeyHex)
|
|
XCTAssertEqual(saved.first?.title, "Saved Messages")
|
|
|
|
let exactPeer = SearchParityPolicy.localAugmentedUsers(
|
|
query: "0x" + peerPair.publicKeyHex,
|
|
currentPublicKey: ownPair.publicKeyHex,
|
|
dialogs: [dialog]
|
|
)
|
|
XCTAssertEqual(exactPeer.count, 1)
|
|
XCTAssertEqual(exactPeer.first?.publicKey, peerPair.publicKeyHex)
|
|
XCTAssertEqual(exactPeer.first?.username, "peer_user")
|
|
}
|
|
|
|
func testServerAndLocalMergeDedupesByPublicKeyWithServerPriority() {
|
|
let key = "021111111111111111111111111111111111111111111111111111111111111111"
|
|
let localOnlyKey = "022222222222222222222222222222222222222222222222222222222222222222"
|
|
|
|
let server = [
|
|
SearchUser(username: "server_u", title: "Server Name", publicKey: key, verified: 2, online: 0),
|
|
]
|
|
let local = [
|
|
SearchUser(username: "local_u", title: "Local Name", publicKey: key, verified: 0, online: 1),
|
|
SearchUser(username: "local_only", title: "Local Only", publicKey: localOnlyKey, verified: 0, online: 1),
|
|
]
|
|
|
|
let merged = SearchParityPolicy.mergeServerAndLocal(server: server, local: local)
|
|
XCTAssertEqual(merged.count, 2)
|
|
XCTAssertEqual(merged[0].publicKey, key)
|
|
XCTAssertEqual(merged[0].title, "Server Name")
|
|
XCTAssertEqual(merged[1].publicKey, localOnlyKey)
|
|
}
|
|
}
|
|
|
|
private extension SearchParityTests {
|
|
static func makeKeyPair() throws -> (privateKeyHex: String, publicKeyHex: String) {
|
|
let mnemonic = try CryptoManager.shared.generateMnemonic()
|
|
let pair = try CryptoManager.shared.deriveKeyPair(from: mnemonic)
|
|
return (pair.privateKey.hexString, pair.publicKey.hexString)
|
|
}
|
|
|
|
static func makeDialog(
|
|
account: String,
|
|
opponentKey: String,
|
|
username: String,
|
|
title: String
|
|
) -> Dialog {
|
|
Dialog(
|
|
id: UUID().uuidString,
|
|
account: account,
|
|
opponentKey: opponentKey,
|
|
opponentTitle: title,
|
|
opponentUsername: username,
|
|
lastMessage: "",
|
|
lastMessageTimestamp: 0,
|
|
unreadCount: 0,
|
|
isOnline: true,
|
|
lastSeen: 0,
|
|
verified: 0,
|
|
iHaveSent: true,
|
|
isPinned: false,
|
|
isMuted: false,
|
|
lastMessageFromMe: false,
|
|
lastMessageDelivered: .delivered,
|
|
lastMessageRead: true
|
|
)
|
|
}
|
|
}
|
|
|
|
private final class MockSearchDispatcher: SearchResultDispatching {
|
|
var connectionState: ConnectionState = .authenticated
|
|
var privateHash: String? = "mock-private-hash"
|
|
private(set) var sentQueries: [String] = []
|
|
private var handlers: [UUID: (PacketSearch) -> Void] = [:]
|
|
|
|
func sendSearchPacket(_ packet: PacketSearch) {
|
|
sentQueries.append(packet.search)
|
|
}
|
|
|
|
@discardableResult
|
|
func addSearchResultHandler(_ handler: @escaping (PacketSearch) -> Void) -> UUID {
|
|
let id = UUID()
|
|
handlers[id] = handler
|
|
return id
|
|
}
|
|
|
|
func removeSearchResultHandler(_ id: UUID) {
|
|
handlers.removeValue(forKey: id)
|
|
}
|
|
}
|