Files
bitchat/bitchatTests/Services/UnifiedPeerServiceTests.swift
T
806c420313 Add comprehensive test coverage for ChatViewModel and BLEService (#962)
* Add comprehensive test coverage for ChatViewModel and BLEService

This commit adds 14 new tests to improve the safety net for future
refactoring of ChatViewModel and BLEService:

New test files:
- ChatViewModelTorTests: Tor lifecycle notification handlers (8 tests)
- ChatViewModelDeliveryStatusTests: Delivery status state machine (6 tests)
- ChatViewModelRefactoringTests: Command routing and message handling (4 tests)
- BLEServiceCoreTests: Packet deduplication and stale broadcast filtering (2 tests)
- PublicMessagePipelineTests: Message ordering and deduplication (4 tests)
- MessageRouterTests: Transport selection and outbox behavior (4 tests)
- PrivateChatManagerTests: Chat selection and read receipts (2 tests)
- UnifiedPeerServiceTests: Fingerprint resolution and blocking (2 tests)
- RelayControllerTests: TTL, handshake, and fragment relay logic (4 tests)

Modified files:
- MockTransport: Added peer snapshot publishing on connect/disconnect
- TestHelpers: Added waitUntil polling helper for async tests
- MockIdentityManager: Extended for new test scenarios

Total: 454 tests across 64 suites (was 440)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Fix flaky test by using waitUntil instead of fixed sleep

Replace fixed 200ms sleep with waitUntil helper for more reliable
async assertion in routing tests. This prevents timing issues on CI.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

---------

Co-authored-by: jack <jackjackbits@users.noreply.github.com>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-16 16:02:13 -10:00

146 lines
4.2 KiB
Swift

//
// UnifiedPeerServiceTests.swift
// bitchatTests
//
// Tests for UnifiedPeerService fingerprint and block resolution.
//
import Testing
import Foundation
@testable import bitchat
struct UnifiedPeerServiceTests {
@Test @MainActor
func getFingerprint_prefersMeshService() async {
let transport = MockTransport()
let identity = TestIdentityManager()
let idBridge = NostrIdentityBridge(keychain: MockKeychainHelper())
let service = UnifiedPeerService(meshService: transport, idBridge: idBridge, identityManager: identity)
let peerID = PeerID(str: "00000000000000CC")
transport.peerFingerprints[peerID] = "fp-1"
let fingerprint = service.getFingerprint(for: peerID)
#expect(fingerprint == "fp-1")
}
@Test @MainActor
func isBlocked_usesSocialIdentity() async {
let transport = MockTransport()
let identity = TestIdentityManager()
let idBridge = NostrIdentityBridge(keychain: MockKeychainHelper())
let service = UnifiedPeerService(meshService: transport, idBridge: idBridge, identityManager: identity)
let peerID = PeerID(str: "00000000000000DD")
let fingerprint = "fp-blocked"
transport.peerFingerprints[peerID] = fingerprint
identity.setBlocked(fingerprint, isBlocked: true)
#expect(service.isBlocked(peerID))
}
}
private final class TestIdentityManager: SecureIdentityStateManagerProtocol {
private var socialIdentities: [String: SocialIdentity] = [:]
private var favorites: Set<String> = []
private var blockedNostr: Set<String> = []
private var verified: Set<String> = []
func forceSave() {}
func getSocialIdentity(for fingerprint: String) -> SocialIdentity? {
socialIdentities[fingerprint]
}
func upsertCryptographicIdentity(fingerprint: String, noisePublicKey: Data, signingPublicKey: Data?, claimedNickname: String?) {}
func getCryptoIdentitiesByPeerIDPrefix(_ peerID: PeerID) -> [CryptographicIdentity] {
[]
}
func updateSocialIdentity(_ identity: SocialIdentity) {
socialIdentities[identity.fingerprint] = identity
}
func getFavorites() -> Set<String> {
favorites
}
func setFavorite(_ fingerprint: String, isFavorite: Bool) {
if isFavorite {
favorites.insert(fingerprint)
} else {
favorites.remove(fingerprint)
}
}
func isFavorite(fingerprint: String) -> Bool {
favorites.contains(fingerprint)
}
func isBlocked(fingerprint: String) -> Bool {
socialIdentities[fingerprint]?.isBlocked ?? false
}
func setBlocked(_ fingerprint: String, isBlocked: Bool) {
var identity = socialIdentities[fingerprint] ?? SocialIdentity(
fingerprint: fingerprint,
localPetname: nil,
claimedNickname: "",
trustLevel: .unknown,
isFavorite: false,
isBlocked: false,
notes: nil
)
identity.isBlocked = isBlocked
socialIdentities[fingerprint] = identity
}
func isNostrBlocked(pubkeyHexLowercased: String) -> Bool {
blockedNostr.contains(pubkeyHexLowercased)
}
func setNostrBlocked(_ pubkeyHexLowercased: String, isBlocked: Bool) {
if isBlocked {
blockedNostr.insert(pubkeyHexLowercased)
} else {
blockedNostr.remove(pubkeyHexLowercased)
}
}
func getBlockedNostrPubkeys() -> Set<String> {
blockedNostr
}
func registerEphemeralSession(peerID: PeerID, handshakeState: HandshakeState) {}
func updateHandshakeState(peerID: PeerID, state: HandshakeState) {}
func clearAllIdentityData() {
socialIdentities.removeAll()
favorites.removeAll()
blockedNostr.removeAll()
verified.removeAll()
}
func removeEphemeralSession(peerID: PeerID) {}
func setVerified(fingerprint: String, verified: Bool) {
if verified {
self.verified.insert(fingerprint)
} else {
self.verified.remove(fingerprint)
}
}
func isVerified(fingerprint: String) -> Bool {
verified.contains(fingerprint)
}
func getVerifiedFingerprints() -> Set<String> {
verified
}
}